From 267b925bb46d53472d28e88edc7d837c5918612b Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Sat, 16 Jul 2005 01:57:20 +0000 Subject: [PATCH] Clone the busybox_0_60_stable branch from the old busybox.stable CVS tree --- busybox/.cvsignore => .cvsignore | 0 busybox/.indent.pro => .indent.pro | 0 busybox/AUTHORS => AUTHORS | 30 +- busybox/Changelog => Changelog | 218 +- Changelog.full | 138 + busybox/Config.h => Config.h | 41 +- busybox/INSTALL => INSTALL | 0 busybox/LICENSE => LICENSE | 9 +- busybox/Makefile => Makefile | 144 +- busybox/README => README | 28 +- busybox/TODO => TODO | 5 - busybox/adjtimex.c => adjtimex.c | 0 busybox/applets.c => applets.c | 0 busybox/applets.h => applets.h | 9 + busybox/ar.c => ar.c | 0 busybox/ash.c => ash.c | 17184 ++++++++-------- busybox/coreutils/basename.c => basename.c | 4 +- busybox/applets/busybox.c => busybox.c | 29 +- busybox/busybox.h => busybox.h | 8 +- busybox/applets/busybox.mkll => busybox.mkll | 0 busybox/applets/busybox.sh => busybox.sh | 0 busybox/examples/busybox.spec => busybox.spec | 8 +- busybox/applets/applets.c | 116 - busybox/archival/ar.c | 89 - busybox/archival/gunzip.c | 183 - busybox/archival/gzip.c | 2550 --- .../archival/libunarchive/decompress_unzip.c | 1026 - busybox/archival/libunarchive/unzip.c | 1026 - busybox/busybox.c | 181 - busybox/busybox.mkll | 24 - busybox/busybox.sh | 16 - busybox/busybox.spec | 44 - busybox/chgrp.c | 91 - busybox/chmod.c | 85 - busybox/chown.c | 113 - busybox/chroot.c | 75 - busybox/chvt.c | 43 - busybox/cmdedit.h | 6 - busybox/console-tools/clear.c | 34 - busybox/console-tools/reset.c | 35 - busybox/console-tools/setkeycodes.c | 72 - busybox/coreutils/cmp.c | 80 - busybox/coreutils/cp.c | 114 - busybox/coreutils/cut.c | 356 - busybox/coreutils/du.c | 257 - busybox/coreutils/env.c | 106 - busybox/coreutils/head.c | 97 - busybox/coreutils/ls.c | 937 - busybox/coreutils/uniq.c | 89 - busybox/cpio.c | 95 - busybox/date.c | 247 - busybox/dd.c | 154 - busybox/deallocvt.c | 43 - busybox/df.c | 158 - busybox/dirname.c | 40 - busybox/docs/busybox.net/.cvsignore | 1 - busybox/docs/busybox.net/busybox-growth.ps | Bin 11697 -> 0 bytes busybox/docs/busybox.net/images/busybox.jpeg | Bin 9023 -> 0 bytes busybox/docs/busybox.net/images/busybox2.jpg | Bin 8204 -> 0 bytes busybox/docs/busybox.net/images/fm.mini.png | Bin 7708 -> 0 bytes .../docs/busybox.net/images/gfx_by_gimp.png | Bin 3955 -> 0 bytes busybox/docs/busybox.net/images/ltbutton2.png | Bin 6799 -> 0 bytes busybox/docs/busybox.net/images/sdsmall.png | Bin 1593 -> 0 bytes .../docs/busybox.net/images/written.in.vi.png | Bin 4394 -> 0 bytes busybox/docs/busybox.net/index.html | 394 - busybox/docs/busybox.net/oldnews.html | 465 - busybox/docs/busybox.net/screenshot.html | 54 - busybox/dos2unix.c | 195 - busybox/dpkg.c | 1445 -- busybox/dpkg_deb.c | 130 - busybox/dumpkmap.c | 95 - busybox/echo.c | 152 - busybox/editors/sed.c | 850 - busybox/examples/bootfloppy/bootfloppy.txt | 185 - busybox/examples/bootfloppy/display.txt | 4 - busybox/examples/bootfloppy/etc/fstab | 2 - busybox/examples/bootfloppy/etc/init.d/rcS | 3 - busybox/examples/bootfloppy/etc/inittab | 5 - busybox/examples/bootfloppy/etc/profile | 8 - busybox/examples/bootfloppy/mkdevs.sh | 62 - busybox/examples/bootfloppy/mkrootfs.sh | 106 - busybox/examples/bootfloppy/mksyslinux.sh | 48 - busybox/examples/bootfloppy/quickstart.txt | 15 - busybox/examples/bootfloppy/syslinux.cfg | 7 - busybox/examples/inittab | 86 - busybox/expr.c | 535 - busybox/findutils/find.c | 200 - busybox/grep.c | 359 - busybox/hostid.c | 32 - busybox/hostname.c | 128 - busybox/hush.c | 2692 --- busybox/id.c | 97 - busybox/ifconfig.c | 492 - busybox/include/applets.h | 478 - busybox/include/busybox.h | 106 - busybox/include/libbb.h | 326 - busybox/include/usage.h | 1826 -- busybox/init/halt.c | 41 - busybox/init/init.c | 1031 - busybox/init/reboot.c | 49 - busybox/install.sh | 52 - busybox/length.c | 13 - busybox/libbb/arith.c | 263 - busybox/libbb/concat_path_file.c | 26 - busybox/libbb/fgets_str.c | 64 - busybox/libbb/get_last_path_component.c | 71 - busybox/libbb/gz_open.c | 35 - busybox/libbb/mk_loop_h.sh | 37 - busybox/ln.c | 131 - busybox/loadacm.c | 357 - busybox/loadfont.c | 209 - busybox/loadkmap.c | 89 - busybox/logger.c | 200 - busybox/logname.c | 41 - busybox/lsmod.c | 166 - busybox/makedevs.c | 95 - busybox/md5sum.c | 1074 - busybox/miscutils/adjtimex.c | 176 - busybox/miscutils/dc.c | 182 - busybox/miscutils/dutmp.c | 64 - busybox/mkdir.c | 64 - busybox/mkfifo.c | 60 - busybox/mknod.c | 92 - busybox/mkswap.c | 422 - busybox/mktemp.c | 40 - busybox/modprobe.c | 121 - busybox/modutils/insmod.c | 3481 ---- busybox/modutils/modprobe.c | 121 - busybox/modutils/rmmod.c | 62 - busybox/more.c | 217 - busybox/mount.c | 498 - busybox/mt.c | 121 - busybox/mv.c | 168 - busybox/nc.c | 137 - busybox/networking/nslookup.c | 183 - busybox/networking/route.c | 450 - busybox/networking/telnet.c | 711 - busybox/networking/tftp.c | 383 - busybox/networking/traceroute.c | 652 - busybox/pidof.c | 79 - busybox/ping.c | 555 - busybox/poweroff.c | 41 - busybox/printf.c | 455 - busybox/procps/free.c | 69 - busybox/procps/kill.c | 142 - busybox/procps/uptime.c | 77 - busybox/ps.c | 266 - busybox/readlink.c | 48 - busybox/reboot.c | 49 - busybox/renice.c | 54 - busybox/rm.c | 77 - busybox/rmdir.c | 97 - busybox/rpm2cpio.c | 91 - busybox/scripts/depmod.pl | 227 - busybox/scripts/mk2knr.pl | 84 - busybox/scripts/undeb | 53 - busybox/scripts/unrpm | 48 - busybox/sed.c | 850 - busybox/shell/ash.c | 12888 ------------ busybox/shell/cmdedit.c | 1521 -- busybox/shell/cmdedit.h | 6 - busybox/shell/lash.c | 1638 -- busybox/shell/msh.c | 4868 ----- busybox/sleep.c | 38 - busybox/sort.c | 106 - busybox/stty.c | 1376 -- busybox/sync.c | 35 - busybox/sysklogd/klogd.c | 153 - busybox/sysklogd/logread.c | 144 - busybox/syslogd.c | 641 - busybox/tail.c | 251 - busybox/tar.c | 1150 -- busybox/tee.c | 68 - busybox/test.c | 579 - busybox/touch.c | 75 - busybox/tr.c | 248 - busybox/tty.c | 44 - busybox/uname.c | 156 - busybox/update.c | 112 - busybox/usage.c | 10 - busybox/usage.h | 1826 -- busybox/usleep.c | 38 - busybox/util-linux/dmesg.c | 95 - busybox/util-linux/fbset.c | 424 - busybox/util-linux/fdflush.c | 47 - busybox/util-linux/freeramdisk.c | 65 - busybox/util-linux/fsck_minix.c | 1478 -- busybox/util-linux/getopt.c | 402 - busybox/util-linux/mkfs_minix.c | 847 - busybox/util-linux/nfsmount.c | 977 - busybox/util-linux/nfsmount.h | 242 - busybox/util-linux/pivot_root.c | 35 - busybox/util-linux/rdate.c | 116 - busybox/util-linux/swaponoff.c | 115 - busybox/util-linux/umount.c | 298 - busybox/uudecode.c | 353 - busybox/uuencode.c | 180 - busybox/vi.c | 3947 ---- busybox/wc.c | 156 - busybox/wget.c | 834 - busybox/which.c | 80 - busybox/whoami.c | 44 - busybox/xargs.c | 105 - busybox/yes.c | 53 - busybox/coreutils/cat.c => cat.c | 4 +- busybox/coreutils/chgrp.c => chgrp.c | 4 +- busybox/coreutils/chmod.c => chmod.c | 18 +- busybox/coreutils/chown.c => chown.c | 4 +- busybox/coreutils/chroot.c => chroot.c | 4 +- busybox/console-tools/chvt.c => chvt.c | 2 +- busybox/clear.c => clear.c | 4 +- busybox/cmdedit.c => cmdedit.c | 630 +- cmdedit.h | 11 + busybox/cmp.c => cmp.c | 4 +- busybox/cp.c => cp.c | 5 +- busybox/archival/cpio.c => cpio.c | 0 busybox/cut.c => cut.c | 4 +- busybox/coreutils/date.c => date.c | 4 +- busybox/dc.c => dc.c | 0 busybox/coreutils/dd.c => dd.c | 27 +- .../console-tools/deallocvt.c => deallocvt.c | 2 +- {busybox/debian => debian}/Config.h-deb | 74 +- {busybox/debian => debian}/Config.h-static | 62 +- {busybox/debian => debian}/Config.h-udeb | 64 +- {busybox/debian => debian}/README.debian | 2 +- {busybox/debian => debian}/changelog | 138 +- {busybox/debian => debian}/control | 5 +- {busybox/debian => debian}/copyright | 0 {busybox/debian => debian}/rules | 13 +- busybox/coreutils/df.c => df.c | 4 +- busybox/coreutils/dirname.c => dirname.c | 4 +- busybox/dmesg.c => dmesg.c | 0 {busybox/docs => docs}/.cvsignore | 0 {busybox/docs => docs}/autodocifier.pl | 8 +- {busybox/docs => docs}/busybox.sgml | 6 +- {busybox/docs => docs}/busybox_footer.pod | 10 +- {busybox/docs => docs}/busybox_header.pod | 1 + {busybox/docs => docs}/contributing.txt | 4 +- {busybox/docs => docs}/new-applet-HOWTO.txt | 2 +- {busybox/docs => docs}/style-guide.txt | 0 busybox/coreutils/dos2unix.c => dos2unix.c | 4 +- busybox/archival/dpkg.c => dpkg.c | 4 +- busybox/archival/dpkg_deb.c => dpkg_deb.c | 0 busybox/du.c => du.c | 91 +- .../console-tools/dumpkmap.c => dumpkmap.c | 0 busybox/dutmp.c => dutmp.c | 6 +- busybox/coreutils/echo.c => echo.c | 0 busybox/env.c => env.c | 2 +- busybox/coreutils/expr.c => expr.c | 0 busybox/fbset.c => fbset.c | 3 + busybox/fdflush.c => fdflush.c | 0 busybox/find.c => find.c | 34 +- busybox/free.c => free.c | 40 +- busybox/freeramdisk.c => freeramdisk.c | 0 busybox/fsck_minix.c => fsck_minix.c | 0 busybox/getopt.c => getopt.c | 0 busybox/findutils/grep.c => grep.c | 35 +- busybox/gunzip.c => gunzip.c | 148 +- busybox/gzip.c => gzip.c | 134 +- busybox/halt.c => halt.c | 4 +- busybox/head.c => head.c | 13 +- busybox/coreutils/hostid.c => hostid.c | 0 busybox/networking/hostname.c => hostname.c | 114 +- busybox/shell/hush.c => hush.c | 375 +- busybox/coreutils/id.c => id.c | 0 busybox/networking/ifconfig.c => ifconfig.c | 7 +- busybox/init.c => init.c | 781 +- busybox/insmod.c => insmod.c | 1052 +- busybox/applets/install.sh => install.sh | 0 .../Will_devps_GoIntoTheKernel | 2 +- .../devps.patch.9_25_2000 | 0 busybox/kill.c => kill.c | 108 +- busybox/klogd.c => klogd.c | 19 +- busybox/lash.c => lash.c | 40 +- busybox/coreutils/length.c => length.c | 0 {busybox/libbb => libbb}/.cvsignore | 0 {busybox/libbb => libbb}/Makefile | 2 +- {busybox/libbb => libbb}/README | 5 +- libbb/arith.c | 376 + {busybox/libbb => libbb}/ask_confirmation.c | 16 +- {busybox/libbb => libbb}/chomp.c | 16 +- busybox/cat.c => libbb/concat_path_file.c | 54 +- {busybox/libbb => libbb}/copy_file.c | 100 +- {busybox/libbb => libbb}/copy_file_chunk.c | 16 +- {busybox/libbb => libbb}/copyfd.c | 0 {busybox/libbb => libbb}/create_icmp_socket.c | 0 {busybox/libbb => libbb}/device_open.c | 8 +- {busybox/libbb => libbb}/dirname.c | 2 +- {busybox/libbb => libbb}/error_msg.c | 8 +- {busybox/libbb => libbb}/error_msg_and_die.c | 8 +- libbb/fgets_str.c | 67 + {busybox/libbb => libbb}/find_mount_point.c | 8 +- {busybox/libbb => libbb}/find_pid_by_name.c | 44 +- {busybox/libbb => libbb}/find_root_device.c | 13 +- {busybox/libbb => libbb}/full_read.c | 21 +- {busybox/libbb => libbb}/full_write.c | 20 +- {busybox/libbb => libbb}/get_console.c | 21 +- .../get_last_path_component.c | 45 +- {busybox/libbb => libbb}/get_line_from_file.c | 56 +- libbb/gz_open.c | 62 + {busybox/libbb => libbb}/herror_msg.c | 8 +- {busybox/libbb => libbb}/herror_msg_and_die.c | 8 +- {busybox/libbb => libbb}/human_readable.c | 0 {busybox/libbb => libbb}/inode_hash.c | 23 +- {busybox/libbb => libbb}/interface.c | 14 +- {busybox/libbb => libbb}/isdirectory.c | 9 +- {busybox/libbb => libbb}/kernel_version.c | 8 +- {busybox/libbb => libbb}/last_char_is.c | 0 {busybox/libbb => libbb}/libbb.h | 40 +- {busybox/libbb => libbb}/libc5.c | 7 +- {busybox/libbb => libbb}/loop.c | 11 +- {busybox/libbb => libbb}/make_directory.c | 0 {busybox/libbb => libbb}/messages.c | 4 +- {busybox/libbb => libbb}/mode_string.c | 16 +- {busybox/libbb => libbb}/module_syscalls.c | 45 +- {busybox/libbb => libbb}/mtab.c | 20 + {busybox/libbb => libbb}/mtab_file.c | 8 +- {busybox/libbb => libbb}/my_getgrgid.c | 8 +- {busybox/libbb => libbb}/my_getgrnam.c | 8 +- {busybox/libbb => libbb}/my_getpwnam.c | 8 +- {busybox/libbb => libbb}/my_getpwnamegid.c | 8 +- {busybox/libbb => libbb}/my_getpwuid.c | 8 +- {busybox/libbb => libbb}/parse_mode.c | 16 +- {busybox/libbb => libbb}/parse_number.c | 16 +- {busybox/libbb => libbb}/perror_msg.c | 8 +- {busybox/libbb => libbb}/perror_msg_and_die.c | 8 +- {busybox/libbb => libbb}/print_file.c | 0 .../libbb => libbb}/process_escape_sequence.c | 0 {busybox/libbb => libbb}/read_package_field.c | 23 + {busybox/libbb => libbb}/real_loop.h | 0 {busybox/libbb => libbb}/recursive_action.c | 8 +- {busybox/libbb => libbb}/remove_file.c | 3 - {busybox/libbb => libbb}/safe_read.c | 8 +- {busybox/libbb => libbb}/safe_strncpy.c | 8 +- busybox/coreutils/pwd.c => libbb/safe_write.c | 42 +- {busybox/libbb => libbb}/simplify_path.c | 2 - {busybox/libbb => libbb}/syscalls.c | 78 +- .../libbb => libbb}/syslog_msg_with_name.c | 8 +- {busybox/libbb => libbb}/time_string.c | 8 +- {busybox/libbb => libbb}/trim.c | 16 +- {busybox/libbb => libbb}/u_signal_names.c | 23 + {busybox/libbb => libbb}/unarchive.c | 2 +- {busybox/libbb => libbb}/unzip.c | 117 +- {busybox/libbb => libbb}/vdprintf.c | 10 +- {busybox/libbb => libbb}/verror_msg.c | 8 +- {busybox/libbb => libbb}/vherror_msg.c | 10 +- {busybox/libbb => libbb}/vperror_msg.c | 8 +- {busybox/libbb => libbb}/wfopen.c | 8 +- {busybox/libbb => libbb}/xfuncs.c | 36 +- {busybox/libbb => libbb}/xgetcwd.c | 0 {busybox/libbb => libbb}/xgethostbyname.c | 3 +- {busybox/libbb => libbb}/xreadlink.c | 0 {busybox/libbb => libbb}/xregcomp.c | 16 +- busybox/coreutils/ln.c => ln.c | 4 +- busybox/console-tools/loadacm.c => loadacm.c | 0 .../console-tools/loadfont.c => loadfont.c | 0 .../console-tools/loadkmap.c => loadkmap.c | 0 busybox/sysklogd/logger.c => logger.c | 4 +- busybox/coreutils/logname.c => logname.c | 0 busybox/logread.c => logread.c | 0 busybox/basename.c => losetup.c | 62 +- busybox/ls.c => ls.c | 82 +- busybox/modutils/lsmod.c => lsmod.c | 53 +- busybox/miscutils/makedevs.c => makedevs.c | 53 +- busybox/coreutils/md5sum.c => md5sum.c | 26 +- busybox/mk_loop_h.sh => mk_loop_h.sh | 4 +- busybox/coreutils/mkdir.c => mkdir.c | 0 busybox/coreutils/mkfifo.c => mkfifo.c | 0 busybox/mkfs_minix.c => mkfs_minix.c | 0 busybox/coreutils/mknod.c => mknod.c | 1 + busybox/util-linux/mkswap.c => mkswap.c | 8 +- busybox/miscutils/mktemp.c => mktemp.c | 0 modprobe.c | 366 + busybox/util-linux/more.c => more.c | 13 +- busybox/util-linux/mount.c => mount.c | 101 +- busybox/msh.c => msh.c | 3245 ++- busybox/miscutils/mt.c => mt.c | 0 busybox/coreutils/mv.c => mv.c | 0 busybox/networking/nc.c => nc.c | 38 +- busybox/nfsmount.c => nfsmount.c | 0 busybox/nfsmount.h => nfsmount.h | 0 busybox/nslookup.c => nslookup.c | 29 +- busybox/procps/pidof.c => pidof.c | 10 +- busybox/networking/ping.c => ping.c | 4 +- busybox/pivot_root.c => pivot_root.c | 0 busybox/init/poweroff.c => poweroff.c | 4 +- busybox/coreutils/printf.c => printf.c | 0 .../pristine_setup.sh => pristine_setup.sh | 5 - busybox/procps/ps.c => ps.c | 142 +- busybox/pwd.c => pwd.c | 1 - pwd_grp/.indent.pro | 33 + pwd_grp/__getgrent.c | 162 + pwd_grp/__getpwent.c | 113 + pwd_grp/config.h | 65 + pwd_grp/fgetgrent.c | 33 + pwd_grp/fgetpwent.c | 33 + pwd_grp/getgrgid.c | 42 + pwd_grp/getgrnam.c | 48 + pwd_grp/getpw.c | 45 + pwd_grp/getpwnam.c | 49 + pwd_grp/getpwuid.c | 42 + pwd_grp/grent.c | 52 + {busybox/include => pwd_grp}/grp.h | 0 pwd_grp/initgroups.c | 74 + pwd_grp/putpwent.c | 37 + {busybox/include => pwd_grp}/pwd.h | 0 pwd_grp/pwent.c | 56 + pwd_grp/setgroups.c | 43 + busybox/rdate.c => rdate.c | 0 busybox/miscutils/readlink.c => readlink.c | 4 +- reboot.c | 116 + busybox/procps/renice.c => renice.c | 0 busybox/reset.c => reset.c | 6 +- busybox/coreutils/rm.c => rm.c | 0 busybox/coreutils/rmdir.c => rmdir.c | 4 +- busybox/rmmod.c => rmmod.c | 4 +- busybox/route.c => route.c | 15 +- busybox/archival/rpm2cpio.c => rpm2cpio.c | 0 {busybox/examples => scripts}/depmod.pl | 6 +- {busybox/scripts => scripts}/inittab | 11 +- {busybox/examples => scripts}/mk2knr.pl | 0 {busybox/examples => scripts}/undeb | 0 {busybox/examples => scripts}/unrpm | 0 sed.c | 1215 ++ busybox/setkeycodes.c => setkeycodes.c | 2 +- busybox/coreutils/sleep.c => sleep.c | 1 - busybox/coreutils/sort.c => sort.c | 0 busybox/coreutils/stty.c => stty.c | 25 +- busybox/swaponoff.c => swaponoff.c | 37 +- busybox/coreutils/sync.c => sync.c | 0 busybox/sysklogd/syslogd.c => syslogd.c | 205 +- busybox/coreutils/tail.c => tail.c | 8 +- busybox/archival/tar.c => tar.c | 8 +- busybox/coreutils/tee.c => tee.c | 3 +- busybox/telnet.c => telnet.c | 120 +- busybox/coreutils/test.c => test.c | 0 {busybox/tests => tests}/.cvsignore | 0 {busybox/tests => tests}/Makefile | 0 {busybox/tests => tests}/cp_tests.mk | 0 {busybox/tests => tests}/ln_tests.mk | 0 {busybox/tests => tests}/multibuild.pl | 0 {busybox/tests => tests}/multifeat.pl | 0 {busybox/tests => tests}/mv_tests.mk | 0 {busybox/tests => tests}/sh.testcases | 10 +- {busybox/tests => tests}/syslog_test.c | 0 {busybox/tests => tests}/testcases | 0 {busybox/tests => tests}/tester.sh | 0 {busybox/tests => tests}/tst-syslogd.c | 0 busybox/tftp.c => tftp.c | 312 +- time.c | 502 + top.c | 739 + busybox/coreutils/touch.c => touch.c | 4 +- busybox/coreutils/tr.c => tr.c | 0 busybox/traceroute.c => traceroute.c | 19 +- busybox/true_false.c => true_false.c | 4 +- busybox/coreutils/tty.c => tty.c | 0 busybox/umount.c => umount.c | 4 +- busybox/coreutils/uname.c => uname.c | 0 busybox/uniq.c => uniq.c | 6 +- busybox/miscutils/update.c => update.c | 0 busybox/uptime.c => uptime.c | 4 +- busybox/applets/usage.c => usage.c | 0 busybox/applets/usage.h => usage.h | 153 +- busybox/coreutils/usleep.c => usleep.c | 0 busybox/coreutils/uudecode.c => uudecode.c | 2 +- busybox/coreutils/uuencode.c => uuencode.c | 0 busybox/editors/vi.c => vi.c | 41 +- busybox/miscutils/watchdog.c => watchdog.c | 0 busybox/coreutils/wc.c => wc.c | 117 +- busybox/networking/wget.c => wget.c | 41 +- busybox/findutils/which.c => which.c | 64 +- busybox/coreutils/whoami.c => whoami.c | 0 busybox/findutils/xargs.c => xargs.c | 43 +- busybox/coreutils/yes.c => yes.c | 0 474 files changed, 19943 insertions(+), 87651 deletions(-) rename busybox/.cvsignore => .cvsignore (100%) rename busybox/.indent.pro => .indent.pro (100%) rename busybox/AUTHORS => AUTHORS (83%) rename busybox/Changelog => Changelog (89%) create mode 100644 Changelog.full rename busybox/Config.h => Config.h (93%) rename busybox/INSTALL => INSTALL (100%) rename busybox/LICENSE => LICENSE (98%) rename busybox/Makefile => Makefile (76%) rename busybox/README => README (88%) rename busybox/TODO => TODO (94%) rename busybox/adjtimex.c => adjtimex.c (100%) rename busybox/applets.c => applets.c (100%) rename busybox/applets.h => applets.h (98%) rename busybox/ar.c => ar.c (100%) rename busybox/ash.c => ash.c (51%) rename busybox/coreutils/basename.c => basename.c (90%) rename busybox/applets/busybox.c => busybox.c (91%) rename busybox/busybox.h => busybox.h (94%) rename busybox/applets/busybox.mkll => busybox.mkll (100%) rename busybox/applets/busybox.sh => busybox.sh (100%) rename busybox/examples/busybox.spec => busybox.spec (86%) delete mode 100644 busybox/applets/applets.c delete mode 100644 busybox/archival/ar.c delete mode 100644 busybox/archival/gunzip.c delete mode 100644 busybox/archival/gzip.c delete mode 100644 busybox/archival/libunarchive/decompress_unzip.c delete mode 100644 busybox/archival/libunarchive/unzip.c delete mode 100644 busybox/busybox.c delete mode 100755 busybox/busybox.mkll delete mode 100755 busybox/busybox.sh delete mode 100644 busybox/busybox.spec delete mode 100644 busybox/chgrp.c delete mode 100644 busybox/chmod.c delete mode 100644 busybox/chown.c delete mode 100644 busybox/chroot.c delete mode 100644 busybox/chvt.c delete mode 100644 busybox/cmdedit.h delete mode 100644 busybox/console-tools/clear.c delete mode 100644 busybox/console-tools/reset.c delete mode 100644 busybox/console-tools/setkeycodes.c delete mode 100644 busybox/coreutils/cmp.c delete mode 100644 busybox/coreutils/cp.c delete mode 100644 busybox/coreutils/cut.c delete mode 100644 busybox/coreutils/du.c delete mode 100644 busybox/coreutils/env.c delete mode 100644 busybox/coreutils/head.c delete mode 100644 busybox/coreutils/ls.c delete mode 100644 busybox/coreutils/uniq.c delete mode 100644 busybox/cpio.c delete mode 100644 busybox/date.c delete mode 100644 busybox/dd.c delete mode 100644 busybox/deallocvt.c delete mode 100644 busybox/df.c delete mode 100644 busybox/dirname.c delete mode 100644 busybox/docs/busybox.net/.cvsignore delete mode 100644 busybox/docs/busybox.net/busybox-growth.ps delete mode 100644 busybox/docs/busybox.net/images/busybox.jpeg delete mode 100644 busybox/docs/busybox.net/images/busybox2.jpg delete mode 100644 busybox/docs/busybox.net/images/fm.mini.png delete mode 100644 busybox/docs/busybox.net/images/gfx_by_gimp.png delete mode 100644 busybox/docs/busybox.net/images/ltbutton2.png delete mode 100644 busybox/docs/busybox.net/images/sdsmall.png delete mode 100644 busybox/docs/busybox.net/images/written.in.vi.png delete mode 100644 busybox/docs/busybox.net/index.html delete mode 100644 busybox/docs/busybox.net/oldnews.html delete mode 100644 busybox/docs/busybox.net/screenshot.html delete mode 100644 busybox/dos2unix.c delete mode 100644 busybox/dpkg.c delete mode 100644 busybox/dpkg_deb.c delete mode 100644 busybox/dumpkmap.c delete mode 100644 busybox/echo.c delete mode 100644 busybox/editors/sed.c delete mode 100644 busybox/examples/bootfloppy/bootfloppy.txt delete mode 100644 busybox/examples/bootfloppy/display.txt delete mode 100644 busybox/examples/bootfloppy/etc/fstab delete mode 100755 busybox/examples/bootfloppy/etc/init.d/rcS delete mode 100644 busybox/examples/bootfloppy/etc/inittab delete mode 100644 busybox/examples/bootfloppy/etc/profile delete mode 100755 busybox/examples/bootfloppy/mkdevs.sh delete mode 100755 busybox/examples/bootfloppy/mkrootfs.sh delete mode 100755 busybox/examples/bootfloppy/mksyslinux.sh delete mode 100644 busybox/examples/bootfloppy/quickstart.txt delete mode 100644 busybox/examples/bootfloppy/syslinux.cfg delete mode 100644 busybox/examples/inittab delete mode 100644 busybox/expr.c delete mode 100644 busybox/findutils/find.c delete mode 100644 busybox/grep.c delete mode 100644 busybox/hostid.c delete mode 100644 busybox/hostname.c delete mode 100644 busybox/hush.c delete mode 100644 busybox/id.c delete mode 100644 busybox/ifconfig.c delete mode 100644 busybox/include/applets.h delete mode 100644 busybox/include/busybox.h delete mode 100644 busybox/include/libbb.h delete mode 100644 busybox/include/usage.h delete mode 100644 busybox/init/halt.c delete mode 100644 busybox/init/init.c delete mode 100644 busybox/init/reboot.c delete mode 100755 busybox/install.sh delete mode 100644 busybox/length.c delete mode 100644 busybox/libbb/arith.c delete mode 100644 busybox/libbb/concat_path_file.c delete mode 100644 busybox/libbb/fgets_str.c delete mode 100644 busybox/libbb/get_last_path_component.c delete mode 100644 busybox/libbb/gz_open.c delete mode 100755 busybox/libbb/mk_loop_h.sh delete mode 100644 busybox/ln.c delete mode 100644 busybox/loadacm.c delete mode 100644 busybox/loadfont.c delete mode 100644 busybox/loadkmap.c delete mode 100644 busybox/logger.c delete mode 100644 busybox/logname.c delete mode 100644 busybox/lsmod.c delete mode 100644 busybox/makedevs.c delete mode 100644 busybox/md5sum.c delete mode 100644 busybox/miscutils/adjtimex.c delete mode 100644 busybox/miscutils/dc.c delete mode 100644 busybox/miscutils/dutmp.c delete mode 100644 busybox/mkdir.c delete mode 100644 busybox/mkfifo.c delete mode 100644 busybox/mknod.c delete mode 100644 busybox/mkswap.c delete mode 100644 busybox/mktemp.c delete mode 100644 busybox/modprobe.c delete mode 100644 busybox/modutils/insmod.c delete mode 100644 busybox/modutils/modprobe.c delete mode 100644 busybox/modutils/rmmod.c delete mode 100644 busybox/more.c delete mode 100644 busybox/mount.c delete mode 100644 busybox/mt.c delete mode 100644 busybox/mv.c delete mode 100644 busybox/nc.c delete mode 100644 busybox/networking/nslookup.c delete mode 100644 busybox/networking/route.c delete mode 100644 busybox/networking/telnet.c delete mode 100644 busybox/networking/tftp.c delete mode 100644 busybox/networking/traceroute.c delete mode 100644 busybox/pidof.c delete mode 100644 busybox/ping.c delete mode 100644 busybox/poweroff.c delete mode 100644 busybox/printf.c delete mode 100644 busybox/procps/free.c delete mode 100644 busybox/procps/kill.c delete mode 100644 busybox/procps/uptime.c delete mode 100644 busybox/ps.c delete mode 100644 busybox/readlink.c delete mode 100644 busybox/reboot.c delete mode 100644 busybox/renice.c delete mode 100644 busybox/rm.c delete mode 100644 busybox/rmdir.c delete mode 100644 busybox/rpm2cpio.c delete mode 100755 busybox/scripts/depmod.pl delete mode 100755 busybox/scripts/mk2knr.pl delete mode 100644 busybox/scripts/undeb delete mode 100644 busybox/scripts/unrpm delete mode 100644 busybox/sed.c delete mode 100644 busybox/shell/ash.c delete mode 100644 busybox/shell/cmdedit.c delete mode 100644 busybox/shell/cmdedit.h delete mode 100644 busybox/shell/lash.c delete mode 100644 busybox/shell/msh.c delete mode 100644 busybox/sleep.c delete mode 100644 busybox/sort.c delete mode 100644 busybox/stty.c delete mode 100644 busybox/sync.c delete mode 100644 busybox/sysklogd/klogd.c delete mode 100644 busybox/sysklogd/logread.c delete mode 100644 busybox/syslogd.c delete mode 100644 busybox/tail.c delete mode 100644 busybox/tar.c delete mode 100644 busybox/tee.c delete mode 100644 busybox/test.c delete mode 100644 busybox/touch.c delete mode 100644 busybox/tr.c delete mode 100644 busybox/tty.c delete mode 100644 busybox/uname.c delete mode 100644 busybox/update.c delete mode 100644 busybox/usage.c delete mode 100644 busybox/usage.h delete mode 100644 busybox/usleep.c delete mode 100644 busybox/util-linux/dmesg.c delete mode 100644 busybox/util-linux/fbset.c delete mode 100644 busybox/util-linux/fdflush.c delete mode 100644 busybox/util-linux/freeramdisk.c delete mode 100644 busybox/util-linux/fsck_minix.c delete mode 100644 busybox/util-linux/getopt.c delete mode 100644 busybox/util-linux/mkfs_minix.c delete mode 100644 busybox/util-linux/nfsmount.c delete mode 100644 busybox/util-linux/nfsmount.h delete mode 100644 busybox/util-linux/pivot_root.c delete mode 100644 busybox/util-linux/rdate.c delete mode 100644 busybox/util-linux/swaponoff.c delete mode 100644 busybox/util-linux/umount.c delete mode 100644 busybox/uudecode.c delete mode 100644 busybox/uuencode.c delete mode 100644 busybox/vi.c delete mode 100644 busybox/wc.c delete mode 100644 busybox/wget.c delete mode 100644 busybox/which.c delete mode 100644 busybox/whoami.c delete mode 100644 busybox/xargs.c delete mode 100644 busybox/yes.c rename busybox/coreutils/cat.c => cat.c (90%) rename busybox/coreutils/chgrp.c => chgrp.c (94%) rename busybox/coreutils/chmod.c => chmod.c (84%) rename busybox/coreutils/chown.c => chown.c (95%) rename busybox/coreutils/chroot.c => chroot.c (92%) rename busybox/console-tools/chvt.c => chvt.c (95%) rename busybox/clear.c => clear.c (87%) rename busybox/cmdedit.c => cmdedit.c (70%) create mode 100644 cmdedit.h rename busybox/cmp.c => cmp.c (94%) rename busybox/cp.c => cp.c (95%) rename busybox/archival/cpio.c => cpio.c (100%) rename busybox/cut.c => cut.c (98%) rename busybox/coreutils/date.c => date.c (98%) rename busybox/dc.c => dc.c (100%) rename busybox/coreutils/dd.c => dd.c (85%) rename busybox/console-tools/deallocvt.c => deallocvt.c (96%) rename {busybox/debian => debian}/Config.h-deb (86%) rename {busybox/debian => debian}/Config.h-static (89%) rename {busybox/debian => debian}/Config.h-udeb (90%) rename {busybox/debian => debian}/README.debian (84%) rename {busybox/debian => debian}/changelog (54%) rename {busybox/debian => debian}/control (95%) rename {busybox/debian => debian}/copyright (100%) rename {busybox/debian => debian}/rules (92%) rename busybox/coreutils/df.c => df.c (96%) rename busybox/coreutils/dirname.c => dirname.c (89%) rename busybox/dmesg.c => dmesg.c (100%) rename {busybox/docs => docs}/.cvsignore (100%) rename {busybox/docs => docs}/autodocifier.pl (95%) rename {busybox/docs => docs}/busybox.sgml (99%) rename {busybox/docs => docs}/busybox_footer.pod (92%) rename {busybox/docs => docs}/busybox_header.pod (99%) rename {busybox/docs => docs}/contributing.txt (99%) rename {busybox/docs => docs}/new-applet-HOWTO.txt (97%) rename {busybox/docs => docs}/style-guide.txt (100%) rename busybox/coreutils/dos2unix.c => dos2unix.c (98%) rename busybox/archival/dpkg.c => dpkg.c (99%) rename busybox/archival/dpkg_deb.c => dpkg_deb.c (100%) rename busybox/du.c => du.c (64%) rename busybox/console-tools/dumpkmap.c => dumpkmap.c (100%) rename busybox/dutmp.c => dutmp.c (94%) rename busybox/coreutils/echo.c => echo.c (100%) rename busybox/env.c => env.c (97%) rename busybox/coreutils/expr.c => expr.c (100%) rename busybox/fbset.c => fbset.c (99%) rename busybox/fdflush.c => fdflush.c (100%) rename busybox/find.c => find.c (83%) rename busybox/free.c => free.c (67%) rename busybox/freeramdisk.c => freeramdisk.c (100%) rename busybox/fsck_minix.c => fsck_minix.c (100%) rename busybox/getopt.c => getopt.c (100%) rename busybox/findutils/grep.c => grep.c (92%) rename busybox/gunzip.c => gunzip.c (66%) rename busybox/gzip.c => gzip.c (97%) rename busybox/halt.c => halt.c (91%) rename busybox/head.c => head.c (88%) rename busybox/coreutils/hostid.c => hostid.c (100%) rename busybox/networking/hostname.c => hostname.c (58%) rename busybox/shell/hush.c => hush.c (89%) rename busybox/coreutils/id.c => id.c (100%) rename busybox/networking/ifconfig.c => ifconfig.c (98%) rename busybox/init.c => init.c (55%) rename busybox/insmod.c => insmod.c (87%) rename busybox/applets/install.sh => install.sh (100%) rename {busybox/examples/kernel-patches => kernel-patches}/Will_devps_GoIntoTheKernel (99%) rename {busybox/examples/kernel-patches => kernel-patches}/devps.patch.9_25_2000 (100%) rename busybox/kill.c => kill.c (60%) rename busybox/klogd.c => klogd.c (85%) rename busybox/lash.c => lash.c (98%) rename busybox/coreutils/length.c => length.c (100%) rename {busybox/libbb => libbb}/.cvsignore (100%) rename {busybox/libbb => libbb}/Makefile (84%) rename {busybox/libbb => libbb}/README (75%) create mode 100644 libbb/arith.c rename {busybox/libbb => libbb}/ask_confirmation.c (70%) rename {busybox/libbb => libbb}/chomp.c (69%) rename busybox/cat.c => libbb/concat_path_file.c (51%) rename {busybox/libbb => libbb}/copy_file.c (76%) rename {busybox/libbb => libbb}/copy_file_chunk.c (79%) rename {busybox/libbb => libbb}/copyfd.c (100%) rename {busybox/libbb => libbb}/create_icmp_socket.c (100%) rename {busybox/libbb => libbb}/device_open.c (79%) rename {busybox/libbb => libbb}/dirname.c (96%) rename {busybox/libbb => libbb}/error_msg.c (76%) rename {busybox/libbb => libbb}/error_msg_and_die.c (76%) create mode 100644 libbb/fgets_str.c rename {busybox/libbb => libbb}/find_mount_point.c (85%) rename {busybox/libbb => libbb}/find_pid_by_name.c (75%) rename {busybox/libbb => libbb}/find_root_device.c (86%) rename {busybox/libbb => libbb}/full_read.c (73%) rename {busybox/libbb => libbb}/full_write.c (71%) rename {busybox/libbb => libbb}/get_console.c (83%) rename busybox/watchdog.c => libbb/get_last_path_component.c (52%) rename {busybox/libbb => libbb}/get_line_from_file.c (62%) create mode 100644 libbb/gz_open.c rename {busybox/libbb => libbb}/herror_msg.c (75%) rename {busybox/libbb => libbb}/herror_msg_and_die.c (76%) rename {busybox/libbb => libbb}/human_readable.c (100%) rename {busybox/libbb => libbb}/inode_hash.c (85%) rename {busybox/libbb => libbb}/interface.c (99%) rename {busybox/libbb => libbb}/isdirectory.c (89%) rename {busybox/libbb => libbb}/kernel_version.c (81%) rename {busybox/libbb => libbb}/last_char_is.c (100%) rename {busybox/libbb => libbb}/libbb.h (93%) rename {busybox/libbb => libbb}/libc5.c (97%) rename {busybox/libbb => libbb}/loop.c (88%) rename {busybox/libbb => libbb}/make_directory.c (100%) rename {busybox/libbb => libbb}/messages.c (94%) rename {busybox/libbb => libbb}/mode_string.c (81%) rename {busybox/libbb => libbb}/module_syscalls.c (69%) rename {busybox/libbb => libbb}/mtab.c (73%) rename {busybox/libbb => libbb}/mtab_file.c (78%) rename {busybox/libbb => libbb}/my_getgrgid.c (78%) rename {busybox/libbb => libbb}/my_getgrnam.c (78%) rename {busybox/libbb => libbb}/my_getpwnam.c (78%) rename {busybox/libbb => libbb}/my_getpwnamegid.c (80%) rename {busybox/libbb => libbb}/my_getpwuid.c (78%) rename {busybox/libbb => libbb}/parse_mode.c (87%) rename {busybox/libbb => libbb}/parse_number.c (78%) rename {busybox/libbb => libbb}/perror_msg.c (76%) rename {busybox/libbb => libbb}/perror_msg_and_die.c (76%) rename {busybox/libbb => libbb}/print_file.c (100%) rename {busybox/libbb => libbb}/process_escape_sequence.c (100%) rename {busybox/libbb => libbb}/read_package_field.c (72%) rename {busybox/libbb => libbb}/real_loop.h (100%) rename {busybox/libbb => libbb}/recursive_action.c (91%) rename {busybox/libbb => libbb}/remove_file.c (99%) rename {busybox/libbb => libbb}/safe_read.c (76%) rename {busybox/libbb => libbb}/safe_strncpy.c (76%) rename busybox/coreutils/pwd.c => libbb/safe_write.c (69%) rename {busybox/libbb => libbb}/simplify_path.c (99%) rename {busybox/libbb => libbb}/syscalls.c (63%) rename {busybox/libbb => libbb}/syslog_msg_with_name.c (78%) rename {busybox/libbb => libbb}/time_string.c (80%) rename {busybox/libbb => libbb}/trim.c (72%) rename {busybox/libbb => libbb}/u_signal_names.c (84%) rename {busybox/libbb => libbb}/unarchive.c (99%) rename {busybox/libbb => libbb}/unzip.c (88%) rename {busybox/libbb => libbb}/vdprintf.c (74%) rename {busybox/libbb => libbb}/verror_msg.c (76%) rename {busybox/libbb => libbb}/vherror_msg.c (75%) rename {busybox/libbb => libbb}/vperror_msg.c (77%) rename {busybox/libbb => libbb}/wfopen.c (76%) rename {busybox/libbb => libbb}/xfuncs.c (71%) rename {busybox/libbb => libbb}/xgetcwd.c (100%) rename {busybox/libbb => libbb}/xgethostbyname.c (99%) rename {busybox/libbb => libbb}/xreadlink.c (100%) rename {busybox/libbb => libbb}/xregcomp.c (73%) rename busybox/coreutils/ln.c => ln.c (95%) rename busybox/console-tools/loadacm.c => loadacm.c (100%) rename busybox/console-tools/loadfont.c => loadfont.c (100%) rename busybox/console-tools/loadkmap.c => loadkmap.c (100%) rename busybox/sysklogd/logger.c => logger.c (97%) rename busybox/coreutils/logname.c => logname.c (100%) rename busybox/logread.c => logread.c (100%) rename busybox/basename.c => losetup.c (52%) rename busybox/ls.c => ls.c (91%) rename busybox/modutils/lsmod.c => lsmod.c (77%) rename busybox/miscutils/makedevs.c => makedevs.c (57%) rename busybox/coreutils/md5sum.c => md5sum.c (98%) rename busybox/mk_loop_h.sh => mk_loop_h.sh (90%) rename busybox/coreutils/mkdir.c => mkdir.c (100%) rename busybox/coreutils/mkfifo.c => mkfifo.c (100%) rename busybox/mkfs_minix.c => mkfs_minix.c (100%) rename busybox/coreutils/mknod.c => mknod.c (96%) rename busybox/util-linux/mkswap.c => mkswap.c (98%) rename busybox/miscutils/mktemp.c => mktemp.c (100%) create mode 100644 modprobe.c rename busybox/util-linux/more.c => more.c (94%) rename busybox/util-linux/mount.c => mount.c (85%) rename busybox/msh.c => msh.c (56%) rename busybox/miscutils/mt.c => mt.c (100%) rename busybox/coreutils/mv.c => mv.c (100%) rename busybox/networking/nc.c => nc.c (81%) rename busybox/nfsmount.c => nfsmount.c (100%) rename busybox/nfsmount.h => nfsmount.h (100%) rename busybox/nslookup.c => nslookup.c (87%) rename busybox/procps/pidof.c => pidof.c (89%) rename busybox/networking/ping.c => ping.c (99%) rename busybox/pivot_root.c => pivot_root.c (100%) rename busybox/init/poweroff.c => poweroff.c (92%) rename busybox/coreutils/printf.c => printf.c (100%) rename busybox/pristine_setup.sh => pristine_setup.sh (87%) rename busybox/procps/ps.c => ps.c (65%) rename busybox/pwd.c => pwd.c (99%) create mode 100644 pwd_grp/.indent.pro create mode 100644 pwd_grp/__getgrent.c create mode 100644 pwd_grp/__getpwent.c create mode 100644 pwd_grp/config.h create mode 100644 pwd_grp/fgetgrent.c create mode 100644 pwd_grp/fgetpwent.c create mode 100644 pwd_grp/getgrgid.c create mode 100644 pwd_grp/getgrnam.c create mode 100644 pwd_grp/getpw.c create mode 100644 pwd_grp/getpwnam.c create mode 100644 pwd_grp/getpwuid.c create mode 100644 pwd_grp/grent.c rename {busybox/include => pwd_grp}/grp.h (100%) create mode 100644 pwd_grp/initgroups.c create mode 100644 pwd_grp/putpwent.c rename {busybox/include => pwd_grp}/pwd.h (100%) create mode 100644 pwd_grp/pwent.c create mode 100644 pwd_grp/setgroups.c rename busybox/rdate.c => rdate.c (100%) rename busybox/miscutils/readlink.c => readlink.c (91%) create mode 100644 reboot.c rename busybox/procps/renice.c => renice.c (100%) rename busybox/reset.c => reset.c (85%) rename busybox/coreutils/rm.c => rm.c (100%) rename busybox/coreutils/rmdir.c => rmdir.c (93%) rename busybox/rmmod.c => rmmod.c (92%) rename busybox/route.c => route.c (97%) rename busybox/archival/rpm2cpio.c => rpm2cpio.c (100%) rename {busybox/examples => scripts}/depmod.pl (96%) rename {busybox/scripts => scripts}/inittab (91%) rename {busybox/examples => scripts}/mk2knr.pl (100%) rename {busybox/examples => scripts}/undeb (100%) rename {busybox/examples => scripts}/unrpm (100%) create mode 100644 sed.c rename busybox/setkeycodes.c => setkeycodes.c (98%) rename busybox/coreutils/sleep.c => sleep.c (99%) rename busybox/coreutils/sort.c => sort.c (100%) rename busybox/coreutils/stty.c => stty.c (97%) rename busybox/swaponoff.c => swaponoff.c (77%) rename busybox/coreutils/sync.c => sync.c (100%) rename busybox/sysklogd/syslogd.c => syslogd.c (78%) rename busybox/coreutils/tail.c => tail.c (97%) rename busybox/archival/tar.c => tar.c (99%) rename busybox/coreutils/tee.c => tee.c (93%) rename busybox/telnet.c => telnet.c (86%) rename busybox/coreutils/test.c => test.c (100%) rename {busybox/tests => tests}/.cvsignore (100%) rename {busybox/tests => tests}/Makefile (100%) rename {busybox/tests => tests}/cp_tests.mk (100%) rename {busybox/tests => tests}/ln_tests.mk (100%) rename {busybox/tests => tests}/multibuild.pl (100%) rename {busybox/tests => tests}/multifeat.pl (100%) rename {busybox/tests => tests}/mv_tests.mk (100%) rename {busybox/tests => tests}/sh.testcases (93%) rename {busybox/tests => tests}/syslog_test.c (100%) rename {busybox/tests => tests}/testcases (100%) rename {busybox/tests => tests}/tester.sh (100%) rename {busybox/tests => tests}/tst-syslogd.c (100%) rename busybox/tftp.c => tftp.c (58%) create mode 100644 time.c create mode 100644 top.c rename busybox/coreutils/touch.c => touch.c (92%) rename busybox/coreutils/tr.c => tr.c (100%) rename busybox/traceroute.c => traceroute.c (98%) rename busybox/true_false.c => true_false.c (88%) rename busybox/coreutils/tty.c => tty.c (100%) rename busybox/umount.c => umount.c (98%) rename busybox/coreutils/uname.c => uname.c (100%) rename busybox/uniq.c => uniq.c (92%) rename busybox/miscutils/update.c => update.c (100%) rename busybox/uptime.c => uptime.c (94%) rename busybox/applets/usage.c => usage.c (100%) rename busybox/applets/usage.h => usage.h (91%) rename busybox/coreutils/usleep.c => usleep.c (100%) rename busybox/coreutils/uudecode.c => uudecode.c (99%) rename busybox/coreutils/uuencode.c => uuencode.c (100%) rename busybox/editors/vi.c => vi.c (99%) rename busybox/miscutils/watchdog.c => watchdog.c (100%) rename busybox/coreutils/wc.c => wc.c (56%) rename busybox/networking/wget.c => wget.c (96%) rename busybox/findutils/which.c => which.c (61%) rename busybox/coreutils/whoami.c => whoami.c (100%) rename busybox/findutils/xargs.c => xargs.c (76%) rename busybox/coreutils/yes.c => yes.c (100%) diff --git a/busybox/.cvsignore b/.cvsignore similarity index 100% rename from busybox/.cvsignore rename to .cvsignore diff --git a/busybox/.indent.pro b/.indent.pro similarity index 100% rename from busybox/.indent.pro rename to .indent.pro diff --git a/busybox/AUTHORS b/AUTHORS similarity index 83% rename from busybox/AUTHORS rename to AUTHORS index 4258e5aa5..9cee03792 100644 --- a/busybox/AUTHORS +++ b/AUTHORS @@ -8,14 +8,14 @@ incorect, _please_ let me know. ----------- -Erik Andersen , +Erik Andersen , Tons of new stuff, major rewrite of most of the core apps, tons of new apps as noted in header files. Edward Betts expr, hostid, logname, tty, wc, whoami, yes -John Beppu +John Beppu du, head, nslookup, sort, tee, uniq Brian Candler @@ -28,9 +28,17 @@ Dave Cinege more(v2), makedevs, dutmp, modularization, auto links file, various fixes, Linux Router Project maintenance +Magnus Damm + tftp client + insmod powerpc support + Larry Doolittle pristine source directory compilation, lots of patches and fixes. +Gennady Feldman + Sysklogd (single threaded syslogd, IPC Circular buffer support, + logread), various fixes. + Karl M. Hegbloom cp_mv.c, the test suite, various fixes to utility.c, &c. @@ -38,7 +46,7 @@ Daniel Jacobowitz mktemp.c Matt Kraai - documentation, bugfixes + documentation, bugfixes, test suite John Lombardo dirname, tr @@ -46,9 +54,16 @@ John Lombardo Glenn McGrath ar, dpkg, dpkg-deb +Vladimir Oleynik + cmdedit; ports: ash, stty, traceroute; locale, various fixes + and irreconcilable critic of everything not perfect. + Bruce Perens Original author of BusyBox. His code is still in many apps. +Tim Riker + bug fixes, member of fan club + Kent Robotti reset, tons and tons of bug reports and patchs. @@ -64,7 +79,7 @@ Gyepi Sam Linus Torvalds mkswap, fsck.minix, mkfs.minix -Mark Whitley +Mark Whitley grep, sed, cut, xargs, style-guide, new-applet-HOWTO, bug fixes, etc. Charles P. Wright @@ -73,9 +88,6 @@ Charles P. Wright Enrique Zanardi tarcat (since removed), loadkmap, various fixes, Debian maintenance -Vladimir Oleynik - cmdedit; ports: ash, stty, traceroute; locale, various fixes - and irreconcilable critic of everything not perfect. +Emanuele Aina + run-parts -Tim Riker - bug fixes, member of fan club diff --git a/busybox/Changelog b/Changelog similarity index 89% rename from busybox/Changelog rename to Changelog index 314bc8ab7..46590b595 100644 --- a/busybox/Changelog +++ b/Changelog @@ -1,18 +1,198 @@ -0.60.2.pre +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: - none. :) + * Added new a 'top' applet (by special request) + * Lots of small uClinux adjustments - Known Problems (to be fixed in 0.60.2) - * msh can segfault on constructs such as + 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 + * 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 ) + -- Several sed fixes + -- Added new losetup applet + * Ben Low + -- allow tftp to work with stdin as well as stdout. + * Frank P. MacLachlan 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 - due to a memory allocation problem. This only seems to cause - problems when the backtick expands to be several k in size. + unfortunately, this also means that msh is no-longer uClinux safe, + and will require some surgery to make it use vfork() again. + * Charles Steinkuehler -- 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 -- fixed ash handling of command line args + when sourcing ('.') commands. + * Ethan Benson + -- Fix mount's noauto option to not automount as "usbdevfs" + * David Kimdon -- fixed md5sum binary sums * Matt Kraai -- Fix sed s/[/]// handling (noted by Dumas Patrice). -- Fix dirname(3) improper consts, allow libc version to override. @@ -22,23 +202,19 @@ -- 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 - -- Fix mount's noauto option to not automount as "usbdevfs" + -- Fixed sed empty line substitutions (noted by Joshua Hudson). + * Steve Merrifield -- 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') - * 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) - + * Andrew Tipton -- enable vi cursor keys when in + edit mode as vim does. - -Erik Andersen, --not yet released-- + -Erik Andersen, 20 November 2001 @@ -608,7 +784,7 @@ Arne Bernin * 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 . The hand-tooled + thanks to Mark Whitley . The hand-tooled "regexp.[ch]" files have been removed. Much help on these from Matt Kraai as well. @@ -631,7 +807,7 @@ * Added a mini ar archive utility, especially written for BusyBox by Glenn McGrath * Added mktemp, contributed by Daniel Jacobowitz - * Added setkeycodes, for those that have wierd keyboard buttons. + * Added setkeycodes, for those that have weird keyboard buttons. * Added md5sum, uuencode and uudecode -- thanks to Alfred M. Szmidt for contributing these. * Added 'grep -v' option (inverted search) and updated @@ -1002,7 +1178,7 @@ 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 - ) + ) * Implemented tee. -beppu Implemented head. -beppu -Erik Andersen, Dec 10, 1999 @@ -1145,7 +1321,7 @@ 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 + 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 diff --git a/Changelog.full b/Changelog.full new file mode 100644 index 000000000..490283135 --- /dev/null +++ b/Changelog.full @@ -0,0 +1,138 @@ +2002-10-27 Erik Andersen + + * Makefile: Increment version number + + * debian/control, debian/changelog: Update packaging info + +2002-10-26 Erik Andersen + + * 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 + + * tftp.c: This patch from Magnus Damm fixed a long standing problem + with freeing memory. + +2002-10-23 Erik Andersen + + * top.c: Backport vodz' reworked top applet from unstable + +2002-10-22 Erik Andersen + + * ash.c, ifconfig.c: Fix warnings + + * md5sum.c: Fix undefined operation (temp = temp = ) 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 + + * 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 + + * 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 + + * docs/.cvsignore: oops + + * docs/.cvsignore, Makefile: Remove docs/busybox.pod on 'make clean' + + * init.c: + Patch from Ben Gamsa 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 fixes my stupid thinko so that 'cp -a' once + again copies symlinks properly. + +2002-09-30 Erik Andersen + + * 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 + + * time.c: Bug fix from Nitin Gupta + +2002-09-26 Erik Andersen + + * lash.c: Avoid calling exit() from within fork/vfork'ed processes. + -Erik + +2002-09-25 Erik Andersen + + * 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 + + * Makefile: Fixup largefile settings. + -Erik + +2002-09-20 Erik Andersen + + * gunzip.c: Doh! As noted by K.-P. Kirchd�rfer" , + gunzip -c deletes the source source file! This fixes it. + -Erik + + * top.c: Don't leak FILEs + diff --git a/busybox/Config.h b/Config.h similarity index 93% rename from busybox/Config.h rename to Config.h index e832eae7a..c5ece5939 100644 --- a/busybox/Config.h +++ b/Config.h @@ -9,7 +9,7 @@ // BusyBox Applications //#define BB_ADJTIMEX //#define BB_AR -//#define BB_ASH +#define BB_ASH #define BB_BASENAME #define BB_CAT #define BB_CHGRP @@ -68,6 +68,7 @@ //#define BB_LOADKMAP #define BB_LOGGER //#define BB_LOGNAME +//#define BB_LOSETUP #define BB_LS #define BB_LSMOD //#define BB_MAKEDEVS @@ -81,7 +82,7 @@ #define BB_MODPROBE #define BB_MORE #define BB_MOUNT -#define BB_MSH +//#define BB_MSH //#define BB_MT #define BB_MV //#define BB_NC @@ -117,6 +118,8 @@ //#define BB_TEST //#define BB_TELNET //#define BB_TFTP +//#define BB_TIME +//#define BB_TOP #define BB_TOUCH //#define BB_TR //#define BB_TRACEROUTE @@ -151,10 +154,10 @@ // // 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_ASH //#define BB_FEATURE_SH_IS_HUSH //#define BB_FEATURE_SH_IS_LASH -#define BB_FEATURE_SH_IS_MSH +//#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 @@ -179,12 +182,12 @@ //#define BB_FEATURE_USE_DEVPS_PATCH // // show verbose usage messages -//#define BB_FEATURE_VERBOSE_USAGE +#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) +// calculate terminal & column widths (for more, ls, and telnet) #define BB_FEATURE_AUTOWIDTH // // show username/groupnames for ls @@ -205,6 +208,9 @@ // 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 // @@ -295,6 +301,13 @@ // 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 // @@ -302,7 +315,7 @@ //#define BB_FEATURE_FBSET_READMODE // // Support insmod/lsmod/rmmod for post 2.1 kernels -//#define BB_FEATURE_NEW_MODULE_INTERFACE +#define BB_FEATURE_NEW_MODULE_INTERFACE // // Support insmod/lsmod/rmmod for pre 2.1 kernels //#define BB_FEATURE_OLD_MODULE_INTERFACE @@ -360,9 +373,12 @@ // Support for the find -perm option. #define BB_FEATURE_FIND_PERM // -// Support for the find -mtine option. +// 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 // @@ -405,16 +421,11 @@ // mere mortals so leave this stuff alone. // #include -#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ +#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_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 diff --git a/busybox/INSTALL b/INSTALL similarity index 100% rename from busybox/INSTALL rename to INSTALL diff --git a/busybox/LICENSE b/LICENSE similarity index 98% rename from busybox/LICENSE rename to LICENSE index 8e5a143d0..3f792d018 100644 --- a/busybox/LICENSE +++ b/LICENSE @@ -17,15 +17,14 @@ Copyright 1998 Dave Cinege mini-gzip(gzip), mini-netcat(mnc) Copyright 1998 Charles P. Wright -Tons of new stuff as noted in header files -Copyright (C) 1999,2000,2001 by Lineo, inc. and written by -Erik Andersen , - +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 Please feed suggestions, bug reports, insults, and bribes back to: Erik Andersen - + diff --git a/busybox/Makefile b/Makefile similarity index 76% rename from busybox/Makefile rename to Makefile index d231f69e7..331929365 100644 --- a/busybox/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Makefile for busybox # -# Copyright (C) 1999,2000,2001 Erik Andersen +# Copyright (C) 1999-2002 Erik Andersen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ # PROG := busybox -VERSION := 0.60.2.pre +VERSION := 0.60.5 BUILDTIME := $(shell TZ=UTC date -u "+%Y.%m.%d-%H:%M%z") export VERSION @@ -39,23 +39,31 @@ DOSTATIC = false # 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. +# 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=0x14f47d83,inter=100,log=logfile` +# 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 @@ -74,7 +82,7 @@ DOLFS = false # If you have a "pristine" source directory, point BB_SRC_DIR to it. # Experimental and incomplete; tell the mailing list -# if you do or don't like it so far. +# 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 @@ -82,11 +90,11 @@ BB_SRC_DIR = CROSS = CC = $(CROSS)gcc AR = $(CROSS)ar -STRIPTOOL = $(CROSS)strip +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 = ../uClibc/extra/gcc-uClibc/i386-uclibc-gcc +#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... @@ -106,15 +114,48 @@ STRIPTOOL = $(CROSS)strip #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 -# + +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" @@ -122,10 +163,9 @@ ARFLAGS = -r # 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 + # 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 @@ -143,11 +183,11 @@ endif ifeq ($(strip $(DODEBUG)),true) CFLAGS += $(WARNINGS) -g -D_GNU_SOURCE LDFLAGS += -Wl,-warn-common - STRIP = + STRIPCMD = /bin/true -Since_we_are_debugging else - CFLAGS += $(WARNINGS) $(OPTIMIZATION) -fomit-frame-pointer -D_GNU_SOURCE + CFLAGS += $(WARNINGS) $(OPTIMIZATIONS) -D_GNU_SOURCE LDFLAGS += -s -Wl,-warn-common - STRIP = $(STRIPTOOL) --remove-section=.note --remove-section=.comment $(PROG) + STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment endif ifeq ($(strip $(DOSTATIC)),true) LDFLAGS += --static @@ -164,7 +204,7 @@ ifeq ($(strip $(DOSTATIC)),true) #endif endif -ifndef $(PREFIX) +ifeq ($(strip $(PREFIX)),) PREFIX = `pwd`/_install endif @@ -237,7 +277,7 @@ 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 \ +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 \ @@ -245,7 +285,7 @@ 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 \ +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 \ @@ -303,15 +343,9 @@ docs/BusyBox.1: docs/busybox.pod - 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 +docs/BusyBox.html: docs/busybox.pod + -@ mkdir -p docs + - pod2html --noindex $< > docs/BusyBox.html -@ rm -f pod2htm* @@ -339,12 +373,12 @@ docs/busybox.pdf: docs/busybox.ps docs/busybox/busyboxdocumentation.html: docs/busybox.sgml - mkdir -p docs - (cd docs/busybox.lineo.com; sgmltools -b html ../busybox.sgml) + (cd docs; sgmltools -b html ../busybox.sgml) busybox: $(PWD_LIB) $(LIBBB_LIB) $(OBJECTS) $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBBB_LIB) $(PWD_LIB) $(LIBRARIES) - $(STRIP) + $(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 @@ -362,19 +396,27 @@ else endif $(PWD_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile - - mkdir -p $(PWD_GRP) +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 - - mkdir -p $(LIBBB) +ifneq ($(strip $(BB_SRC_DIR)),) + -mkdir -p $(LIBBB) +endif $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -c $< -o $*.o $(LIBBB_MOBJ): $(LIBBB_MSRC) - - mkdir -p $(LIBBB) +ifneq ($(strip $(BB_SRC_DIR)),) + -mkdir -p $(LIBBB) +endif $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o $(LIBBB_AROBJS): $(LIBBB_ARCSRC) - - mkdir -p $(LIBBB) +ifneq ($(strip $(BB_SRC_DIR)),) + -mkdir -p $(LIBBB) +endif $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o libpwd.a: $(PWD_OBJS) @@ -398,14 +440,13 @@ test tests: 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.1 docs/BusyBox.html docs/BusyBox.html - rm -f docs/busybox.txt docs/busybox.dvi docs/busybox.ps \ - docs/busybox.pdf docs/busybox.lineo.com/busybox.html + 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.links libbb/loop.h *~ slist.mk core applet_source_list - - find -name \*.o -exec rm -f {} \; + - 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 @@ -414,6 +455,9 @@ distclean: clean 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 diff --git a/busybox/README b/README similarity index 88% rename from busybox/README rename to README index b45ef57f4..7e978b632 100644 --- a/busybox/README +++ b/README @@ -39,8 +39,9 @@ Supported architectures: 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. + 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: @@ -82,7 +83,7 @@ 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 +archives at http://busybox.net/lists/busybox/ or even join the mailing list if you are interested. ---------------- @@ -90,12 +91,12 @@ 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. +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.lineo.com. Bug reports should look something like this: +to submit@bugs.busybox.net. Bug reports should look something like this: - To: submit@bugs.lineo.com + To: submit@bugs.busybox.net From: diligent@testing.linux.org Subject: /bin/true doesn't work @@ -123,30 +124,25 @@ understanding. FTP: Source for the latest released version can always be downloaded from - ftp://ftp.lineo.com/pub/busybox. + http://busybox.net/downloads/ ---------------- CVS: BusyBox now has its own publicly browsable CVS tree at: - http://opensource.lineo.com/cgi-bin/cvsweb/busybox/ + http://busybox.net/cgi-bin/cvsweb/busybox/ Anonymous CVS access is available. For instructions, check out: - http://opensource.lineo.com/cvs_anon.html + http://busybox.net/cvs_anon.html For those that are actively contributing there is even CVS write access: - http://opensource.lineo.com/cvs_write.html + http://busybox.net/cvs_write.html ---------------- Please feed suggestions, bug reports, insults, and bribes back to: Erik Andersen - + - - - -Many thanks to go to Lineo for paying me to work on busybox. - diff --git a/busybox/TODO b/TODO similarity index 94% rename from busybox/TODO rename to TODO index 3d9af20a7..1e6388576 100644 --- a/busybox/TODO +++ b/TODO @@ -18,7 +18,6 @@ around to it some time. If you have any good ideas, please let me know. Possible apps to include some time: * hwclock -* start-stop-daemon * group/commonize strings, remove dups (for i18n, l10n) ----------- @@ -46,10 +45,6 @@ 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/adjtimex.c similarity index 100% rename from busybox/adjtimex.c rename to adjtimex.c diff --git a/busybox/applets.c b/applets.c similarity index 100% rename from busybox/applets.c rename to applets.c diff --git a/busybox/applets.h b/applets.h similarity index 98% rename from busybox/applets.h rename to applets.h index 7d7517385..403c06ee7 100644 --- a/busybox/applets.h +++ b/applets.h @@ -242,6 +242,9 @@ #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 @@ -401,6 +404,12 @@ #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 diff --git a/busybox/ar.c b/ar.c similarity index 100% rename from busybox/ar.c rename to ar.c diff --git a/busybox/ash.c b/ash.c similarity index 51% rename from busybox/ash.c rename to ash.c index c0d47559d..6db0c887f 100644 --- a/busybox/ash.c +++ b/ash.c @@ -5,6 +5,10 @@ * Copyright (c) 1989, 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 1997-2003 Herbert Xu + * was re-ported from NetBSD and debianized. + * + * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * @@ -22,65 +26,89 @@ * 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 and - * Vladimir Oleynik to be used in busybox + * 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 * + * Modified by Vladimir Oleynik (c) 2001-2003 to be + * used in busybox and size optimizations, + * support locale, rewrited arith (see notes to this) * - * 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 +/* + * 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 ASH_ALIAS +#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. */ -//#undef ASH_MATH_SUPPORT -#define ASH_MATH_SUPPORT +#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 ASH_GETOPTS +#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 ASH_CMDCMD +#undef BB_ASH_CMDCMD +/* Check for mail */ +#undef BB_ASH_MAIL /* Optimize size vs speed as size */ -#define ASH_OPTIMIZE_FOR_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 -/* These are here to work with glibc -- Don't change these... */ -#undef FNMATCH_BROKEN -#undef GLOB_BROKEN + + #define IFS_BROKEN +#define PROFILE 0 + +#ifdef DEBUG +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include #include #include #include @@ -88,190 +116,122 @@ #include #include #include -#include #include #include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(FNMATCH_BROKEN) #include -#endif -#if !defined(GLOB_BROKEN) -#include + + +#include "busybox.h" +#include "pwd_grp/pwd.h" + +#ifdef BB_ASH_JOB_CONTROL +#define JOBS 1 +#else +#undef JOBS #endif -#ifdef JOBS +#if JOBS #include #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 */ +#ifdef __GLIBC__ +/* glibc sucks */ +static int *dash_errno; +#undef errno +#define errno (*dash_errno) +#endif -/* 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 */ +#if defined(__uClinux__) +#error "Do not even bother, ash will not run on uClinux" +#endif -#define SYNBASE 130 -#define PEOF -130 +#ifdef DEBUG +#define _DIAGASSERT(assert_expr) assert(assert_expr) +#else +#define _DIAGASSERT(assert_expr) +#endif -#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) +#ifdef BB_ASH_ALIAS +/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */ -/* 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 ALIASINUSE 1 +#define ALIASDEAD 2 -#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') +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 -#define _DIAGASSERT(x) +/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */ +static void setpwd(const char *, int); -#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 */ +/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */ -/* 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 */ +/* + * Types of operations (passed to the errmsg routine). + */ -/* 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 */ +static const char not_found_msg[] = "%s: not found"; -/* - * 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 +#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 */ /* - * Most machines require the value returned from malloc to be aligned - * in some way. The following macro will get this right on many machines. + * 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. */ -#ifndef ALIGN -union align { - int i; - char *cp; +struct jmploc { + jmp_buf loc; }; -#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1)) -#endif +static struct jmploc *handler; +static int exception; +static volatile int suppressint; +static volatile sig_atomic_t intpending; -#ifdef BB_LOCALE_SUPPORT -#include -static void change_lc_all(const char *value); -static void change_lc_ctype(const char *value); -#endif +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 @@ -280,105 +240,144 @@ static void change_lc_ctype(const char *value); * 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 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() -#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 *); +#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 */ /* - * 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. + * BSD setjmp saves the signal mask, which violates ANSI C and takes time, + * so we use _setjmp instead. */ -#define MINSIZE 504 /* minimum size of a block */ +#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 stack_block { - struct stack_block *prev; - char space[MINSIZE]; +struct strlist { + struct strlist *next; + char *text; }; -static struct stack_block stackbase; -static struct stack_block *stackp = &stackbase; -static struct stackmark *markp; -static char *stacknxt = stackbase.space; -static int stacknleft = MINSIZE; +struct arglist { + struct strlist *list; + struct strlist **lastp; +}; -#define equal(s1, s2) (strcmp(s1, s2) == 0) +/* + * 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 */ -#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')) +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 -#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) +/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */ -#define ckfree(p) free((pointer)(p)) +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 */ -#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 +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 NSEMI 0 -#define NCMD 1 -#define NPIPE 2 -#define NREDIR 3 -#define NBACKGND 4 -#define NSUBSHELL 5 -#define NAND 6 -#define NOR 7 +#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 @@ -388,91 +387,23 @@ static void opentrace (void); #define NDEFUN 14 #define NARG 15 #define NTO 16 -#define NFROM 17 -#define NFROMTO 18 -#define NAPPEND 19 -#define NTOOV 20 +#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 -/* - * 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 ncmd { + int type; + union node *assign; + union node *args; + union node *redirect; }; @@ -490,6 +421,13 @@ struct nredir { }; +struct nbinary { + int type; + union node *ch1; + union node *ch2; +}; + + struct nif { int type; union node *test; @@ -563,10 +501,10 @@ struct nnot { union node { int type; - struct nbinary nbinary; struct ncmd ncmd; struct npipe npipe; struct nredir nredir; + struct nbinary nbinary; struct nif nif; struct nfor nfor; struct ncase ncase; @@ -584,38 +522,72 @@ struct nodelist { 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 funcnode { + int count; + union node n; }; -struct strlist { - struct strlist *next; - char *text; -}; +static void freefunc(struct funcnode *); +/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */ -struct arglist { - struct strlist *list; - struct strlist **lastp; -}; +/* 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 ASH_ALIAS +#ifdef BB_ASH_ALIAS struct alias *ap; /* if push was associated with an alias */ #endif char *string; /* remember the string since it may change */ @@ -633,540 +605,657 @@ struct parsefile { struct strpush basestrpush; /* so pushing one is fast */ }; -struct stackmark { - struct stack_block *stackp; - char *stacknxt; - int stacknleft; - struct stackmark *marknext; -}; +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 */ -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 */ +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 $ */ -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 */ +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]; -static struct tblentry *cmdtable[CMDTABLESIZE]; -static int builtinloc = -1; /* index in path of %builtin, or -1 */ -static int exerrno = 0; /* Last exec error */ + 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. + */ -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 *); +#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. + */ -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); } +/* 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 */ -#ifndef ASH_OPTIMIZE_FOR_SIZE -#define out2c(c) putc((c), stderr) +#ifdef BB_ASH_ALIAS +#define SYNBASE 130 +#define PEOF -130 +#define PEOA -129 +#define PEOA_OR_PEOF PEOA #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 -}; +#define SYNBASE 129 +#define PEOF -129 +#define PEOA_OR_PEOF PEOF +#endif -/* 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 -}; +#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))) -/* 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 -}; +/* + * 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)) -/* 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 -}; +#define digit_val(c) ((c) - '0') -/* 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 -}; +/* + * This file was generated by the mksyntax program. + */ -/* 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, +#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 }; - -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\"", - "\"{\"", - "\"}\"", +#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 */ -#define KWDOFFSET 14 - -static const char *const parsekwd[] = { - "!", - "case", - "do", - "done", - "elif", - "else", - "esac", - "fi", - "for", - "if", - "in", - "then", - "until", - "while", - "{", - "}" +#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 */ -static int plinno = 1; /* input line number */ +/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */ -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 */ +#define ATABSIZE 39 -/* - * 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 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 int tokpushback; /* last token pushed back */ -#define NEOF ((union node *)&tokpushback) -static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ +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 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 evalstring(char *, int); +union node; /* BLETCH for ansi C */ +static void evaltree(union node *, int); +static void evalbackcmd(union node *, struct backcmd *); -static void shprocvar(void); -static void deletefuncs(void); -static void setparam (char **); -static void freeparam (volatile struct shparam *); +/* 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 @@ -1174,109 +1263,278 @@ static void freeparam (volatile struct shparam *); #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. + * This file was generated by the mkbuiltins program. */ -/* 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 */ -}; +#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 $ */ -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -#define rmescapes(p) _rmescapes((p), 0) -static char *_rmescapes (char *, int); -#else -static void rmescapes (char *); +#ifdef BB_ASH_MAIL +static void chkmail(void); +static void changemail(const char *); #endif -static int casematch (union node *, const char *); -static void clearredir(void); -static void popstring(void); -static void readcmdfile (const char *); +/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */ -static int number (const char *); -static int is_number (const char *, int *num); -static char *single_quote (const char *); -static int nextopt (const char *); +/* 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 */ -static void redirect (union node *, int); -static void popredir (void); -static int dup_as_newfd (int, int); +struct builtincmd { + const char *name; + int (*builtin)(int, char **); + /* unsigned flags; */ +}; -static void changepath(const char *newval); -static void getoptsreset(const char *value); +#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" -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 */ +#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1) +#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2) -static const char spcstr[] = " "; -static const char snlfmt[] = "%s\n"; +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 }, +}; -static int sstrnleft; -static int herefd = -1; +#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) ) -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; + +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 -struct varinit { - struct var *var; - int flags; - const char *text; - void (*func) (const char *); +/* $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 */ }; -static const char defpathvar[] = - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; -#define defpath (defpathvar + 5) +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 +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) @@ -1284,39 +1542,49 @@ static const char defifsvar[] = "IFS= \t\n"; static const char defifs[] = " \t\n"; #endif -static const struct varinit varinit[] = { + +static struct var varinit[] = { #ifdef IFS_BROKEN - { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar, + { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 }, #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 }, + { 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 - { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=", - change_lc_all }, - { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=", - change_lc_ctype }, + {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 - { NULL, 0, NULL, - NULL } }; -#define VTABSIZE 39 +#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] -static struct var *vartab[VTABSIZE]; +#define defpath (defpathvar + 5) /* * The following macros access the values of the above variables. @@ -1331,996 +1599,1114 @@ static struct var *vartab[VTABSIZE]; #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 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 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 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 inline int varequal(const char *a, const char *b) { + return !varcmp(a, b); +} -#ifdef ASH_ALIAS +static int loopnest; /* current loop nesting level */ -#define ALIASINUSE 1 -#define ALIASDEAD 2 +/* + * The parsefile structure pointed to by the global variable parsefile + * contains information about the current file being read. + */ -#define ATABSIZE 39 -struct alias { - struct alias *next; - char *name; - char *val; - int flag; +struct redirtab { + struct redirtab *next; + int renamed[10]; + int nullredirs; }; -static struct alias *atab[ATABSIZE]; +static struct redirtab *redirlist; +static int nullredirs; -static void setalias (char *, char *); -static struct alias **hashalias (const char *); -static struct alias *freealias (struct alias *); -static struct alias **__lookupalias (const char *); +extern char **environ; -static void -setalias(name, val) - char *name, *val; -{ - struct alias *ap, **app; +/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */ - 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; +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); - app = __lookupalias(name); +static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ - if (*app) { - INTOFF; - *app = freealias(*app); - INTON; - return (0); - } - return (1); +static void out1str(const char *p) +{ + outstr(p, stdout); } -static void -rmaliases(void) +static void out2str(const char *p) { - 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; + outstr(p, stderr); + flushout(stderr); } -static struct alias * -lookupalias(const char *name, int check) +/* + * Initialization code. + */ + +/* + * This routine initializes the builtin variables. + */ + +static inline void +initvar(void) { - struct alias *ap = *__lookupalias(name); + struct var *vp; + struct var *end; + struct var **vpp; - if (check && ap && (ap->flag & ALIASINUSE)) - return (NULL); - return (ap); + /* + * 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 void -printalias(const struct alias *ap) { - char *p; +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]; - p = single_quote(ap->val); - printf("alias %s=%s\n", ap->name, p); - stunalloc(p); + 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) */ /* - * TODO - sort output + * 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 -aliascmd(int argc, char **argv) -{ - char *n, *v; - int ret = 0; - struct alias *ap; - if (argc == 1) { - int i; +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); - 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); -} +/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */ -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; +/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ +#define FORK_FG 0 +#define FORK_BG 1 +#define FORK_NOJOB 2 - hashval = *p << 4; - while (*p) - hashval+= *p++; - return &atab[hashval % ATABSIZE]; -} +/* 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 */ -static struct alias * -freealias(struct alias *ap) { - struct alias *next; - if (ap->flag & ALIASINUSE) { - ap->flag |= ALIASDEAD; - return ap; - } +/* + * 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. + */ - next = ap->next; - ckfree(ap->name); - ckfree(ap->val); - ckfree(ap); - return next; -} +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 struct alias ** -__lookupalias(const char *name) { - struct alias **app = hashalias(name); +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 - for (; *app; app = &(*app)->next) { - if (equal(name, (*app)->name)) { - break; - } - } +static struct job *makejob(union node *, int); +static int forkshell(struct job *, union node *, int); +static int waitforjob(struct job *); +static int stoppedjobs(void); - return app; -} +#if ! JOBS +#define setjobctl(on) /* do nothing */ +#else +static void setjobctl(int); +static void showjobs(FILE *, int); #endif -#ifdef ASH_MATH_SUPPORT -/* The generated file arith.c has been replaced with a custom hand - * written implementation written by Aaron Lehmann . - * 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 */ +/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */ -/* - * 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); +/* 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); -#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" +/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */ -#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; +struct stackmark { + struct stack_block *stackp; + char *stacknxt; + size_t stacknleft; + struct stackmark *marknext; }; +/* minimum size of a block */ +#define MINSIZE SHELL_ALIGN(504) -/* 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 }, +struct stack_block { + struct stack_block *prev; + char space[MINSIZE]; }; -#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; +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; -/* 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. - */ +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 *); -struct procstat { - pid_t pid; /* process id */ - int status; /* status flags (defined above) */ - char *cmd; /* text of command being run */ -}; +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)) -static int job_warning; /* user was warned about stopped jobs */ +#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) +#define ungrabstackstr(s, p) stunalloc((s)) +#define stackstrend() ((void *)sstrend) -#ifdef JOBS -static void setjobctl(int enable); -#else -#define setjobctl(on) /* do nothing */ -#endif +#define ckfree(p) free((pointer)(p)) +/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */ -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 */ + +#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 }; -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 *); +#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 +}; -static int docd (char *, int); -static char *getcomponent (void); -static void updatepwd (const char *); -static void getpwd (void); +#define optletters(n) optletters_optnames[(n)][0] +#define optnames(n) (&optletters_optnames[(n)][1]) -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 char optlist[NOPTS]; -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; +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 */ - } - } - error("can't cd to %s", dest); - /* NOTREACHED */ -} +static char *minusc; /* argument to -c option */ -/* - * Actually do the chdir. In an interactive shell, print the - * directory name if "print" is nonzero. - */ +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 *); -static int -docd(dest, print) - char *dest; - int print; -{ - char *p; - char *q; - char *component; - struct stat statb; - int first; - int badstat; +/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */ - TRACE(("docd(\"%s\", %d) called\n", dest, print)); +/* flags passed to redirect */ +#define REDIR_PUSH 01 /* save previous values of file descriptors */ +#define REDIR_SAVEFD2 03 /* set preverrout */ - /* - * 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; - } - } +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); - INTOFF; - if (chdir(dest) < 0) { - INTON; - return -1; - } - updatepwd(badstat ? NULL : dest); - INTON; - if (print && iflag) - printf(snlfmt, curdir); - return 0; -} +/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */ -/* - * Get the next component of the path name pointed to by cdcomppath. - * This routine overwrites the string pointed to by cdcomppath. - */ +#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 -static char * -getcomponent() { - char *p; - char *start; +/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */ - 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; -} +/* 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); /* - * 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. + * 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 hashcd (void); - static void -updatepwd(const char *dir) +reset(void) { - char *new; - char *p; - size_t len; + /* from eval.c: */ + { + evalskip = 0; + loopnest = 0; + funcnest = 0; + } - hashcd(); /* update command hash table */ + /* from input.c: */ + { + parselleft = parsenleft = 0; /* clear input buffer */ + popallfiles(); + } - /* - * 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); -} + /* from parser.c: */ + { + tokpushback = 0; + checkkwd = 0; + } + /* from redir.c: */ + { + clearredir(0); + } -#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; -} +#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 -setpwd(const char *val, int setold) +setalias(const char *name, const char *val) { - if (setold) { - setvar("OLDPWD", curdir, VEXPORT); - } + struct alias *ap, **app; + + app = __lookupalias(name); + ap = *app; INTOFF; - if (curdir != nullstr) { - free(curdir); - curdir = nullstr; - } - if (!val) { - getpwd(); + if (ap) { + if (!(ap->flag & ALIASINUSE)) { + ckfree(ap->val); + } + ap->val = savestr(val); + ap->flag &= ~ALIASDEAD; } else { - curdir = savestr(val); + /* not found */ + ap = ckmalloc(sizeof (struct alias)); + ap->name = savestr(name); + ap->val = savestr(val); + ap->flag = 0; + ap->next = 0; + *app = ap; } 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 int +unalias(const char *name) +{ + struct alias **app; -static void exverror (int, const char *, va_list) - __attribute__((__noreturn__)); + app = __lookupalias(name); -/* - * 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". - */ + if (*app) { + INTOFF; + *app = freealias(*app); + INTON; + return (0); + } -static void exraise (int) __attribute__((__noreturn__)); + return (1); +} static void -exraise(int e) +rmaliases(void) { -#ifdef DEBUG - if (handler == NULL) - abort(); -#endif - flushall(); - exception = e; - longjmp(handler->loc, 1); + 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); +} /* - * 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.) + * TODO - sort output */ +static int +aliascmd(int argc, char **argv) +{ + char *n, *v; + int ret = 0; + struct alias *ap; -static void -onint(void) { - sigset_t mysigset; + if (argc == 1) { + int i; - if (suppressint) { - intpending++; - return; + for (i = 0; i < ATABSIZE; i++) + for (ap = atab[i]; ap; ap = ap->next) { + printalias(ap); + } + return (0); } - intpending = 0; - sigemptyset(&mysigset); - sigprocmask(SIG_SETMASK, &mysigset, NULL); - if (rootshell && iflag) - exraise(EXINT); - else { - signal(SIGINT, SIG_DFL); - raise(SIGINT); + 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); + } } - /* NOTREACHED */ -} + return (ret); +} -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) +static int +unaliascmd(int argc, char **argv) { - CLEAR_PENDING_INT; - INTOFF; + int i; -#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'); + while ((i = nextopt("a")) != '\0') { + if (i == 'a') { + rmaliases(); + return (0); + } } - exraise(cond); - /* NOTREACHED */ + 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; -static void -error(const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); - exverror(EXERROR, msg, ap); - /* NOTREACHED */ - va_end(ap); -} + if (ap->flag & ALIASINUSE) { + ap->flag |= ALIASDEAD; + return ap; + } + next = ap->next; + ckfree(ap->name); + ckfree(ap->val); + ckfree(ap); + return next; +} static void -exerror(int cond, const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); - exverror(cond, msg, ap); - /* NOTREACHED */ - va_end(ap); +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; -/* - * 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). - */ + ch = (unsigned char)*p; + hashval = ch << 4; + while (ch) { + hashval += ch; + ch = (unsigned char)*++p; + } + app = &atab[hashval % ATABSIZE]; -#define E_OPEN 01 /* opening a file */ -#define E_CREAT 02 /* creating a file */ -#define E_EXEC 04 /* executing a program */ + for (; *app; app = &(*app)->next) { + if (equal(name, (*app)->name)) { + break; + } + } -#define ALL (E_OPEN|E_CREAT|E_EXEC) + return app; +} +#endif /* BB_ASH_ALIAS */ -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)) +/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */ /* - * 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. + * The cd and pwd commands. */ -static const char * -errmsg(int e, int action) +#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) { - struct errname const *ep; - static char buf[12]; + int flags = 0; + int i, j; - for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) { - if (ep->errcode == e && (ep->action & action) != 0) - return strerror(e); + j = 'L'; + while ((i = nextopt("LP"))) { + if (i != j) { + flags ^= CD_PHYSICAL; + j = i; + } } - snprintf(buf, sizeof buf, "error %d", e); - return buf; + 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; -#ifdef ASH_OPTIMIZE_FOR_SIZE -static void -__inton() { - if (--suppressint == 0 && intpending) { - onint(); + 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); } -static void forceinton (void) { - suppressint = 0; - if (intpending) - onint(); -} + +/* + * 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 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 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 struct strlist *cmdenviron; /* environment for builtin command */ -static int exitstatus; /* exit status of last command */ -static int oexitstatus; /* saved exit status */ +static const struct builtincmd bltin = { + "\0\0", bltincmd +}; -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. */ @@ -2328,12 +2714,9 @@ static union node *parsecmd(int); /* * The eval commmand. */ -static void evalstring (char *, int); static int -evalcmd(argc, argv) - int argc; - char **argv; +evalcmd(int argc, char **argv) { char *p; char *concat; @@ -2345,8 +2728,7 @@ evalcmd(argc, argv) STARTSTACKSTR(concat); ap = argv + 2; for (;;) { - while (*p) - STPUTC(*p++, concat); + concat = stputs(p, concat); if ((p = *ap++) == NULL) break; STPUTC(' ', concat); @@ -2359,17 +2741,11 @@ evalcmd(argc, argv) 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) { @@ -2378,82 +2754,150 @@ evalstring(char *s, int flag) setstackmark(&smark); setinputstring(s); + while ((n = parsecmd(0)) != NEOF) { evaltree(n, flag); popstackmark(&smark); + if (evalskip) + break; } 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. + * Evaluate a parse tree. The value is left in the global variable + * exitstatus. */ 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) +evaltree(union node *n, int flags) { - struct tblentry *cmdp; - - INTOFF; - cmdp = cmdlookup(name, 1); - if (cmdp->cmdtype == CMDFUNCTION) { - freefunc(cmdp->param.func); + int checkexit = 0; + void (*evalfn)(union node *, int); + unsigned isor; + int status; + if (n == NULL) { + TRACE(("evaltree(NULL) called\n")); + goto out; } - cmdp->cmdtype = entry->cmdtype; - cmdp->param = entry->u; - INTON; + 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); } -static inline void -evalloop(const union node *n, int flags) + +#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) { @@ -2464,14 +2908,12 @@ skipping: if (evalskip == SKIPCONT && --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); + i = exitstatus; + if (n->type != NWHILE) + i = !i; + if (i != 0) + break; + evaltree(n->nbinary.ch2, flags); status = exitstatus; if (evalskip) goto skipping; @@ -2480,8 +2922,10 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { exitstatus = status; } + + static void -evalfor(const union node *n, int flags) +evalfor(union node *n, int flags) { struct arglist arglist; union node *argp; @@ -2491,8 +2935,8 @@ evalfor(const union node *n, int flags) 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); + /* XXX */ if (evalskip) goto out; } @@ -2500,9 +2944,10 @@ evalfor(const union node *n, int flags) 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 & EV_TESTED); + evaltree(n->nfor.body, flags); if (evalskip) { if (evalskip == SKIPCONT && --skipcount <= 0) { evalskip = 0; @@ -2518,8 +2963,10 @@ evalfor(const union node *n, int flags) popstackmark(&smark); } -static inline void -evalcase(const union node *n, int flags) + + +static void +evalcase(union node *n, int flags) { union node *cp; union node *patp; @@ -2528,8 +2975,8 @@ evalcase(const union node *n, int flags) setstackmark(&smark); arglist.lastp = &arglist.list; - oexitstatus = exitstatus; 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)) { @@ -2544,6 +2991,77 @@ evalcase(const union node *n, int flags) 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 @@ -2551,9 +3069,8 @@ evalcase(const union node *n, int flags) * of all the rest.) */ -static inline void -evalpipe(n) - union node *n; +static void +evalpipe(union node *n, int flags) { struct job *jp; struct nodelist *lp; @@ -2565,6 +3082,7 @@ evalpipe(n) pipelen = 0; for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) pipelen++; + flags |= EV_EXIT; INTOFF; jp = makejob(n, pipelen); prevfd = -1; @@ -2579,54 +3097,125 @@ evalpipe(n) } if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { INTON; + if (pip[1] >= 0) { + close(pip[0]); + } if (prevfd > 0) { - close(0); - dup_as_newfd(prevfd, 0); + dup2(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]); - } + if (pip[1] > 1) { + dup2(pip[1], 1); + close(pip[1]); } - evaltree(lp->n, EV_EXIT); + evaltreenr(lp->n, flags); + /* never returns */ } 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; } + INTON; } -static void find_command (const char *, struct cmdentry *, int, const char *); -static int -isassignment(const char *word) { - if (!is_name(*word)) { - return 0; + +/* + * 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; } - do { - word++; - } while (is_in_name(*word)); - return *word == '='; + + 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) { @@ -2636,588 +3225,344 @@ evalcommand(union node *cmd, int flags) struct arglist varlist; char **argv; int argc; - char **envp; - struct strlist *sp; - int mode; + const struct strlist *sp; 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 + 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); - arglist.lastp = &arglist.list; + back_exitstatus = 0; + + cmdentry.cmdtype = CMDBUILTIN; + cmdentry.u.cmd = &bltin; 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); + arglist.lastp = &arglist.list; + *arglist.lastp = NULL; + argc = 0; - for (sp = arglist.list ; sp ; sp = sp->next) - argc++; - argv = stalloc(sizeof (char *) * (argc + 1)); + 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)); - *argv++ = sp->text; + *nargv++ = sp->text; } - *argv = NULL; + *nargv = NULL; + lastarg = NULL; if (iflag && funcnest == 0 && argc > 0) - lastarg = argv[-1]; - argv -= argc; + lastarg = nargv[-1]; - /* Print the command if xflag is set. */ - if (xflag) { - out2c('+'); - eprintlist(varlist.list); - eprintlist(arglist.list); - out2c('\n'); - } + preverrout_fd = 2; + expredir(cmd->ncmd.redirect); + status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2); - /* 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; + 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 */ - for (sp = varlist.list ; sp ; sp = sp->next) - if (varequal(sp->text, defpathvar)) { - path = sp->text + 5; - findflag |= DO_BRUTE; + 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; - oldfindflag = findflag; - firstbltin = 0; - for(;;) { - find_command(argv[0], &cmdentry, findflag, path); - if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ - exitstatus = 127; - goto out; + 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) { + 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 (!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; + if (status) { + /* We have a redirection error. */ + if (spclbltin > 0) + exraise(EXERROR); +bail: + exitstatus = status; + goto out; } - /* 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; + 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; } - 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); + FORCEINTON; } - 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); + 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; } - 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; + break; -parent: /* parent process gets here (if we forked) */ - if (mode == 0) { /* argument to fork */ - INTOFF; - exitstatus = waitforjob(jp); - INTON; + 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); } -/* - * Evaluate a parse tree. The value is left in the global variable - * exitstatus. - */ -static void -evaltree(n, flags) - union node *n; - int flags; +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) { - 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; + volatile struct shparam saveparam; + struct localvar *volatile savelocalvars; + struct jmploc *volatile savehandler; + struct jmploc jmploc; + int e; - 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; + 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; } -out: - if (pendingsigs) - dotrap(); - if ( - flags & EV_EXIT || - (checkexit && eflag && exitstatus && !(flags & EV_TESTED)) - ) - exitshell(exitstatus); + return e; } + /* - * Kick off a subshell to evaluate a tree. + * 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 -evalsubshell(const union node *n, int flags) +prehash(union node *n) { - struct job *jp; - int backgnd = (n->type == NBACKGND); + struct cmdentry entry; - 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; - } + if (n->type == NCMD && n->ncmd.args) + find_command(n->ncmd.args->narg.text, &entry, 0, pathval()); } + + /* - * Compute the names of the files in a redirection list. + * Builtin commands. Builtin commands whose functions are closely + * tied to evaluation are implemented here. */ -static void fixredir(union node *n, const char *text, int err); +/* + * No command given. + */ -static void -expredir(union node *n) +static int +bltincmd(int argc, char **argv) { - 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; - } - } + /* + * Preserve exitstatus of a previous possible redirection + * as POSIX mandates + */ + return back_exitstatus; } /* - * 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. + * 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 void -evalbackcmd(union node *n, struct backcmd *result) +static int +breakcmd(int argc, char **argv) { - 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; + int n = argc > 1 ? number(argv[1]) : 1; + if (n <= 0) + error(illnum, argv[1]); if (n > loopnest) n = loopnest; if (n > 0) { @@ -3233,11 +3578,9 @@ breakcmd(argc, argv) */ static int -returncmd(argc, argv) - int argc; - char **argv; +returncmd(int argc, char **argv) { - int ret = argc > 1 ? number(argv[1]) : oexitstatus; + int ret = argc > 1 ? number(argv[1]) : exitstatus; if (funcnest) { evalskip = SKIPFUNC; @@ -3253,105 +3596,87 @@ returncmd(argc, argv) } -#ifndef BB_TRUE_FALSE static int -false_main(argc, argv) - int argc; - char **argv; +falsecmd(int argc, char **argv) { return 1; } static int -true_main(argc, argv) - int argc; - char **argv; +truecmd(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; +execcmd(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); + shellexec(argv + 1, pathval(), 0); } return 0; } -static void -eprintlist(struct strlist *sp) -{ - for (; sp; sp = sp->next) { - out2fmt(" %s",sp->text); - } -} + +/* $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 const char *pathopt; /* set by padvance */ - static void -shellexec(argv, envp, path, idx) - char **argv, **envp; - const char *path; - int idx; +shellexec(char **argv, const char *path, int idx) { char *cmdname; int e; + char **envp; - if (strchr(argv[0], '/') != NULL) { + 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 { @@ -3378,1133 +3703,1432 @@ shellexec(argv, envp, path, idx) 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 */ } -/* - * Clear traps on a fork. - */ + static void -clear_traps(void) { - char **tp; +tryexec(char *cmd, char **argv, char **envp) +{ + int repeated = 0; +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + int flg_bb = 0; + char *name = cmd; - 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; +#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"; } } -} - - -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; +repeat: +#ifdef SYSV + do { + execve(cmd, argv, envp); + } while (errno == EINTR); +#else + execve(cmd, argv, envp); #endif - } - - /* from options.c: */ - { - int i; + if (repeated++) { + ckfree(argv); + } else if (errno == ENOEXEC) { + char **ap; + char **new; - for (i = 0; i < NOPTS; i++) - optent_val(i) = 0; - optschanged(); + 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; + } +} - } - /* from redir.c: */ - { - clearredir(); - } - /* from trap.c: */ - { - char *sm; +/* + * 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. + */ - clear_traps(); - for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) { - if (*sm == S_IGN) - *sm = S_HARD_IGN; - } - } +static char * +padvance(const char **path, const char *name) +{ + const char *p; + char *q; + const char *start; + size_t len; - /* from var.c: */ - { - shprocvar(); - } + 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); } -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. - */ +/*** Command hashing code ***/ -#ifndef ASH_OPTIMIZE_FOR_SIZE -#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer()) -static int -pgetc(void) +static void +printentry(struct tblentry *cmdp) { - return pgetc_macro(); + 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)); } -#else + + static int -pgetc_macro(void) +hashcmd(int argc, char **argv) { - return --parsenleft >= 0? *parsenextc++ : preadbuffer(); -} + struct tblentry **pp; + struct tblentry *cmdp; + int c; + struct cmdentry entry; + char *name; -static inline int -pgetc(void) -{ - return pgetc_macro(); + 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; } -#endif /* - * Undo the last call to pgetc. Only one character may be pushed back. - * PEOF may be pushed back. + * Resolve a command name. If you change this routine, you may have to + * change the shellexec routine as well. */ static void -pungetc() { - parsenleft++; - parsenextc--; -} +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; -static void -popfile(void) { - struct parsefile *pf = parsefile; + 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; - 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; + cmdp = cmdlookup(name, 1); + cmdp->cmdtype = CMDBUILTIN; + cmdp->param.cmd = bcmd; INTON; +success: + cmdp->rehash = 0; + entry->cmdtype = cmdp->cmdtype; + entry->u = cmdp->param; } /* - * Return to top level. + * 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); +} -static void -popallfiles(void) { - while (parsefile != &basepf) - popfile(); +/* + * 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; } + + /* - * Close the file(s) that the shell is reading commands from. Called - * after a fork is done. + * Called when a cd is done. Marks all commands so the next time they + * are executed they will be rehashed. */ static void -closescript() { - popallfiles(); - if (parsefile->fd > 0) { - close(parsefile->fd); - parsefile->fd = 0; +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; + } } } + /* - * Like setinputfile, but takes an open file descriptor. Call this with - * interrupts off. + * 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 -setinputfd(fd, push) - int fd, push; +changepath(const char *newval) { - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); - if (push) { - pushfile(); - parsefile->buf = 0; - } else { - closescript(); - while (parsefile->strpush) - popstring(); + 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++; } - parsefile->fd = fd; - if (parsefile->buf == NULL) - parsefile->buf = ckmalloc(BUFSIZ); - parselleft = parsenleft = 0; - plinno = 1; + if (builtinloc < 0 && idx_bltin >= 0) + builtinloc = idx_bltin; /* zap builtins */ + if (builtinloc >= 0 && idx_bltin < 0) + firstchange = 0; + clearcmdentry(firstchange); + builtinloc = idx_bltin; } /* - * Set the input to take input from a file. If push is set, push the - * old input onto the stack first. + * Clear out command entries. The argument specifies the first entry in + * PATH which has changed. */ static void -setinputfile(const char *fname, int push) +clearcmdentry(int firstchange) { - int fd; - int myfileno2; + struct tblentry **tblp; + struct tblentry **pp; + struct tblentry *cmdp; 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; + 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; + } + } } - setinputfd(fd, push); INTON; } -static void -tryexec(char *cmd, char **argv, char **envp) + +/* + * 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) { - int e; + unsigned int hashval; + const char *p; + struct tblentry *cmdp; + struct tblentry **pp; -#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); + 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); } - errno = e; + lastcmdentry = pp; + return cmdp; } -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. + * Delete the command entry returned on the last lookup. */ -static const char *pathopt; +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; +} -static void growstackblock(void); +/* + * Add a new command entry, replacing any existing command entry for + * the same name - except special builtins. + */ -static char * -padvance(const char **path, const char *name) +static inline void +addcmdentry(char *name, struct cmdentry *entry) { - const char *p; - char *q; - const char *start; - int len; + struct tblentry *cmdp; - 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++; + cmdp = cmdlookup(name, 1); + if (cmdp->cmdtype == CMDFUNCTION) { + freefunc(cmdp->param.func); } - if (*p == ':') - *path = p + 1; - else - *path = NULL; - return stalloc(len); + cmdp->cmdtype = entry->cmdtype; + cmdp->param = entry->u; + cmdp->rehash = 0; } /* - * Wrapper around strcmp for qsort/bsearch/... + * Make a copy of a parse tree. */ -static int -pstrcmp(const void *a, const void *b) + +static inline struct funcnode * +copyfunc(union node *n) { - return strcmp((const char *) a, *(const char *const *) b); + 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; } /* - * Find a keyword is in a sorted array. + * Define a shell function. */ -static const char *const * -findkwd(const char *s) +static void +defun(char *name, union node *func) { - return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *), - sizeof(const char *), pstrcmp); + struct cmdentry entry; + + INTOFF; + entry.cmdtype = CMDFUNCTION; + entry.u.func = copyfunc(func); + addcmdentry(name, &entry); + INTON; } -/*** Command hashing code ***/ +/* + * 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 -hashcmd(argc, argv) - int argc; - char **argv; +describe_command(char *command, int describe_command_verbose) +#else +#define describe_command_verbose 1 +static int +describe_command(char *command) +#endif { - struct tblentry **pp; - struct tblentry *cmdp; - int c; - int verbose; struct cmdentry entry; - char *name; -#ifdef ASH_ALIAS + 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; + } - verbose = 0; - while ((c = nextopt("rvV")) != '\0') { - if (c == 'r') { - clearcmdentry(0); +#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; - } else if (c == 'v' || c == 'V') { - verbose = c; } + goto out; } - if (*argptr == NULL) { - for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (cmdp->cmdtype != CMDBUILTIN) { - printentry(cmdp, verbose); - } - } +#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); } - return 0; + if (describe_command_verbose) { + out1fmt(" is%s %s", + (cmdp ? " a tracked alias for" : nullstr), p + ); + } else { + out1str(p); + } + break; } - 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; + + case CMDFUNCTION: + if (describe_command_verbose) { + out1str(" is a shell function"); + } else { + out1str(command); } -#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; + break; + + case CMDBUILTIN: + if (describe_command_verbose) { + out1fmt(" is a %sshell builtin", + IS_BUILTIN_SPECIAL(entry.u.cmd) ? + "special " : nullstr + ); + } else { + out1str(command); } + break; - 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(); + default: + if (describe_command_verbose) { + out1str(": not found\n"); } + return 127; } - return c; + +out: + outstr("\n", stdout); + return 0; } -static void -printentry(cmdp, verbose) - struct tblentry *cmdp; - int verbose; - { - int idx; - const char *path; - char *name; +static int +typecmd(int argc, char **argv) +{ + int i; + int err = 0; - 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); + for (i = 1; i < argc; i++) { +#ifdef BB_ASH_CMDCMD + err |= describe_command(argv[i], 1); +#else + err |= describe_command(argv[i]); #endif } - printf(snlfmt, cmdp->rehash ? "*" : nullstr); + return err; } - - -/*** List the available builtins ***/ - - -static int helpcmd(int argc, char** argv) +#ifdef BB_ASH_CMDCMD +static int +commandcmd(int argc, char **argv) { - int col, i; + int c; + int default_path = 0; + int verify_only = 0; + int verbose_verify_only = 0; - 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; + 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; + } - for (i=0; i < NUM_APPLETS; i++) { + 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; + } - col += printf("%c%s", ((col == 0) ? '\t' : ' '), - applets[i].name); - if (col > 60) { - printf("\n"); - col = 0; - } - } + if (verify_only || verbose_verify_only) { + return describe_command(*argptr, verbose_verify_only); } -#endif - printf("\n\n"); - return EXIT_SUCCESS; + + return 0; } +#endif + +/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */ /* - * Resolve a command name. If you change this routine, you may have to - * change the shellexec routine as well. + * Routines to expand arguments to commands. We have to deal with + * backquotes, shell variables, and file metacharacters. */ -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; - } +/* + * _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 */ - updatetbl = 1; - if (act & DO_BRUTE) { - firstchange = path_change(path, &bltin); - } else { - bltin = builtinloc; - firstchange = 9999; - } +/* + * Structure specifying which parts of the string should be searched + * for IFS characters. + */ - /* 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; - } - } +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 */ +}; - bcmd = find_builtin(name); - regular = bcmd && IS_BUILTIN_REGULAR(bcmd); +/* 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. + */ - if (regular) { - if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) { - goto success; - } - } else if (act & DO_BRUTE) { - if (firstchange == 0) { - updatetbl = 0; - } +static inline char * +preglob(const char *pattern, int quoted, int flag) { + flag |= RMESCAPE_GLOB; + if (quoted) { + flag |= RMESCAPE_QUOTED; } + return _rmescapes((char *)pattern, flag); +} - /* 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; - } +static size_t +esclen(const char *start, const char *p) { + size_t esc = 0; - 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; + while (p > start && *--p == CTLESC) { + esc++; } - - /* 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; + return esc; } - /* - * Search the table of builtin commands. + * Expand shell variables and backquotes inside a here document. */ -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) +static inline void +expandhere(union node *arg, int fd) { - struct builtincmd *bp; - - bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd), - bstrcmp - ); - return bp; + herefd = fd; + expandarg(arg, (struct arglist *)NULL, 0); + xwrite(fd, stackblock(), expdest - (char *)stackblock()); } /* - * Called when a cd is done. Marks all commands so the next time they - * are executed they will be rehashed. + * 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 -hashcd(void) { - struct tblentry **pp; - struct tblentry *cmdp; +void +expandarg(union node *arg, struct arglist *arglist, int flag) +{ + struct strlist *sp; + char *p; - 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; - } + 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; } } - /* - * 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. + * 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 -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; -} +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; -/* - * Clear out command entries. The argument specifies the first entry in - * PATH which has changed. - */ + 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; -static void -clearcmdentry(firstchange) - int firstchange; -{ - struct tblentry **tblp; - struct tblentry **pp; - struct tblentry *cmdp; + 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; + } - 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; + 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 } } - INTON; +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; -/* - * Delete all functions. - */ - -static void -deletefuncs(void) { - struct tblentry **tblp; - struct tblentry **pp; - struct tblentry *cmdp; + name = p + 1; - 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; - } + 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; } } - INTON; +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); } - -/* - * 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) +static void +removerecordregions(int endoff) { - int hashval; - const char *p; - struct tblentry *cmdp; - struct tblentry **pp; + if (ifslastp == NULL) + return; - 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 (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; } - if (add && cmdp == NULL) { + + ifslastp = &ifsfirst; + while (ifslastp->next && ifslastp->next->begoff < endoff) + ifslastp=ifslastp->next; + while (ifslastp->next != NULL) { + struct ifsregion *ifsp; INTOFF; - cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB - + strlen(name) + 1); - cmdp->next = NULL; - cmdp->cmdtype = CMDUNKNOWN; - cmdp->rehash = 0; - strcpy(cmdp->cmdname, name); + ifsp = ifslastp->next->next; + ckfree(ifslastp->next); + ifslastp->next = ifsp; INTON; } - lastcmdentry = pp; - return cmdp; + if (ifslastp->endoff > endoff) + ifslastp->endoff = endoff; } + +#ifdef BB_ASH_MATH_SUPPORT /* - * Delete the command entry returned on the last lookup. + * 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; -static void -delete_cmd_entry() { - struct tblentry *cmdp; + /* ifsfree(); */ - INTOFF; - cmdp = *lastcmdentry; - *lastcmdentry = cmdp->next; - ckfree(cmdp); - INTON; -} + /* + * 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; -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)), -}; + removerecordregions(begoff); + flag = p[1]; + expdest = p; -/* - * Delete a function if it exists. - */ + if (quotes) + rmescapes(p + 2); -static void -unsetfunc(char *name) -{ - struct tblentry *cmdp; + len = cvtnum(dash_arith(p + 2)); - if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) { - freefunc(cmdp->param.func); - delete_cmd_entry(); - } + if (flag != '"') + recordregion(begoff, begoff + len, 0); } - +#endif /* - * Locate and print what a word is... + * Expand stuff in backwards quotes. */ -static int -typecmd(int argc, char **argv) +static void +expbackq(union node *cmd, int quoted, int quotes) { + struct backcmd in; int i; - int err = 0; - char *argv_a[2]; + char buf[128]; + char *p; + char *dest; + int startloc; + int syntax = quoted? DQSYNTAX : BASESYNTAX; + struct stackmark smark; - argv_a[1] = 0; + INTOFF; + setstackmark(&smark); + dest = expdest; + startloc = dest - (char *)stackblock(); + grabstackstr(dest); + evalbackcmd(cmd, (struct backcmd *) &in); + popstackmark(&smark); - for (i = 1; i < argc; i++) { - argv_a[0] = argv[i]; - argptr = argv_a; - optptr = "v"; - err |= hashcmd(argc, argv); + 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; } - 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; + if (in.buf) + ckfree(in.buf); + if (in.fd >= 0) { + close(in.fd); + back_exitstatus = waitforjob(in.jp); + } + INTON; - 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; - } + /* Eat all trailing newlines */ + dest = expdest; + for (; dest > (char *)stackblock() && dest[-1] == '\n';) + STUNPUTC(dest); + expdest = dest; - 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 (quoted == 0) + recordregion(startloc, dest - (char *)stackblock(), 0); + TRACE(("evalbackq: size=%d: \"%.*s\"\n", + (dest - (char *)stackblock()) - startloc, + (dest - (char *)stackblock()) - startloc, + stackblock() + startloc)); +} - 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); - } +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; } -#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++; +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--; + } } - new++, old++; } - if (builtinloc >= 0 && *bltin < 0) - firstchange = 0; - return firstchange; + return 0; } -/* - * 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 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); -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 *); + herefd = -1; + argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); + STPUTC('\0', expdest); + herefd = saveherefd; + argbackq = saveargbackq; + startp = stackblock() + startloc; -/* - * Expand shell variables and backquotes inside a here document. - */ + switch (subtype) { + case VSASSIGN: + setvar(str, startp, 0); + amount = startp - expdest; + STADJUST(amount, expdest); + return startp; -/* 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()); -} + case VSQUESTION: + varunset(p, str, startp, varflags); + /* NOTREACHED */ + } + subtype -= VSTRIMRIGHT; +#ifdef DEBUG + if (subtype < 0 || subtype > 3) + abort(); +#endif -/* - * 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. - */ + 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); -static void -expandarg(arg, arglist, flag) - union node *arg; - struct arglist *arglist; - int flag; -{ - struct strlist *sp; - char *p; + /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ + zero = subtype >> 1; + /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ + scan = (subtype & 1) ^ zero ? scanleft : scanright; - 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; + 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; } @@ -4512,124 +5136,84 @@ expandarg(arg, arglist, flag) * 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; +static char * +evalvar(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; + size_t varlen; int easy; - int quotes = flag & (EXP_FULL | EXP_CASE); + int quotes; + int quoted; + quotes = flag & (EXP_FULL | EXP_CASE); varflags = *p++; subtype = varflags & VSTYPE; + quoted = varflags & VSQUOTE; var = p; - special = 0; - if (! is_name(*p)) - special = 1; + easy = (!quoted || (*var == '@' && shellparam.nparam)); + varlen = 0; + startloc = expdest - (char *)stackblock(); p = strchr(p, '=') + 1; -again: /* jump here after setting a variable with ${var=text} */ - if (special) { + + if (!is_name(*var)) { 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); + set--; + if (subtype == VSPLUS) + goto vsplus; + if (++set) { + varvalue(var, quoted, flag); if (subtype == VSLENGTH) { - varlen = expdest - stackblock() - startloc; + varlen = + expdest - (char *)stackblock() - + startloc; STADJUST(-varlen, expdest); + goto vslen; } - } else { - if (subtype == VSLENGTH) { - varlen = strlen(val); - } else { - strtodest( - val, - varflags & VSQUOTE ? - DQSYNTAX : BASESYNTAX, - quotes - ); - } + } + } 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 == 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 (subtype == VSMINUS) { +vsplus: if (!set) { - argstr(p, flag); - break; + argstr( + p, flag | EXP_TILDE | + (quoted ? EXP_QWORD : EXP_WORD) + ); + goto end; } 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; + goto end; + } - case VSASSIGN: - case VSQUESTION: + if (subtype == VSASSIGN || subtype == VSQUESTION) { if (!set) { if (subevalvar(p, var, 0, subtype, startloc, - varflags, quotes)) { + varflags, 0)) { varflags &= ~VSNUL; /* * Remove any recorded regions beyond @@ -4638,26 +5222,70 @@ evalvar(p, flag) removerecordregions(startloc); goto again; } - break; + goto end; } if (easy) goto record; - break; + 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 } +#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; + 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++; @@ -4671,562 +5299,114 @@ evalvar(p, flag) } + /* - * 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. + * Test whether a specialized variable is set. */ -static void -argstr(p, flag) - char *p; - int flag; +static int +varisset(char *name, int nulok) { - 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; -} + if (*name == '!') + return backgndpid != 0; + else if (*name == '@' || *name == '*') { + if (*shellparam.p == NULL) + return 0; -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); + if (nulok) { + char **av; - 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; + for (av = shellparam.p; *av; av++) + if (**av != '\0') + return 1; + return 0; } - 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); -} - + } else if (is_digit(*name)) { + char *ap; + int num = atoi(name); -static void -removerecordregions(int endoff) -{ - if (ifslastp == NULL) - return; + if (num > shellparam.nparam) + return 0; - 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; - } + if (num == 0) + ap = arg0; + else + ap = shellparam.p[num - 1]; - 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 (nulok && (ap == NULL || *ap == '\0')) + return 0; } - if (ifslastp->endoff > endoff) - ifslastp->endoff = endoff; + return 1; } -#ifdef ASH_MATH_SUPPORT /* - * Expand arithmetic expression. Backup to start of expression, - * evaluate, place result in (backed up) result, adjust string position. + * Put a string on the stack. */ -static void -expari(int flag) -{ - char *p, *start; - int errcode; - int result; - int begoff; - int quotes = flag & (EXP_FULL | EXP_CASE); - int quoted; - /* ifsfree(); */ +static void +memtodest(const char *p, size_t len, int syntax, int quotes) { + char *q = expdest; - /* - * 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++; + q = makestrspace(len * 2, q); - 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); + while (len--) { + int c = *p++; + if (!c) + continue; + if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) + USTPUTC(CTLESC, q); + USTPUTC(c, q); } - snprintf(p, 12, "%d", result); - while (*p++) - ; + expdest = q; +} - if (quoted == 0) - recordregion(begoff, p - 1 - start, 0); - result = expdest - p + 1; - STADJUST(-result, expdest); + +static void +strtodest(const char *p, int syntax, int quotes) +{ + memtodest(p, strlen(p), syntax, quotes); } -#endif + /* - * Expand stuff in backwards quotes. + * Add the value of a specialized variable to the stack string. */ static void -expbackq(cmd, quoted, flag) - union node *cmd; - int quoted; - int flag; +varvalue(char *name, int quoted, int flags) { - volatile struct backcmd in; - int i; - char buf[128]; + int num; 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; - } + int i; + int sep; + int sepq = 0; + char **ap; + int syntax; + int allow_split = flags & EXP_FULL; + int quotes = flags & (EXP_FULL | EXP_CASE); - 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); + 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 '@': @@ -5238,15 +5418,17 @@ varvalue(name, quoted, flags) case '*': sep = ifsset() ? ifsval()[0] : ' '; if (quotes) { - sepq = syntax[(int) sep] == CCTL; + 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, expdest); - STPUTC(sep, expdest); + STPUTC(CTLESC, p); + STPUTC(sep, p); + expdest = p; } } break; @@ -5269,10 +5451,7 @@ varvalue(name, quoted, flags) */ static void -recordregion(start, end, nulonly) - int start; - int end; - int nulonly; +recordregion(int start, int end, int nulonly) { struct ifsregion *ifsp; @@ -5292,17 +5471,14 @@ recordregion(start, end, 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; - { +ifsbreakup(char *string, struct arglist *arglist) +{ struct ifsregion *ifsp; struct strlist *sp; char *start; @@ -5314,10 +5490,10 @@ ifsbreakup(string, arglist) start = string; - ifsspc = 0; - nulonly = 0; - realifs = ifsset() ? ifsval() : defifs; if (ifslastp != NULL) { + ifsspc = 0; + nulonly = 0; + realifs = ifsset() ? ifsval() : defifs; ifsp = &ifsfirst; do { p = string + ifsp->begoff; @@ -5371,11 +5547,14 @@ ifsbreakup(string, arglist) p++; } } while ((ifsp = ifsp->next) != NULL); - if (!(*start || (!ifsspc && start > string && nulonly))) { - return; - } + if (nulonly) + goto add; } + if (!*start) + return; + +add: sp = (struct strlist *)stalloc(sizeof *sp); sp->text = start; *arglist->lastp = sp; @@ -5383,133 +5562,60 @@ ifsbreakup(string, arglist) } static void -ifsfree() +ifsfree(void) { - while (ifsfirst.next != NULL) { + struct ifsregion *p; + + INTOFF; + p = ifsfirst.next; + do { struct ifsregion *ifsp; - INTOFF; - ifsp = ifsfirst.next->next; - ckfree(ifsfirst.next); - ifsfirst.next = ifsp; - INTON; - } + ifsp = p->next; + ckfree(p); + p = ifsp; + } while (p); ifslastp = NULL; ifsfirst.next = NULL; + INTON; } -/* - * 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); -} - +static void expmeta(char *, char *); +static struct strlist *expsort(struct strlist *); +static struct strlist *msort(struct strlist *, int); -#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ static char *expdir; static void -expandmeta(str, flag) - struct strlist *str; - int flag; +expandmeta(struct strlist *str, int flag) { - char *p; - struct strlist **savelastp; - struct strlist *sp; - char c; + static const char metachars[] = { + '*', '?', '[', 0 + }; /* TODO - EXP_REDIR */ while (str) { + struct strlist **savelastp; + struct strlist *sp; + char *p; + 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; - } + if (!strpbrk(str->text, metachars)) + goto nometa; savelastp = exparg.lastp; + INTOFF; - if (expdir == NULL) { + p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); + { int i = strlen(str->text); expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ } - expmeta(expdir, str->text); + expmeta(expdir, p); ckfree(expdir); - expdir = NULL; + if (p != str->text) + ckfree(p); INTON; if (exparg.lastp == savelastp) { /* @@ -5530,41 +5636,51 @@ expandmeta(str, flag) } } - /* - * Do metacharacter (i.e. *, ?, [...]) expansion. + * Add a file name to the list. */ 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; +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++) { + for (p = name; *p; p++) { if (*p == '*' || *p == '?') metaflag = 1; else if (*p == '[') { - q = p + 1; + char *q = p + 1; if (*q == '!') q++; for (;;) { - while (*q == CTLQUOTEMARK) - q++; - if (*q == CTLESC) + if (*q == '\\') q++; if (*q == '/' || *q == '\0') break; @@ -5573,46 +5689,36 @@ expmeta(enddir, name) 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) + } else if (*p == '\\') p++; - if (*p == '/') { + else if (*p == '/') { if (metaflag) - break; + goto out; start = p + 1; } } +out: 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 = name; + do { + if (*p == '\\') p++; *enddir++ = *p; - if (*p == '\0') - break; - } + } while (*p++); if (metaflag == 0 || lstat(expdir, &statb) >= 0) addfname(expdir); return; } endname = p; - if (start != name) { + if (name < start) { p = name; - while (p < start) { - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) + do { + if (*p == '\\') p++; *enddir++ = *p++; - } + } while (p < start); } if (enddir == expdir) { cp = "."; @@ -5634,18 +5740,16 @@ expmeta(enddir, name) } matchdot = 0; p = start; - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) + if (*p == '\\') p++; if (*p == '.') matchdot++; - while (! int_pending() && (dp = readdir(dirp)) != NULL) { + while (! intpending && (dp = readdir(dirp)) != NULL) { if (dp->d_name[0] == '.' && ! matchdot) continue; - if (patmatch(start, dp->d_name, 0)) { + if (pmatch(start, dp->d_name)) { if (atend) { - strcpy(enddir, dp->d_name); + scopy(dp->d_name, enddir); addfname(expdir); } else { for (p = enddir, cp = dp->d_name; @@ -5660,11 +5764,7 @@ expmeta(enddir, name) 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 @@ -5672,9 +5772,8 @@ expmeta(enddir, name) */ static struct strlist * -expsort(str) - struct strlist *str; - { +expsort(struct strlist *str) +{ int len; struct strlist *sp; @@ -5686,9 +5785,7 @@ expsort(str) static struct strlist * -msort(list, len) - struct strlist *list; - int len; +msort(struct strlist *list, int len) { struct strlist *p, *q = NULL; struct strlist **lpp; @@ -5708,7 +5805,12 @@ msort(list, len) p = msort(p, len - half); /* sort second half */ lpp = &list; for (;;) { - if (strcmp(p->text, q->text) < 0) { +#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) { @@ -5726,178 +5828,31 @@ msort(list, len) } 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) +static inline int +patmatch(char *pattern, const char *string) { - 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; + return pmatch(preglob(pattern, 0, 0), string); } -#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 }; + unsigned inquotes; + int notescaped; + int globbing; p = strpbrk(str, qchars); if (!p) { @@ -5907,75 +5862,71 @@ _rmescapes(char *str, int flag) r = str; if (flag & RMESCAPE_ALLOC) { size_t len = p - str; - q = r = stalloc(strlen(p) + len + 1); + 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) { - memcpy(q, str, len); - q += len; + 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 (flag & RMESCAPE_GLOB && *p != '/') { + if (notescaped && inquotes && *p != '/') { *q++ = '\\'; } } + notescaped = globbing; +copy: *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++; + if (flag & RMESCAPE_GROW) { + expdest = r; + STADJUST(q - r + 1, expdest); } - *q = '\0'; + return r; } -#endif - /* * See if a pattern matches in a case statement. */ -static int -casematch(union node *pattern, const char *val) +int +casematch(union node *pattern, 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); + STACKSTRNUL(expdest); + result = patmatch(stackblock(), val); popstackmark(&smark); return result; } @@ -5984,198 +5935,154 @@ casematch(union node *pattern, const char *val) * Our own itoa(). */ -static char * -cvtnum(num, buf) - int num; - char *buf; - { +static int +cvtnum(long num) +{ int len; - CHECKSTRSPACE(32, buf); - len = sprintf(buf, "%d", num); - STADJUST(len, buf); - return buf; + expdest = makestrspace(32, expdest); + len = fmtstr(expdest, 32, "%ld", num); + STADJUST(len, expdest); + return len; } -/* - * Editline and history functions (and glue). - */ -static int histcmd(argc, argv) - int argc; - char **argv; + +static void +varunset(const char *end, const char *var, const char *umsg, int varflags) { - error("not compiled with history support"); - /* NOTREACHED */ -} + 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); +} -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; +/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */ -extern char **environ; +/* + * 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); /* - * Initialization code. + * Read a line from the script. */ -static void -init(void) { +static inline char * +pfgets(char *line, int len) +{ + char *p = line; + int nleft = len; + int c; - /* from cd.c: */ - { - setpwd(0, 0); - } + while (--nleft > 0) { + c = pgetc2(); + if (c == PEOF) { + if (p == line) + return NULL; + break; + } + *p++ = c; + if (c == '\n') + break; + } + *p = '\0'; + return line; +} - /* from input.c: */ - { - basepf.nextc = basepf.buf = basebuf; - } - /* from var.c: */ - { - char **envp; - char ppid[32]; +/* + * Read a character from the script, returning PEOF on end of file. + * Nul characters in the input are silently discarded. + */ - initvar(); - for (envp = environ ; *envp ; envp++) { - if (strchr(*envp, '=')) { - setvareq(*envp, VEXPORT|VTEXTFIXED); - } - } +#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer()) - snprintf(ppid, sizeof(ppid), "%d", (int) getppid()); - setvar("PPID", ppid, 0); - } +#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 /* - * This routine is called when an error or an interrupt occurs in an - * interactive shell and control is returned to the main command loop. + * Same as pgetc(), but ignores PEOA. */ +#ifdef BB_ASH_ALIAS +static int pgetc2(void) +{ + int c; -/* 1 == check for aliases, 2 == also check for assignments */ -static int checkalias; /* also used in no alias mode for check assignments */ + do { + c = pgetc_macro(); + } while (c == PEOA); + return c; +} +#else +static inline int pgetc2(void) +{ + return pgetc_macro(); +} +#endif -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() +static const char *cmdedit_prompt; +static inline void putprompt(const char *s) { - int c; - do { - c = pgetc_macro(); - } while (c == PEOA); - return c; + cmdedit_prompt = s; } #else -static inline int pgetc2() { return pgetc_macro(); } -#endif - -/* - * Read a line from the script. - */ - -static inline char * -pfgets(char *line, int len) +static inline void putprompt(const char *s) { - 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; + out2str(s); } +#endif static inline int preadfd(void) { - int nr; - char *buf = parsefile->buf; - parsenextc = buf; + 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 (!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); @@ -6196,39 +6103,6 @@ preadfd(void) 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: * @@ -6239,7 +6113,7 @@ popstring(void) * 4) Process input up to the next newline, deleting nul characters. */ -static int +int preadbuffer(void) { char *p, *q; @@ -6247,7 +6121,7 @@ preadbuffer(void) char savec; while (parsefile->strpush) { -#ifdef ASH_ALIAS +#ifdef BB_ASH_ALIAS if (parsenleft == -1 && parsefile->strpush->ap && parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { return PEOA; @@ -6278,11 +6152,11 @@ preadbuffer(void) p++; /* Skip nul */ goto check; - case '\n': parsenleft = q - parsenextc; more = 0; /* Stop processing here */ break; + } *q++ = *p++; @@ -6307,16 +6181,29 @@ preadbuffer(void) 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. */ -static void -pushstring(char *s, int len, void *ap) +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) { @@ -6327,7 +6214,7 @@ pushstring(char *s, int len, void *ap) sp = parsefile->strpush = &(parsefile->basestrpush); sp->prevstring = parsenextc; sp->prevnleft = parsenleft; -#ifdef ASH_ALIAS +#ifdef BB_ASH_ALIAS sp->ap = (struct alias *)ap; if (ap) { ((struct alias *)ap)->flag |= ALIASINUSE; @@ -6339,6 +6226,81 @@ pushstring(char *s, int len, void *ap) 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. @@ -6357,14 +6319,14 @@ setinputstring(char *string) } - /* * 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) { +pushfile(void) +{ struct parsefile *pf; parsefile->nleft = parsenleft; @@ -6379,105 +6341,218 @@ pushfile(void) { 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); + +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; +} /* - * 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 to top level. + */ -/* Return true if fd 0 has already been redirected at least once. */ -static inline int -fd0_redirected_p () { - return fd0_redirected != 0; +static void +popallfiles(void) +{ + while (parsefile != &basepf) + popfile(); } -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. + * 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 setjobctl(int enable) +static void +set_curjob(struct job *jp, unsigned mode) { -#ifdef OLD_TTY_DRIVER - int ldisc; -#endif + struct job *jp1; + struct job **jpp, **curp; - 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) { + /* 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 - 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; - } + 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 - setsignal(SIGTSTP); + 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); - 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 + 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; } - jobctl = enable; + ttyfd = fd; + jobctl = on; } -#endif - -#ifdef JOBS static int -killcmd(argc, argv) - int argc; - char **argv; +killcmd(int argc, char **argv) { int signo = -1; int list = 0; @@ -6493,13 +6568,17 @@ killcmd(argc, argv) ); } - if (*argv[1] == '-') { - signo = decode_signal(argv[1] + 1, 1); + 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; @@ -6512,133 +6591,255 @@ killcmd(argc, argv) ); } break; -#ifdef DEBUG - default: - error( - "nextopt returned character code 0%o", c); -#endif - } + } + argv = argptr; } else - argptr++; + argv++; } if (!list && signo < 0) signo = SIGTERM; - if ((signo < 0 || !*argptr) ^ list) { + if ((signo < 0 || !*argv) ^ list) { goto usage; } if (list) { const char *name; - if (!*argptr) { - out1str("0\n"); + if (!*argv) { for (i = 1; i < NSIG; i++) { name = u_signal_names(0, &i, 1); - if(name) - printf(snlfmt, name); + if (name) + out1fmt(snlfmt, name); } return 0; } name = u_signal_names(*argptr, &signo, -1); if (name) - printf(snlfmt, name); + out1fmt(snlfmt, name); else - error("invalid signal number or exit status: %s", - *argptr); + error("invalid signal number or exit status: %s", *argptr); return 0; } + i = 0; do { - if (**argptr == '%') { - jp = getjob(*argptr); - if (jp->jobctl == 0) - error("job %s not created under job control", - *argptr); + if (**argv == '%') { + jp = getjob(*argv, 0); pid = -jp->ps[0].pid; } else - pid = atoi(*argptr); - if (kill(pid, signo) != 0) - error("%s: %m", *argptr); - } while (*++argptr); + pid = number(*argv); + if (kill(pid, signo) != 0) { + sh_warnx("%m\n"); + i = 1; + } + } while (*++argv); - return 0; + return i; } +#endif /* JOBS */ +#if defined(JOBS) || defined(DEBUG) static int -fgcmd(argc, argv) - int argc; - char **argv; +jobno(const struct job *jp) { - 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; + return jp - jobtab + 1; } +#endif - +#ifdef JOBS static int -bgcmd(argc, argv) - int argc; - char **argv; +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); - if (jp->jobctl == 0) - error("job not created under job control"); - restartjob(jp); - } while (--argc > 1); - return 0; + 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 void -restartjob(jp) - struct job *jp; + +static int +restartjob(struct job *jp, int mode) { struct procstat *ps; int i; + int status; + pid_t pgid; - if (jp->state == JOBDONE) - return; INTOFF; - killpg(jp->ps[0].pid, SIGCONT); - for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { + 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; - jp->state = 0; } - } + } 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); -static void showjobs(int change); + jp->changed = 0; + + if (jp->state == JOBDONE) { + TRACE(("showjob: freeing job %d\n", jobno(jp))); + freejob(jp); + } +} static int -jobscmd(argc, argv) - int argc; - char **argv; +jobscmd(int argc, char **argv) { - showjobs(0); + 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; } @@ -6646,81 +6847,25 @@ jobscmd(argc, argv) /* * 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; +showjobs(FILE *out, int mode) { - 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); - } + 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. @@ -6729,7 +6874,7 @@ showjobs(change) static void freejob(struct job *jp) { - const struct procstat *ps; + struct procstat *ps; int i; INTOFF; @@ -6740,66 +6885,70 @@ freejob(struct job *jp) if (jp->ps != &jp->ps0) ckfree(jp->ps); jp->used = 0; -#ifdef JOBS - if (curjob == jp - jobtab + 1) - curjob = 0; -#endif + set_curjob(jp, CUR_DELETE); INTON; } - static int -waitcmd(argc, argv) - int argc; - char **argv; +waitcmd(int argc, char **argv) { struct job *job; - int status, retval; + int 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; + 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->used && jp->state == 0) + if (jp->state == JOBRUNNING) break; + jp->waited = 1; + jp = jp->prev_job; } - } - if (dowait(2, 0) < 0 && errno == EINTR) { - return 129; + 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; +} /* @@ -6807,113 +6956,175 @@ waitcmd(argc, argv) */ static struct job * -getjob(const char *name) +getjob(const char *name, int getctl) { - int jobno; struct job *jp; - int pid; - int i; + struct job *found; + const char *err_msg = "No such job: %s"; + unsigned num; + int c; + const char *p; + char *(*match)(const char *, const char *); - if (name == NULL) { -#ifdef JOBS + 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: - 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; + 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; } - } 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; + } + + if (is_number(p)) { + num = atoi(p); + if (num < njobs) { + jp = jobtab + num - 1; + if (jp->used) + goto gotit; + goto err; } } - error("No such job: %s", name); - /* NOTREACHED */ -} + 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, + * Return a new job structure. + * Called with interrupts off. */ static struct job * -makejob(const union node *node, int nprocs) +makejob(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; + jp = growjobtab(); break; } if (jp->used == 0) break; + if (jp->state != JOBDONE || !jp->waited) + continue; +#if JOBS + if (jobctl) + continue; +#endif + freejob(jp); + break; } - INTOFF; - jp->state = 0; - jp->used = 1; - jp->changed = 0; - jp->nprocs = 0; -#ifdef JOBS - jp->jobctl = jobctl; + 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)); - } else { - jp->ps = &jp->ps0; } - INTON; TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, - jp - jobtab + 1)); + 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 of a subshell. If we are doing job control, give the subshell its + * 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: @@ -6925,117 +7136,114 @@ makejob(const union node *node, int nprocs) * 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 int -forkshell(struct job *jp, const union node *n, int mode) +static inline void +forkchild(struct job *jp, union node *n, int mode) { - int pid; -#ifdef JOBS - int pgrp; -#endif - const char *devnull = _PATH_DEVNULL; - const char *nullerr = "Can't open %s"; + int wasroot; - 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; - 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); - } - } + 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 - for (i = njobs, p = jobtab ; --i >= 0 ; p++) - if (p->used) - freejob(p); - if (wasroot && iflag) { - setsignal(SIGINT); - setsignal(SIGQUIT); - setsignal(SIGTERM); + 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); } - return pid; } -#ifdef JOBS - if (rootshell && mode != FORK_NOJOB && mflag) { - if (jp == NULL || jp->nprocs == 0) + 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; - setpgid(pid, pgrp); + /* This can fail because we are doing it in the child also */ + (void)setpgid(pid, pgrp); } #endif - if (mode == FORK_BG) + 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 (iflag && rootshell && n) +#if JOBS + if (jobctl && n) ps->cmd = commandtext(n); +#endif } - INTON; - TRACE(("In parent shell: child = %d\n", pid)); - return pid; } +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. @@ -7054,91 +7262,41 @@ forkshell(struct job *jp, const union node *n, int mode) * 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. */ -static int +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 + TRACE(("waitforjob(%%%d) called\n", jobno(jp))); + while (jp->state == JOBRUNNING) { + dowait(DOWAIT_BLOCK, jp); } - 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 + 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 - * occured, and if so interrupt ourselves. Yuck. - mycroft + * occurred, and if so interrupt ourselves. Yuck. - mycroft */ - if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) + if (jp->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 @@ -7161,15 +7319,19 @@ waitforjob(struct job *jp) * 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; + int flags = 0; - flags = 0; -#ifdef JOBS +#if JOBS if (jobctl) flags |= WUNTRACED; #endif @@ -7178,355 +7340,487 @@ waitproc(int block, int *status) 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 procstat *sp; struct job *jp; struct job *thisjob; - int done; - int stopped; - int core; - int sig; + int state; 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); + pid = waitproc(block, &status); + TRACE(("wait returns pid %d, status=%d\n", pid, status)); 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; + 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 (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; + if (sp->status == -1) + state = JOBRUNNING; #ifdef JOBS - if (done && curjob == jp - jobtab + 1) - curjob = 0; /* no current job */ -#endif - } + if (state == JOBRUNNING) + continue; + if (WIFSTOPPED(sp->status)) { + jp->stopstatus = sp->status; + state = JOBSTOPPED; } - } +#endif + } while (++sp < spend); + if (thisjob) + goto gotjob; } - INTON; - if (! rootshell || ! iflag || (job && thisjob == job)) { - core = WCOREDUMP(status); #ifdef JOBS - if (WIFSTOPPED(status)) sig = WSTOPSIG(status); - else + if (!WIFSTOPPED(status)) #endif - if (WIFEXITED(status)) sig = 0; - else sig = WTERMSIG(status); - if (sig != 0 && sig != SIGINT && sig != SIGPIPE) { - if (thisjob != job) - out2fmt("%d: ", pid); + 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 (sig == SIGTSTP && rootshell && iflag) - out2fmt("%%%ld ", - (long)(job - jobtab + 1)); + if (state == JOBSTOPPED) { + set_curjob(thisjob, CUR_STOPPED); + } #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; -} +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 */ -static int + +int stoppedjobs(void) { - int jobno; struct job *jp; + int retval; + retval = 0; 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); - } + goto out; + jp = curjob; + if (jp && jp->state == JOBSTOPPED) { + out2str("You have stopped jobs.\n"); + job_warning = 2; + retval++; } - return (0); +out: + return retval; } /* * Return a string identifying a command (to be printed by the - * jobs command. + * jobs command). */ +#if JOBS static char *cmdnextc; -static int cmdnleft; -#define MAXCMDTEXT 200 -static void -cmdputs(const char *s) +static char * +commandtext(union node *n) { - const char *p; - char *q; - char c; - int subtype = 0; + char *name; - 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; + 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(const union node *n) +cmdtxt(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; + default: +#if DEBUG + abort(); +#endif case NPIPE: - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { + lp = n->npipe.cmdlist; + for (;;) { cmdtxt(lp->n); - if (lp->next) - cmdputs(" | "); + lp = lp->next; + if (!lp) + break; + cmdputs(" | "); } break; - case NSUBSHELL: - cmdputs("("); - cmdtxt(n->nredir.n); - 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: - cmdtxt(n->nredir.n); + 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 "); - cmdtxt(n->nif.ifpart); - cmdputs("..."); - break; + 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: - cmdputs("while "); + p = "while "; goto until; case NUNTIL: - cmdputs("until "); + p = "until "; until: + cmdputs(p); cmdtxt(n->nbinary.ch1); + n = n->nbinary.ch2; + p = "; done"; +dodo: cmdputs("; do "); - cmdtxt(n->nbinary.ch2); - cmdputs("; done"); - break; +dotail: + cmdtxt(n); + goto dotail2; case NFOR: cmdputs("for "); cmdputs(n->nfor.var); - cmdputs(" in ..."); - break; - case NCASE: - cmdputs("case "); - cmdputs(n->ncase.expr->narg.text); - cmdputs(" in ..."); - break; + cmdputs(" in "); + cmdlist(n->nfor.args, 1); + n = n->nfor.body; + p = "; done"; + goto dodo; case NDEFUN: cmdputs(n->narg.text); - cmdputs("() ..."); - break; + p = "() { ... }"; + goto dotail2; 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); - } + cmdlist(n->ncmd.args, 1); + cmdlist(n->ncmd.redirect, 0); break; case NARG: - cmdputs(n->narg.text); + 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 = ">"; i = 1; goto redir; + p = ">"; + goto redir; + case NCLOBBER: + p = ">|"; + goto redir; case NAPPEND: - p = ">>"; i = 1; goto redir; + p = ">>"; + goto redir; case NTOFD: - p = ">&"; i = 1; goto redir; - case NTOOV: - p = ">|"; i = 1; goto redir; + p = ">&"; + goto redir; case NFROM: - p = "<"; i = 0; goto redir; + p = "<"; + goto redir; case NFROMFD: - p = "<&"; i = 0; goto redir; + p = "<&"; + goto redir; case NFROMTO: - p = "<>"; i = 0; goto redir; + p = "<>"; redir: - if (n->nfile.fd != i) { - s[0] = n->nfile.fd + '0'; - s[1] = '\0'; - cmdputs(s); - } + 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); + p = s; + goto dotail2; } else { - cmdtxt(n->nfile.fname); + n = n->nfile.fname; + goto donode; } - break; - case NHERE: - case NXHERE: - cmdputs("<<..."); - break; - default: - cmdputs("???"); - break; } } - -static char * -commandtext(const union node *n) +static void +cmdlist(union node *np, int sep) { - char *name; - - cmdnextc = name = ckmalloc(MAXCMDTEXT); - cmdnleft = MAXCMDTEXT - 4; - cmdtxt(n); - *cmdnextc = '\0'; - return name; -} - - -static void waitonint(int sig) { - intreceived = 1; - return; + for (; np; np = np->narg.next) { + if (!sep) + cmdputs(spcstr); + cmdtxt(np); + if (sep && np->narg.next) + cmdputs(spcstr); + } } -/* - * 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) +cmdputs(const char *s) { - int i; - const char *mpath; - char *p; - char *q; - struct stackmark smark; - struct stat statb; + const char *p, *str; + char c, cc[2] = " "; + char *nextc; + int subtype = 0; + int quoted = 0; + static const char *const vstype[16] = { + nullstr, "}", "-", "+", "?", "=", + "#", "##", "%", "%%" + }; - 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) + 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; @@ -7536,31 +7830,42 @@ chkmail(int silent) 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"); + 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" + ); } - mailtime[i] = statb.st_size; + *mtp = statb.st_mtime; } - nmboxes = i; + mail_var_path_changed = 0; popstackmark(&smark); } -#define PROFILE 0 + +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 void read_profile (const char *); -static void cmdloop (int); -static void options (int); -static void setoption (int, int); -static void procargs (int, char **); +static int isloginsh; +static void read_profile(const char *); /* * Main routine. We initialize things, parse the arguments, execute @@ -7571,65 +7876,48 @@ static void procargs (int, char **); */ int -ash_main(argc, argv) - int argc; - char **argv; +ash_main(int argc, char **argv) { + char *shinit; + volatile int state; 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"); +#ifdef __GLIBC__ + dash_errno = __errno_location(); #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; + int status; + int e; + reset(); + + e = exception; + switch (exception) { case EXEXEC: - exitstatus = exerrno; + status = exerrno; break; case EXERROR: - exitstatus = 2; + status = 2; break; default: + status = exitstatus; break; } + exitstatus = status; - if (exception != EXSHELLPROC) { - if (state == 0 || iflag == 0 || ! rootshell) - exitshell(exitstatus); - } - reset(); - if (exception == EXINT) { - out2c('\n'); + if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell) + exitshell(); + + if (e == EXINT) { + outcslow('\n', stderr); } popstackmark(&smark); FORCEINTON; /* enable interrupts */ @@ -7652,7 +7940,23 @@ ash_main(argc, argv) init(); setstackmark(&smark); procargs(argc, argv); - if (argv[0] && argv[0][0] == '-') { +#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: @@ -7661,44 +7965,43 @@ ash_main(argc, argv) } state2: state = 3; + if ( #ifndef linux - if (getuid() == geteuid() && getgid() == getegid()) { + getuid() == geteuid() && getgid() == getegid() && #endif + iflag + ) { 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) { +#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 - exitshell(exitstatus); +#if GPROF + { + extern void _mcleanup(void); + _mcleanup(); + } +#endif + exitshell(); /* NOTREACHED */ } @@ -7721,12 +8024,16 @@ cmdloop(int top) for (;;) { if (pendingsigs) dotrap(); +#if JOBS + if (jobctl) + showjobs(stderr, SHOW_CHANGED); +#endif inter = 0; if (iflag && top) { inter++; - showjobs(1); - chkmail(0); - flushall(); +#ifdef BB_ASH_MAIL + chkmail(); +#endif } n = parsecmd(inter); /* showtree(n); DEBUG */ @@ -7755,14 +8062,12 @@ cmdloop(int top) } - /* * Read /etc/profile or .profile. Return on error. */ static void -read_profile(name) - const char *name; +read_profile(const char *name) { int fd; int xflag_set = 0; @@ -7792,13 +8097,12 @@ read_profile(name) } - /* * Read a file containing shell functions. */ static void -readcmdfile(const char *name) +readcmdfile(char *name) { int fd; @@ -7813,26 +8117,23 @@ readcmdfile(const char *name) } - /* - * Take commands from a file. To be compatable we should do a path + * 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(mybasename) - char *mybasename; +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(mybasename, '/')) - return mybasename; + if (strchr(name, '/')) + return name; - while ((fullname = padvance(&path, mybasename)) != NULL) { + while ((fullname = padvance(&path, name)) != NULL) { if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { /* * Don't bother freeing here, since it will @@ -7844,21 +8145,15 @@ find_dot_file(mybasename) } /* not found in the PATH */ - error("%s: not found", mybasename); + error(not_found_msg, name); /* NOTREACHED */ } -static int -dotcmd(argc, argv) - int argc; - char **argv; +int +dotcmd(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; @@ -7876,66 +8171,110 @@ dotcmd(argc, argv) static int -exitcmd(argc, argv) - int argc; - char **argv; +exitcmd(int argc, char **argv) { if (stoppedjobs()) return 0; if (argc > 1) exitstatus = number(argv[1]); - else - exitstatus = oexitstatus; - exitshell(exitstatus); + 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(int nbytes) +stalloc(size_t nbytes) { char *p; + size_t aligned; - nbytes = ALIGN(nbytes); - if (nbytes > stacknleft) { - int blocksize; + aligned = SHELL_ALIGN(nbytes); + if (aligned > stacknleft) { + size_t len; + size_t blocksize; struct stack_block *sp; - blocksize = nbytes; + blocksize = aligned; if (blocksize < MINSIZE) blocksize = MINSIZE; + len = sizeof(struct stack_block) - MINSIZE + blocksize; + if (len < blocksize) + error(memory_exhausted); INTOFF; - sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize); + sp = ckmalloc(len); sp->prev = stackp; stacknxt = sp->space; stacknleft = blocksize; + sstrend = stacknxt + blocksize; stackp = sp; INTON; } p = stacknxt; - stacknxt += nbytes; - stacknleft -= nbytes; + stacknxt += aligned; + stacknleft -= aligned; return p; } -static void +void stunalloc(pointer p) { #ifdef DEBUG - if (p == NULL) { /*DEBUG */ + if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { 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 +void setstackmark(struct stackmark *mark) { mark->stackp = stackp; @@ -7946,7 +8285,7 @@ setstackmark(struct stackmark *mark) } -static void +void popstackmark(struct stackmark *mark) { struct stack_block *sp; @@ -7960,6 +8299,7 @@ popstackmark(struct stackmark *mark) } stacknxt = mark->stacknxt; stacknleft = mark->stacknleft; + sstrend = mark->stacknxt + mark->stacknleft; INTON; } @@ -7974,61 +8314,69 @@ popstackmark(struct stackmark *mark) * 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; +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; - stackp = sp->prev; - sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen); - sp->prev = 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; - { - /* 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; - } + 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 { - p = stalloc(newlen); - memcpy(p, oldspace, oldlen); - stacknxt = p; /* free the space */ - stacknleft += newlen; /* we just allocated */ + 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(int len) +grabstackblock(size_t len) { - len = ALIGN(len); + len = SHELL_ALIGN(len); stacknxt += len; stacknleft -= len; } - - /* - * The following routines are somewhat easier to use that the above. + * 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 @@ -8045,542 +8393,172 @@ grabstackblock(int len) * is space for at least one character. */ - -static char * -growstackstr(void) { - int len = stackblocksize(); +void * +growstackstr(void) +{ + size_t 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 { +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(); - sstrnleft = stackblocksize() - len; - } while (sstrnleft < newlen); + } return stackblock() + len; } +char * +stnputs(const char *s, size_t n, char *p) +{ + p = makestrspace(n, p); + p = mempcpy(p, s, n); + return p; +} - -static void -ungrabstackstr(char *s, char *p) +char * +stputs(const char *s, char *p) { - stacknleft += stacknxt - s; - stacknxt = s; - sstrnleft = stacknleft - (p - s); + return stnputs(s, strlen(s), p); } + +/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */ + /* - * Miscelaneous builtins. + * 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; +} -#undef rflag -//#ifdef __GLIBC__ -static mode_t getmode(const void *, mode_t); -static void *setmode(const char *); -//#endif +/* + * Convert a string of digits to an integer, printing an error message on + * failure. + */ -#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 -typedef long rlim_t; -#endif +int +number(const char *s) +{ + if (! is_number(s)) + error(illnum, s); + return atoi(s); +} /* - * The read builtin. The -e option causes backslashes to escape the - * following character. - * - * This uses unbuffered input, which may be avoidable in some cases. + * Check for a valid number. This should be elsewhere. */ -static int -readcmd(argc, argv) - int argc; - char **argv; +int +is_number(const char *p) { - 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; + 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. + */ -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; - } +char * +single_quote(const char *s) { + char *p; - INTOFF; - mask = umask(0); - umask(mask); - INTON; + STARTSTACKSTR(p); - 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; + do { + char *q; + size_t len; - INTOFF; - if ((set = setmode(ap)) != 0) { - mask = getmode(set, ~mask & 0777); - ckfree(set); - } - INTON; - if (!set) - error("Illegal mode: %s", ap); + len = strchrnul(s, '\'') - s; - umask(~mask & 0777); - } - } - return 0; -} + q = p = makestrspace(len + 3, p); -/* - * 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. - */ + *q++ = '\''; + q = mempcpy(q, s, len); + *q++ = '\''; + s += len; -struct limits { - const char *name; - int cmd; - int factor; /* multiply by to get rlim_{cur,max} values */ - char option; -}; + STADJUST(q - p, p); -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' } -}; + len = strspn(s, "'"); + if (!len) + break; -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; + q = p = makestrspace(len + 3, p); - 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; - } + *q++ = '"'; + q = mempcpy(q, s, len); + *q++ = '"'; + s += len; - for (l = limits; l->name && l->option != what; l++) - ; - if (!l->name) - error("internal error (%c)", what); + STADJUST(q - p, p); + } while (*s); - set = *argptr ? 1 : 0; - if (set) { - char *p = *argptr; + USTPUTC(0, p); - if (all || argptr[1]) - error("too many arguments"); - if (strcmp(p, "unlimited") == 0) - val = RLIM_INFINITY; - else { - val = (rlim_t) 0; + return stackblock(); +} - 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; +/* + * Like strdup but works with the ash stack. + */ - printf("%-20s ", l->name); - if (val == RLIM_INFINITY) - printf("unlimited\n"); - else - { - val /= l->factor; - printf("%lld\n", (long long) val); - } - } - return 0; - } +char * +sstrdup(const char *p) +{ + size_t len = strlen(p) + 1; + return memcpy(stalloc(len), p, len); +} - 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) +calcsize(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); @@ -8595,6 +8573,14 @@ calcsize(const union node *n) 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); @@ -8621,10 +8607,10 @@ calcsize(const union node *n) calcsize(n->narg.next); break; case NTO: + case NCLOBBER: case NFROM: case NFROMTO: case NAPPEND: - case NTOOV: calcsize(n->nfile.fname); calcsize(n->nfile.next); break; @@ -8644,11 +8630,12 @@ calcsize(const union node *n) }; } + static void -sizenodelist(const struct nodelist *lp) +sizenodelist(struct nodelist *lp) { while (lp) { - funcblocksize += ALIGN(sizeof(struct nodelist)); + funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); calcsize(lp->n); lp = lp->next; } @@ -8656,7 +8643,7 @@ sizenodelist(const struct nodelist *lp) static union node * -copynode(const union node *n) +copynode(union node *n) { union node *new; @@ -8665,19 +8652,10 @@ copynode(const union node *n) 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); @@ -8689,6 +8667,14 @@ copynode(const union node *n) 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); @@ -8715,10 +8701,10 @@ copynode(const union node *n) new->narg.next = copynode(n->narg.next); break; case NTO: + case NCLOBBER: 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); @@ -8741,12 +8727,12 @@ copynode(const union node *n) break; }; new->type = n->type; - return new; + return new; } static struct nodelist * -copynodelist(const struct nodelist *lp) +copynodelist(struct nodelist *lp) { struct nodelist *start; struct nodelist **lpp; @@ -8754,7 +8740,8 @@ copynodelist(const struct nodelist *lp) lpp = &start; while (lp) { *lpp = funcblock; - funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist)); + funcblock = (char *) funcblock + + SHELL_ALIGN(sizeof(struct nodelist)); (*lpp)->n = copynode(lp->n); lp = lp->next; lpp = &(*lpp)->next; @@ -8765,98 +8752,127 @@ copynodelist(const struct nodelist *lp) static char * -nodesavestr(const char *s) +nodesavestr(char *s) { - const char *p = s; - char *q = funcstring; char *rtn = funcstring; - while ((*q++ = *p++) != '\0') - continue; - funcstring = q; + funcstring = stpcpy(funcstring, s) + 1; return rtn; } -#ifdef ASH_GETOPTS -static int getopts (char *, char *, char **, int *, int *); -#endif + +/* + * 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. */ -static void -procargs(argc, argv) - int argc; - char **argv; +void +procargs(int argc, char **argv) { int i; + const char *xminusc; + char **xargv; - argptr = argv; + xargv = argv; + arg0 = xargv[0]; if (argc > 0) - argptr++; + xargv++; for (i = 0; i < NOPTS; i++) - optent_val(i) = 2; + optlist[i] = 2; + argptr = xargv; options(1); - if (*argptr == NULL && minusc == NULL) + 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 (optent_val(i) == 2) - optent_val(i) = 0; - arg0 = argv[0]; - if (sflag == 0 && minusc == NULL) { - commandname = argv[0]; - arg0 = *argptr++; - setinputfile(arg0, 0); + 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; } - /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ - if (argptr && minusc && *argptr) - arg0 = *argptr++; - shellparam.p = argptr; + shellparam.p = xargv; +#ifdef BB_ASH_GETOPTS shellparam.optind = 1; shellparam.optoff = -1; +#endif /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ - while (*argptr) { + while (*xargv) { shellparam.nparam++; - argptr++; + xargv++; } optschanged(); } - -/* - * Process shell options. The global variable argptr contains a pointer - * to the argument list; we advance it past the options. - */ +void +optschanged(void) +{ +#ifdef DEBUG + opentrace(); +#endif + setinteractive(iflag); + setjobctl(mflag); +} static inline void -minus_o(const char *name, int val) +minus_o(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"); + out1fmt("%-16s%s\n", optnames(i), + optlist[i] ? "on" : "off"); } else { for (i = 0; i < NOPTS; i++) - if (equal(name, optent_name(optlist[i]))) { - setoption(optent_letter(optlist[i]), val); + 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) @@ -8890,21 +8906,15 @@ options(int cmdline) } 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 + 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); } @@ -8919,15 +8929,8 @@ 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; - } + if (optletters(i) == flag) { + optlist[i] = val; return; } error("Illegal option -%c", flag); @@ -8940,7 +8943,7 @@ setoption(int flag, int val) * Set the shell parameters. */ -static void +void setparam(char **argv) { char **newparam; @@ -8957,8 +8960,10 @@ setparam(char **argv) shellparam.malloc = 1; shellparam.nparam = nparam; shellparam.p = newparam; +#ifdef BB_ASH_GETOPTS shellparam.optind = 1; shellparam.optoff = -1; +#endif } @@ -8966,7 +8971,7 @@ setparam(char **argv) * Free the list of positional parameters. */ -static void +void freeparam(volatile struct shparam *param) { char **ap; @@ -8984,10 +8989,8 @@ freeparam(volatile struct shparam *param) * The shift builtin command. */ -static int -shiftcmd(argc, argv) - int argc; - char **argv; +int +shiftcmd(int argc, char **argv) { int n; char **ap1, **ap2; @@ -9005,8 +9008,10 @@ shiftcmd(argc, argv) } ap2 = shellparam.p; while ((*ap2++ = *ap1++) != NULL); +#ifdef BB_ASH_GETOPTS shellparam.optind = 1; shellparam.optoff = -1; +#endif INTON; return 0; } @@ -9017,13 +9022,11 @@ shiftcmd(argc, argv) * The set command builtin. */ -static int -setcmd(argc, argv) - int argc; - char **argv; +int +setcmd(int argc, char **argv) { if (argc == 1) - return showvarscmd(argc, argv); + return showvars(nullstr, 0, VUNSET); INTOFF; options(0); optschanged(); @@ -9035,118 +9038,55 @@ setcmd(argc, argv) } +#ifdef BB_ASH_GETOPTS static void -getoptsreset(const char *value) +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) + if (value != 0 && *value != 0) setlocale(LC_ALL, value); } static void change_lc_ctype(const char *value) { - if(value != 0 && *value != 0) + 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; -} - +#ifdef BB_ASH_GETOPTS static int -getopts(optstr, optvar, optfirst, myoptind, optoff) - char *optstr; - char *optvar; - char **optfirst; - int *myoptind; - int *optoff; +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[10]; - char **optnext = optfirst + *myoptind - 1; + char s[12]; + char **optnext; + + if(*param_optind < 1) + return 1; + optnext = optfirst + *param_optind - 1; - if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) || - strlen(*(optnext - 1)) < *optoff) + if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff) p = NULL; else - p = *(optnext - 1) + *optoff; + 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; @@ -9163,13 +9103,12 @@ getopts(optstr, optvar, optfirst, myoptind, optoff) s[0] = c; s[1] = '\0'; err |= setvarsafe("OPTARG", s, 0); - } - else { - out2fmt("Illegal option -%c\n", c); + } else { + fprintf(stderr, "Illegal option -%c\n", c); (void) unsetvar("OPTARG"); } c = '?'; - goto bad; + goto out; } if (*++q == ':') q++; @@ -9182,43 +9121,71 @@ getopts(optstr, optvar, optfirst, myoptind, optoff) s[1] = '\0'; err |= setvarsafe("OPTARG", s, 0); c = ':'; - } - else { - out2fmt("No arg for -%c option\n", c); + } else { + fprintf(stderr, "No arg for -%c option\n", c); (void) unsetvar("OPTARG"); c = '?'; } - goto bad; + goto out; } if (p == *optnext) optnext++; - setvarsafe("OPTARG", p, 0); + err |= setvarsafe("OPTARG", p, 0); p = NULL; - } - else - setvarsafe("OPTARG", "", 0); - *myoptind = optnext - optfirst + 1; - goto out; + } else + err |= setvarsafe("OPTARG", nullstr, 0); -bad: - *myoptind = 1; - p = NULL; out: *optoff = p ? p - *(optnext - 1) : -1; - snprintf(s, sizeof(s), "%d", *myoptind); + *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) { - *myoptind = 1; + *param_optind = 1; *optoff = -1; + flushall(); exraise(EXERROR); } return done; } -#endif + +/* + * 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 @@ -9263,53 +9230,92 @@ nextopt(const char *optstring) return c; } -static void -flushall() { + +/* $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 -out2fmt(const char *fmt, ...) +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); - vfprintf(stderr, fmt, ap); + INTOFF; + ret = vsnprintf(outbuf, length, fmt, ap); va_end(ap); + INTON; + return ret; } + /* * Version of write which resumes after a signal is caught. */ -static int -xwrite(int fd, const char *buf, int nbytes) +static void +xwrite(int fd, const void *p, size_t n) { - int ntry; - int i; - int n; + ssize_t i; - 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; - } - } + 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. */ @@ -9317,7 +9323,6 @@ xwrite(int fd, const char *buf, int nbytes) #define EOFMARKLEN 79 - struct heredoc { struct heredoc *next; /* next here document in list */ union node *here; /* redirection node */ @@ -9325,36 +9330,43 @@ struct heredoc { 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 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 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); +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 == '='; +} /* @@ -9362,7 +9374,7 @@ static void setprompt (int); * valid parse tree indicating a blank line.) */ -static union node * +union node * parsecmd(int interact) { int t; @@ -9370,9 +9382,7 @@ parsecmd(int interact) tokpushback = 0; doprompt = interact; if (doprompt) - setprompt(1); - else - setprompt(0); + setprompt(doprompt); needprompt = 0; t = readtoken(); if (t == TEOF) @@ -9385,30 +9395,29 @@ parsecmd(int interact) static union node * -list(nlflag) - int nlflag; +list(int nlflag) { union node *n1, *n2, *n3; int tok; - checkkwd = 2; - if (nlflag == 0 && tokendlist[peektoken()]) + checkkwd = CHKNL | CHKKWD | CHKALIAS; + if (nlflag == 2 && 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; + if (n2->type == NPIPE) { + n2->npipe.backgnd = 1; } else { - n3 = (union node *)stalloc(sizeof (struct nredir)); - n3->type = NBACKGND; - n3->nredir.n = n2; - n3->nredir.redirect = NULL; - n2 = n3; + 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) { @@ -9429,13 +9438,13 @@ list(nlflag) case TNL: if (tok == TNL) { parseheredoc(); - if (nlflag) + if (nlflag == 1) return n1; } else { tokpushback++; } - checkkwd = 2; - if (tokendlist[peektoken()]) + checkkwd = CHKNL | CHKKWD | CHKALIAS; + if (peektoken()) return n1; break; case TEOF: @@ -9445,7 +9454,7 @@ list(nlflag) pungetc(); /* push back EOF on input */ return n1; default: - if (nlflag) + if (nlflag == 1) synexpect(-1); tokpushback++; return n1; @@ -9456,11 +9465,11 @@ list(nlflag) static union node * -andor() { +andor(void) +{ union node *n1, *n2, *n3; int t; - checkkwd = 1; n1 = pipeline(); for (;;) { if ((t = readtoken()) == TAND) { @@ -9471,7 +9480,7 @@ andor() { tokpushback++; return n1; } - checkkwd = 2; + checkkwd = CHKNL | CHKKWD | CHKALIAS; n2 = pipeline(); n3 = (union node *)stalloc(sizeof (struct nbinary)); n3->type = t; @@ -9484,7 +9493,8 @@ andor() { static union node * -pipeline() { +pipeline(void) +{ union node *n1, *n2, *pipenode; struct nodelist *lp, *prev; int negate; @@ -9493,7 +9503,7 @@ pipeline() { TRACE(("pipeline: entered\n")); if (readtoken() == TNOT) { negate = !negate; - checkkwd = 1; + checkkwd = CHKKWD | CHKALIAS; } else tokpushback++; n1 = command(); @@ -9507,7 +9517,7 @@ pipeline() { do { prev = lp; lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - checkkwd = 2; + checkkwd = CHKNL | CHKKWD | CHKALIAS; lp->n = command(); prev->next = lp; } while (readtoken() == TPIPE); @@ -9527,26 +9537,22 @@ pipeline() { static union node * -command() { +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; - n1 = NULL; - rpp = &redir; - - /* Check for redirection which may precede command */ - while (readtoken() == TREDIR) { - *rpp = n2 = redirnode; - rpp = &n2->nfile.next; - parsefname(); - } - tokpushback++; + rpp2 = &redir; switch (readtoken()) { + default: + synexpect(-1); + /* NOTREACHED */ case TIF: n1 = (union node *)stalloc(sizeof (struct nif)); n1->type = NIF; @@ -9570,9 +9576,7 @@ command() { n2->nif.elsepart = NULL; tokpushback++; } - if (readtoken() != TFI) - synexpect(TFI); - checkkwd = 1; + t = TFI; break; case TWHILE: case TUNTIL: { @@ -9581,13 +9585,11 @@ command() { 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 : "")); +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; + t = TDONE; break; } case TFOR: @@ -9596,7 +9598,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); n1 = (union node *)stalloc(sizeof (struct nfor)); n1->type = NFOR; n1->nfor.var = wordtext; - checkkwd = 1; + checkkwd = CHKKWD | CHKALIAS; if (readtoken() == TIN) { app = ≈ while (readtoken() == TWORD) { @@ -9612,11 +9614,9 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 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.text = (char *)dolatstr; n2->narg.backquote = NULL; n2->narg.next = NULL; n1->nfor.args = n2; @@ -9627,13 +9627,11 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); if (lasttoken != TNL && lasttoken != TSEMI) tokpushback++; } - checkkwd = 2; + checkkwd = CHKNL | CHKKWD | CHKALIAS; if (readtoken() != TDO) synexpect(TDO); n1->nfor.body = list(0); - if (readtoken() != TDONE) - synexpect(TDONE); - checkkwd = 1; + t = TDONE; break; case TCASE: n1 = (union node *)stalloc(sizeof (struct ncase)); @@ -9646,13 +9644,15 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); n2->narg.backquote = backquotelist; n2->narg.next = NULL; do { - checkkwd = 1; + checkkwd = CHKKWD | CHKALIAS; } while (readtoken() == TNL); if (lasttoken != TIN) - synerror("expecting \"in\""); + synexpect(TIN); cpp = &n1->ncase.cases; - checkkwd = 2, readtoken(); - do { +next_case: + checkkwd = CHKNL | CHKKWD; + t = readtoken(); + while(t != TESAC) { if (lasttoken == TLP) readtoken(); *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); @@ -9663,7 +9663,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); ap->type = NARG; ap->narg.text = wordtext; ap->narg.backquote = backquotelist; - if (checkkwd = 2, readtoken() != TPIPE) + if (readtoken() != TPIPE) break; app = &ap->narg.next; readtoken(); @@ -9671,59 +9671,44 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); ap->narg.next = NULL; if (lasttoken != TRP) synexpect(TRP); - cp->nclist.body = list(0); + cp->nclist.body = list(2); + + cpp = &cp->nclist.next; - checkkwd = 2; + checkkwd = CHKNL | CHKKWD; if ((t = readtoken()) != TESAC) { if (t != TENDCASE) synexpect(TENDCASE); else - checkkwd = 2, readtoken(); + goto next_case; } - cpp = &cp->nclist.next; - } while(lasttoken != TESAC); + } *cpp = NULL; - checkkwd = 1; - break; + goto redir; 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; + t = TRP; break; case TBEGIN: n1 = list(0); - if (readtoken() != TEND) - synexpect(TEND); - checkkwd = 1; + t = TEND; 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: + case TREDIR: tokpushback++; - n1 = simplecmd(); - return n1; - default: - synexpect(-1); - /* NOTREACHED */ + 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; @@ -9746,11 +9731,12 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); static union node * -simplecmd() { +simplecmd(void) { union node *args, **app; union node *n = NULL; union node *vars, **vpp; union node **rpp, *redir; + int savecheckkwd; args = NULL; app = &args; @@ -9759,21 +9745,22 @@ simplecmd() { redir = NULL; rpp = &redir; - checkalias = 2; + savecheckkwd = CHKALIAS; for (;;) { + checkkwd = savecheckkwd; 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 { + if (savecheckkwd && isassignment(wordtext)) { *vpp = n; vpp = &n->narg.next; + } else { + *app = n; + app = &n->narg.next; + savecheckkwd = 0; } break; case TREDIR: @@ -9786,11 +9773,22 @@ simplecmd() { 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 = 2; + checkkwd = CHKNL | CHKKWD | CHKALIAS; n->narg.next = command(); return n; } @@ -9806,7 +9804,6 @@ simplecmd() { *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; @@ -9814,7 +9811,8 @@ simplecmd() { } static union node * -makename(void) { +makename(void) +{ union node *n; n = (union node *)stalloc(sizeof (struct narg)); @@ -9825,7 +9823,7 @@ makename(void) { return n; } -static void fixredir(union node *n, const char *text, int err) +void fixredir(union node *n, const char *text, int err) { TRACE(("Fix redir %s %d\n", text, err)); if (!err) @@ -9846,7 +9844,8 @@ static void fixredir(union node *n, const char *text, int err) static void -parsefname(void) { +parsefname(void) +{ union node *n = redirnode; if (readtoken() != TWORD) @@ -9859,10 +9858,6 @@ parsefname(void) { 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); @@ -9887,13 +9882,15 @@ parsefname(void) { */ static void -parseheredoc() { +parseheredoc(void) +{ struct heredoc *here; union node *n; - while (heredoclist) { - here = heredoclist; - heredoclist = here->next; + here = heredoclist; + heredoclist = 0; + + while (here) { if (needprompt) { setprompt(2); needprompt = 0; @@ -9906,94 +9903,78 @@ parseheredoc() { n->narg.text = wordtext; n->narg.backquote = backquotelist; here->here->nhere.doc = n; + here = here->next; } } -static int -peektoken() { +static char peektoken(void) +{ int t; t = readtoken(); tokpushback++; - return (t); + return tokname_array[t][0]; } static int -readtoken() { +readtoken(void) +{ int t; - -#ifdef ASH_ALIAS - int savecheckalias = checkalias; - int savecheckkwd = checkkwd; - struct alias *ap; -#endif - #ifdef DEBUG int alreadyseen = tokpushback; #endif -#ifdef ASH_ALIAS +#ifdef BB_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(); - } + /* + * eat newlines + */ + if (checkkwd & CHKNL) { + 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 || quoteflag) { + goto out; } + /* + * check for keywords + */ + if (checkkwd & CHKKWD) { + const char *const *pp; - if (t != TWORD) { - if (t != TREDIR) { - checkalias = 0; + if ((pp = findkwd(wordtext))) { + lasttoken = t = pp - tokname_array; + TRACE(("keyword %s recognized\n", tokname(t))); + goto out; } - } else if (checkalias == 2 && isassignment(wordtext)) { - lasttoken = t = TASSIGN; -#ifdef ASH_ALIAS - } else if (checkalias) { - if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) { + } + + if (checkkwd & CHKALIAS) { +#ifdef BB_ASH_ALIAS + struct alias *ap; + if ((ap = lookupalias(wordtext, 1)) != NULL) { if (*ap->val) { - pushstring(ap->val, strlen(ap->val), ap); + pushstring(ap->val, ap); } - checkkwd = savecheckkwd; goto top; } - checkalias = 0; #endif } out: + checkkwd = 0; #ifdef DEBUG if (!alreadyseen) - TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : "")); + TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); else - TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : "")); + TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); #endif return (t); } @@ -10017,10 +9998,94 @@ readtoken() { * 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() { +xxreadtoken(void) +{ int c; if (tokpushback) { @@ -10036,7 +10101,7 @@ xxreadtoken() { c = pgetc_macro(); switch (c) { case ' ': case '\t': -#ifdef ASH_ALIAS +#ifdef BB_ASH_ALIAS case PEOA: #endif continue; @@ -10049,8 +10114,6 @@ xxreadtoken() { startlinno = ++plinno; if (doprompt) setprompt(2); - else - setprompt(0); continue; } pungetc(); @@ -10088,7 +10151,7 @@ xxreadtoken() { return readtoken1(c, BASESYNTAX, (char *)NULL, 0); #undef RETURN } - +#endif /* NEW_xxreadtoken */ /* @@ -10111,12 +10174,8 @@ xxreadtoken() { #define PARSEARITH() {goto parsearith; parsearith_return:;} static int -readtoken1(firstc, syntax, eofmark, striptabs) - int firstc; - char const *syntax; - char *eofmark; - int striptabs; - { +readtoken1(int firstc, int syntax, char *eofmark, int striptabs) +{ int c = firstc; char *out; int len; @@ -10129,7 +10188,7 @@ readtoken1(firstc, syntax, eofmark, striptabs) int parenlevel; /* levels of parens in arithmetic */ int dqvarnest; /* levels of variables expansion within double quotes */ int oldstyle; - char const *prevsyntax; /* syntax before arithmetic */ + int prevsyntax; /* syntax before arithmetic */ #if __GNUC__ /* Avoid longjmp clobbering */ (void) &out; @@ -10159,8 +10218,8 @@ readtoken1(firstc, syntax, eofmark, striptabs) 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]) { + CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ + switch(SIT(c, syntax)) { case CNL: /* '\n' */ if (syntax == BASESYNTAX) goto endword; /* exit outer loop */ @@ -10168,66 +10227,65 @@ readtoken1(firstc, syntax, eofmark, striptabs) 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) + 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 - setprompt(0); } else { - if (dblquote && c != '\\' && c != '`' && c != '$' - && (c != '"' || eofmark != NULL)) + if ( + dblquote && + c != '\\' && c != '`' && + c != '$' && ( + c != '"' || + eofmark != NULL + ) + ) { + USTPUTC(CTLESC, out); USTPUTC('\\', out); - if (SQSYNTAX[c] == CCTL) + } + if (SIT(c, SQSYNTAX) == 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; +quotemark: + if (eofmark == NULL) { + USTPUTC(CTLQUOTEMARK, out); + } break; case CDQUOTE: - if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); syntax = DQSYNTAX; dblquote = 1; - break; + goto quotemark; 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) { + if (dqvarnest == 0) { syntax = BASESYNTAX; dblquote = 0; } quotef++; + goto quotemark; } break; case CVAR: /* '$' */ @@ -10244,7 +10302,7 @@ readtoken1(firstc, syntax, eofmark, striptabs) USTPUTC(c, out); } break; -#ifdef ASH_MATH_SUPPORT +#ifdef BB_ASH_MATH_SUPPORT case CLP: /* '(' in arithmetic */ parenlevel++; USTPUTC(c, out); @@ -10285,7 +10343,7 @@ readtoken1(firstc, syntax, eofmark, striptabs) default: if (varnest == 0) goto endword; /* exit outer loop */ -#ifdef ASH_ALIAS +#ifdef BB_ASH_ALIAS if (c != PEOA) #endif USTPUTC(c, out); @@ -10295,16 +10353,19 @@ readtoken1(firstc, syntax, eofmark, striptabs) } } 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 - stackblock(); + len = out - (char *)stackblock(); out = stackblock(); if (eofmark == NULL) { if ((c == '>' || c == '<') @@ -10334,7 +10395,7 @@ readtoken1(firstc, syntax, eofmark, striptabs) checkend: { if (eofmark) { -#ifdef ASH_ALIAS +#ifdef BB_ASH_ALIAS if (c == PEOA) { c = pgetc2(); } @@ -10355,7 +10416,7 @@ checkend: { plinno++; needprompt = doprompt; } else { - pushstring(line, strlen(line), NULL); + pushstring(line, NULL); } } } @@ -10380,10 +10441,10 @@ parseredir: { c = pgetc(); if (c == '>') np->type = NAPPEND; + else if (c == '|') + np->type = NCLOBBER; else if (c == '&') np->type = NTOFD; - else if (c == '|') - np->type = NTOOV; else { np->type = NTO; pungetc(); @@ -10442,21 +10503,25 @@ parsesub: { c = pgetc(); if ( - c <= PEOA || + 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 - stackblock(); + typeloc = out - (char *)stackblock(); USTPUTC(VSNORMAL, out); subtype = VSNORMAL; if (c == '{') { @@ -10470,14 +10535,14 @@ parsesub: { else subtype = 0; } - if (c > PEOA && is_name(c)) { + if (c > PEOA_OR_PEOF && is_name(c)) { do { STPUTC(c, out); c = pgetc(); - } while (c > PEOA && is_in_name(c)); + } while (c > PEOA_OR_PEOF && is_in_name(c)); } else if (is_digit(c)) { do { - USTPUTC(c, out); + STPUTC(c, out); c = pgetc(); } while (is_digit(c)); } @@ -10517,2340 +10582,2915 @@ badsub: synerror("Bad substitution"); } } } else { - pungetc(); - } - if (dblquote || arinest) - flags |= VSQUOTE; - *(stackblock() + typeloc) = subtype | flags; - if (subtype != VSNORMAL) { - varnest++; - if (dblquote) { - dqvarnest++; - } + 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); } - } - goto parsesub_return; + dupredirect(n, newfd); + } while ((n = n->nfile.next)); + INTON; + if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0) + preverrout_fd = sv->renamed[2]; } /* - * 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. + * Undo the effects of the last redirection. */ -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 +void +popredir(int drop) +{ + struct redirtab *rp; + int i; - savepbq = parsebackquote; - if (setjmp(jmploc.loc)) { - if (str) - ckfree(str); - parsebackquote = 0; - handler = savehandler; - longjmp(handler->loc, 1); - } + if (--nullredirs >= 0) + return; INTOFF; - str = NULL; - savelen = out - stackblock(); - if (savelen > 0) { - str = ckmalloc(savelen); - memcpy(str, stackblock(), savelen); + 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]); + } } - savehandler = handler; - handler = &jmploc; + redirlist = rp->next; + nullredirs = rp->nullredirs; + ckfree(rp); 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; +} +/* + * Undo all redirections. Called on error or interrupt. + */ - STARTSTACKSTR(pout); - for (;;) { - if (needprompt) { - setprompt(2); - needprompt = 0; - } - switch (pc = pgetc()) { - case '`': - goto done; +/* + * Discard all saved file descriptors. + */ - 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 */ +void +clearredir(int drop) +{ + for (;;) { + nullredirs = 0; + if (!redirlist) + break; + popredir(drop); + } +} - case PEOF: -#ifdef ASH_ALIAS - case PEOA: -#endif - startlinno = plinno; - synerror("EOF in backquote substitution"); - case '\n': - plinno++; - needprompt = doprompt; - break; +/* + * 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. + */ - 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; +int +ash_copyfd(int from, int to) +{ + int newfd; - if (oldstyle) { - saveprompt = doprompt; - doprompt = 0; + newfd = fcntl(from, F_DUPFD, to); + if (newfd < 0) { + if (errno == EMFILE) + return EMPTY; + else + error("%d: %m", from); } + return newfd; +} - n = list(0); - if (oldstyle) - doprompt = saveprompt; - else { - if (readtoken() != TRP) - synexpect(TRP); - } +int +redirectsafe(union node *redir, int flags) +{ + int err; + volatile int saveint; + struct jmploc *volatile savehandler = handler; + struct jmploc jmploc; - (*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; + SAVEINT(saveint); + if (!(err = setjmp(jmploc.loc) * 2)) { + handler = &jmploc; + redirect(redir, flags); } - parsebackquote = savepbq; handler = savehandler; - if (arinest || dblquote) - USTPUTC(CTLBACKQ | CTLQUOTE, out); - else - USTPUTC(CTLBACKQ, out); - if (oldstyle) - goto parsebackq_oldreturn; - else - goto parsebackq_newreturn; + 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, "", n->type); + if (ind >= 0) + putc('\n', fp); + break; + } } -/* - * 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); +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; } - 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; - { +static void +sharg(union node *arg, FILE *fp) +{ char *p; - char c; + struct nodelist *bqlist; + int subtype; - p = text; - while ((c = *p++) != '\0') { - if (c == CTLQUOTEMARK) - continue; - if (c == CTLESC) - p++; - else if (BASESYNTAX[(int)c] == CCTL) - return 0; + if (arg->type != NARG) { + out1fmt("\n", arg->type); + abort(); } - return 1; -} - + 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); -/* - * Return true if the argument is a legal variable name (a letter or - * underscore followed by zero or more letters, underscores, and digits). - */ + while (*p != '=') + putc(*p++, fp); -static int -goodname(const char *name) -{ - const char *p; + if (subtype & VSNUL) + putc(':', fp); - p = name; - if (! is_name(*p)) - return 0; - while (*++p) { - if (! is_in_name(*p)) - return 0; + 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); + } + 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; + } } - 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; +indent(int amount, char *pfx, FILE *fp) { - char msg[64]; + int i; - if (token >= 0) { - snprintf(msg, 64, "%s unexpected (expecting %s)", - tokname[lasttoken], tokname[token]); - } else { - snprintf(msg, 64, "%s unexpected", tokname[lasttoken]); + for (i = 0 ; i < amount ; i++) { + if (pfx && i == amount - 1) + fputs(pfx, fp); + putc('\t', fp); } - 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. + * Debugging stuff. */ -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 +FILE *tracefile; -/* - * Open a file in noclobber mode. - * The code was copied from bash. - */ -static inline int -noclobberopen(const char *fname) +void +trputc(int c) { - 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 (debug != 1) + return; + putc(c, tracefile); +} - /* If the open failed, return the file descriptor right away. */ - if (fd < 0) - return fd; +void +trace(const char *fmt, ...) +{ + va_list va; - /* - * 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 (debug != 1) + return; + va_start(va, fmt); + (void) vfprintf(tracefile, fmt, va); + va_end(va); +} - /* - * 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; +void +tracev(const char *fmt, va_list va) +{ + if (debug != 1) + return; + (void) vfprintf(tracefile, fmt, va); +} - /* The file has been replaced. badness. */ - close(fd); - errno = EEXIST; - return -1; + +void +trputs(const char *s) +{ + if (debug != 1) + return; + fputs(s, tracefile); } -/* - * 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) +static void +trstring(char *s) { - int pip[2]; - int len = 0; + char *p; + char c; - 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 (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; } } - 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); + putc('"', tracefile); +} + + +void +trargs(char **ap) +{ + if (debug != 1) + return; + while (*ap) { + trstring(*ap++); + if (*ap) + putc(' ', tracefile); else - expandhere(redir->nhere.doc, pip[1]); - _exit(0); + putc('\n', tracefile); } -out: - close(pip[1]); - return pip[0]; } -static inline int -openredirect(const union node *redir) +void +opentrace(void) { - char *fname; - int f; + char s[100]; +#ifdef O_APPEND + int flags; +#endif - 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; + 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; } - 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; + } else { + if ((tracefile = fopen(s, "a")) == NULL) { + fprintf(stderr, "Can't open %s\n", s); + debug = 0; + return; + } + } #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(); + if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) + fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); #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)); + setlinebuf(tracefile); + fputs("\nTracing started.\n", tracefile); } +#endif /* DEBUG */ + +/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */ /* - * 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. + * 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, */ -static void -redirect(union node *redir, int flags) +#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) { - 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 */ + char *action; + char **ap; + int signo; - 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 */ + nextopt(nullstr); + ap = argptr; + if (!*ap) { + for (signo = 0 ; signo < NSIG ; signo++) { + if (trap[signo] != NULL) { + const char *sn; - 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; - } + sn = u_signal_names(0, &signo, 0); + if (sn == NULL) + sn = "???"; + out1fmt("trap -- %s %s\n", + single_quote(trap[signo]), sn); } - } else if (fd != newfd) { - close(fd); } - if (fd == 0) - fd0_redirected++; - if (!try) - dupredirect(n, newfd, fd1dup); + 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; } -static void -dupredirect(const union node *redir, int f, int fd1dup) -{ - int fd = redir->nfile.fd; +/* + * Clear traps on a fork. + */ - 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; - } +void +clear_traps(void) +{ + char **tp; - if (f != fd) { - dup_as_newfd(f, fd); - close(f); + 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; + } } - return; } - /* - * Undo the effects of the last redirection. + * Set the signal handler for the specified signal. The routine figures + * out what it should be set to. */ -static void -popredir(void) +void +setsignal(int signo) { - struct redirtab *rp = redirlist; - int i; + int action; + char *t, tsig; + struct sigaction act; - 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]); - } + 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 } } - redirlist = rp->next; - ckfree(rp); - INTON; + + 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); } /* - * Discard all saved file descriptors. + * Ignore a signal. */ -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; - } +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; } /* - * 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. + * Signal handler. */ -static int -dup_as_newfd(from, to) - int from; - int to; +void +onsig(int signo) { - int newfd; + gotsig[signo - 1] = 1; + pendingsigs = signo; - newfd = fcntl(from, F_DUPFD, to); - if (newfd < 0) { - if (errno == EMFILE) - return EMPTY; - else - error("%d: %m", from); + if (exsig || (signo == SIGINT && !trap[SIGINT])) { + if (!suppressint) + onint(); + intpending = 1; } - 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). + * Called to execute a trap. Perhaps we should avoid entering new trap + * handlers while we are executing a trap handler. */ -static mode_t -getmode(bbox, omode) - const void *bbox; - mode_t omode; -{ - const BITCMD *set; - mode_t clrval, newmode, value; - _DIAGASSERT(bbox != NULL); +void +dotrap(void) +{ + char *p; + char *q; + int savestatus; - 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; + 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; + } +} - case '+': - newmode |= set->bits; - break; - case '-': - newmode &= ~set->bits; - break; +/* + * Controls whether the shell is interactive or not. + */ - case 'X': - if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) - newmode |= set->bits; - break; +void +setinteractive(int on) +{ + static int is_interactive; - case '\0': - default: -#ifdef SETMODE_DEBUG - (void)printf("getmode:%04o -> %04o\n", omode, newmode); -#endif - return (newmode); + 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 } -#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) +#ifndef BB_FEATURE_SH_EXTRA_QUIET +/*** List the available builtins ***/ -static void * -setmode(p) - const char *p; +static int helpcmd(int argc, char **argv) { - 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); + int col, i; - /* - * 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); + 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; } - ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); - set->cmd = 0; - return (saveset); } +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + { + extern const struct BB_applet applets[]; + extern const size_t NUM_APPLETS; - /* - * 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; + 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 */ -getop: if ((op = *p++) != '+' && op != '-' && op != '=') { - free(saveset); - return (NULL); - } - if (op == '=') - equalopdone = 0; +/* + * Called to exit the shell. + */ - 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; +void +exitshell(void) +{ + struct jmploc loc; + char *p; + int status; - 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; - } - } + 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"); -apply: if (!*p) - break; - if (*p != ',') - goto getop; - ++p; + if(hp != NULL ) + save_history ( hp ); } - 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); +out: + _exit(status); + /* NOTREACHED */ } -static BITCMD * -addcmd(set, op, who, oparg, mask) - BITCMD *set; - int oparg, who; - int op; - u_int mask; +static int decode_signal(const char *string, int minsig) { + int signo; + const char *name = u_signal_names(string, &signo, minsig); - _DIAGASSERT(set != NULL); + return name ? signo : -1; +} - switch (op) { - case '=': - set->cmd = '-'; - set->bits = who ? who : STANDARD_BITS; - set++; +/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */ - op = '+'; - /* FALLTHROUGH */ - case '+': - case '-': - case 'X': - set->cmd = op; - set->bits = (who ? who : mask) & oparg; - break; +static struct var *vartab[VTABSIZE]; - 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; - } +static int vpcmp(const void *, const void *); +static struct var **findvar(struct var **, const char *); - 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); -} +/* + * Initialize the varable symbol tables and import the environment + */ -#ifdef SETMODE_DEBUG -static void -dumpmode(set) - BITCMD *set; -{ - _DIAGASSERT(set != NULL); +#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; - 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" : ""); + SAVEINT(saveint); + if (setjmp(jmploc.loc)) + err = 1; + else { + handler = &jmploc; + setvar(name, val, flags); + err = 0; + } + handler = savehandler; + RESTOREINT(saveint); + return err; } #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. + * 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 -compress_mode(set) - BITCMD *set; +setvar(const char *name, const char *val, int flags) { - 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; - } + char *p, *q; + size_t namelen; + char *nameeq; + size_t vallen; - 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++; - } + 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; } -#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; +/* + * 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) { - trputs("showtree called\n"); - shtree(n, 1, NULL, stdout); -} + 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); + } -static void -shtree(n, ind, pfx, fp) - union node *n; - int ind; - char *pfx; - FILE *fp; -{ - struct nodelist *lp; - const char *s; + if (flags & VNOSET) + return; - if (n == NULL) - return; + if (vp->func && (flags & VNOFUNC) == 0) + (*vp->func)(strchrnul(s, '=') + 1); - 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, "", n->type); - if (ind >= 0) - putc('\n', fp); - break; + 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 -shcmd(cmd, fp) - union node *cmd; - FILE *fp; +listsetvar(struct strlist *list_set_var, int flags) { - union node *np; - int first; - const char *s; - int dftfd; + struct strlist *lp = list_set_var; - 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; - } + 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 void -sharg(arg, fp) - union node *arg; - FILE *fp; - { - char *p; - struct nodelist *bqlist; - int subtype; +static char * +lookupvar(const char *name) +{ + struct var *v; - if (arg->type != NARG) { - printf("\n", arg->type); - fflush(stdout); - abort(); + if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { + return strchrnul(v->text, '=') + 1; } - 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); + return NULL; +} - while (*p != '=') - putc(*p++, fp); - if (subtype & VSNUL) - putc(':', fp); +/* + * Search the environment of a builtin command. + */ - 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); - } - 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 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); } -static void -indent(amount, pfx, fp) - int amount; - char *pfx; - FILE *fp; -{ - int i; +/* + * Generate a list of variables satisfying the given conditions. + */ - for (i = 0 ; i < amount ; i++) { - if (pfx && i == amount - 1) - fputs(pfx, fp); - putc('\t', fp); - } -} -#endif +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); +} /* - * Debugging stuff. + * 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; -#ifdef DEBUG -FILE *tracefile; + ep = listvars(on, off, &epend); + qsort(ep, epend - ep, sizeof(char *), vpcmp); -#if DEBUG == 2 -static int debug = 1; -#else -static int debug = 0; -#endif + sep = *sep_prefix ? spcstr : sep_prefix; + for (; ep < epend; ep++) { + const char *p; + const char *q; -static void -trputc(c) - int c; -{ - if (tracefile == NULL) - return; - putc(c, tracefile); - if (c == '\n') - fflush(tracefile); -} + p = strchrnul(*ep, '='); + q = nullstr; + if (*p) + q = single_quote(++p); -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); + out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q); } - va_end(va); + + return 0; } -static void -trputs(s) - const char *s; -{ - if (tracefile == NULL) - return; - fputs(s, tracefile); - if (strchr(s, '\n')) - fflush(tracefile); -} +/* + * The export and readonly commands. + */ -static void -trstring(s) - char *s; +static int +exportcmd(int argc, char **argv) { - char *p; - char c; + struct var *vp; + char *name; + const char *p; + char **aptr; + int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; + int notp; - 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); + 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; + } } - break; - } + setvar(name, p, flag); + } while ((name = *++aptr) != NULL); + } else { + showvars(argv[0], flag, 0); } - putc('"', tracefile); + return 0; } -static void -trargs(ap) - char **ap; -{ - if (tracefile == NULL) - return; - while (*ap) { - trstring(*ap++); - if (*ap) - putc(' ', tracefile); - else - putc('\n', tracefile); - } - fflush(tracefile); -} - +/* + * 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 -opentrace() { - char s[100]; -#ifdef O_APPEND - int flags; -#endif +static inline void +mklocal(char *name) +{ + struct localvar *lvp; + struct var **vpp; + struct var *vp; - if (!debug) - return; -#ifdef not_this_way - { + INTOFF; + lvp = ckmalloc(sizeof (struct localvar)); + if (name[0] == '-' && name[1] == '\0') { char *p; - if ((p = getenv("HOME")) == NULL) { - if (geteuid() == 0) - 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 - p = "/tmp"; + 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); } - 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); + lvp->vp = vp; + lvp->next = localvars; + localvars = lvp; + INTON; } -#endif /* DEBUG */ - /* - * The trap builtin. + * The "local" command. */ static int -trapcmd(argc, argv) - int argc; - char **argv; +localcmd(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; + char *name; - 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++; + argv = argptr; + while ((name = *argv++) != NULL) { + mklocal(name); } return 0; } - - - - /* - * Set the signal handler for the specified signal. The routine figures - * out what it should be set to. + * Called after a function returns. + * Interrupts must be off. */ static void -setsignal(int signo) +poplocalvars(void) { - 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 - } - } + struct localvar *lvp; + struct var *vp; - 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; + 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 { - *t = S_RESET; /* force to be set */ + 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); } - 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. + * 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 void -ignoresig(signo) - int signo; +int +unsetcmd(int argc, char **argv) { - if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { - signal(signo, SIG_IGN); + char **ap; + int i; + int flag = 0; + int ret = 0; + + while ((i = nextopt("vf")) != '\0') { + flag = i; } - sigmode[signo - 1] = S_HARD_IGN; + + 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; } /* - * Signal handler. + * Unset the specified variable. */ -static void -onsig(int signo) +int +unsetvar(const char *s) { - if (signo == SIGINT && trap[SIGINT] == NULL) { - onint(); - return; + 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; } - gotsig[signo - 1] = 1; - pendingsigs++; + +out: + return retval; } + /* - * Called to execute a trap. Perhaps we should avoid entering new trap - * handlers while we are executing a trap handler. + * Find the appropriate entry in the hash table from the name. */ -static void -dotrap(void) +static struct var ** +hashvar(const char *p) { - int i; - int savestatus; + unsigned int hashval; - 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; + hashval = ((unsigned char) *p) << 4; + while (*p && *p != '=') + hashval += (unsigned char) *p++; + return &vartab[hashval % VTABSIZE]; } + + /* - * Called to exit the shell. + * 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'. */ -static void -exitshell(int status) +int +varcmp(const char *p, const char *q) { - struct jmploc loc1, loc2; - char *p; + int c, d; - TRACE(("exitshell(%d) pid=%d\n", status, getpid())); - if (setjmp(loc1.loc)) { - goto l1; + while ((c = *p) == (d = *q)) { + if (!c || c == '=') + goto out; + p++; + q++; } - if (setjmp(loc2.loc)) { - goto l2; + 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; + } } - handler = &loc1; - if ((p = trap[0]) != NULL && *p != '\0') { - trap[0] = NULL; - evalstring(p, 0); + return vpp; +} +/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */ + +#include + +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); } -l1: handler = &loc2; /* probably unnecessary */ - flushall(); -#ifdef JOBS - setjobctl(0); -#endif -l2: _exit(status); - /* NOTREACHED */ + INTON; + + return (result); } -static int decode_signal(const char *string, int minsig) + +/* + * 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 + */ + +static int +letcmd(int argc, char **argv) { - int signo; - const char *name = u_signal_names(string, &signo, minsig); + char **ap; + long i; - return name ? signo : -1; + 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 */ -static struct var **hashvar (const char *); -static void showvars (const char *, int, int); -static struct var **findvar (struct var **, const char *); +/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */ /* - * Initialize the varable symbol tables and import the environment + * Miscelaneous builtins. */ +#undef rflag + +#ifdef __GLIBC__ +#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 +typedef enum __rlimit_resource rlim_t; +#endif +#endif + + /* - * This routine initializes the builtin variables. It is called when the - * shell is initialized and again when a shell procedure is spawned. + * 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 void -initvar() { - const struct varinit *ip; - struct var *vp; - struct var **vpp; +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; - 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; - } + rflag = 0; + prompt = NULL; + while ((i = nextopt("p:r")) != '\0') { + if (i == 'p') + prompt = optionarg; + else + rflag = 1; } - /* - * 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; + 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; } -/* - * 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; +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; - 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++ = 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); } - 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'; + 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); + } } - setvareq(nameeq, flags); - INTON; + return 0; } - - /* - * 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. + * 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. */ -static void -setvareq(s, flags) - char *s; - int flags; +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) { - struct var *vp, **vpp; + 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; - 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); + 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; } - INTOFF; - if (vp->func && (flags & VNOFUNC) == 0) - (*vp->func)(strchr(s, '=') + 1); + for (l = limits; l->name && l->option != what; l++) + ; + if (!l->name) + error("internal error (%c)", what); - if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) - ckfree(vp->text); + set = *argptr ? 1 : 0; + if (set) { + char *p = *argptr; - vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); - vp->flags |= flags; - vp->text = s; + if (all || argptr[1]) + error("too many arguments"); + if (strncmp(p, "unlimited\n", 9) == 0) + val = RLIM_INFINITY; + else { + val = (rlim_t) 0; - /* - * 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; + 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; + } } - /* not found */ - vp = ckmalloc(sizeof (*vp)); - vp->flags = flags; - vp->text = s; - vp->next = *vpp; - vp->func = NULL; - *vpp = vp; -} - - + 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; -/* - * Process a linked list of variable assignments. - */ + out1fmt("%-20s ", l->name); + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else + { + val /= l->factor; + out1fmt("%lld\n", (long long) val); + } + } + return 0; + } -static void -listsetvar(mylist) - struct strlist *mylist; - { - struct strlist *lp; + 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; - INTOFF; - for (lp = mylist ; lp ; lp = lp->next) { - setvareq(savestr(lp->text), 0); + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else + { + val /= l->factor; + out1fmt("%lld\n", (long long) val); + } } - INTON; + return 0; } +#ifdef BB_ASH_MATH_SUPPORT -/* - * Find the value of a variable. Returns NULL if not set. - */ - -static const char * -lookupvar(name) - const char *name; - { - struct var *v; +/* Copyright (c) 2001 Aaron Lehmann - if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { - return strchr(v->text, '=') + 1; - } - return NULL; -} + 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. +*/ -/* - * 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); -} +/* 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 */ /* - * Generate a list of exported variables. This routine is used to construct - * the third argument to execve when executing a program. + * 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. */ -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; -} - +/* + * 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. + * + */ /* - * 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. + * (C) 2003 Vladimir Oleynik + * + * - 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 ;-) */ -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(); -} +#define arith_isspace(arithval) \ + (arithval == ' ' || arithval == '\n' || arithval == '\t') -/* - * 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. - */ +typedef unsigned char operator; -static int -showvarscmd(argc, argv) - int argc; - char **argv; -{ - showvars(nullstr, VUNSET, VUNSET); - return 0; -} +/* 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) -/* - * The export and readonly commands. - */ +#define TOK_COMMA tok_decl(1,0) -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; +#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) - 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; -} +#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) -/* - * The "local" command. - */ +/* conditional is right associativity too */ +#define TOK_CONDITIONAL tok_decl(4,0) +#define TOK_CONDITIONAL_SEP tok_decl(4,1) -/* funcnest nonzero if we are currently evaluating a function */ +#define TOK_OR tok_decl(5,0) -static int -localcmd(argc, argv) - int argc; - char **argv; -{ - char *name; +#define TOK_AND tok_decl(6,0) - if (! funcnest) - error("Not in a function"); - while ((name = *argptr++) != NULL) { - mklocal(name); - } - return 0; -} +#define TOK_BOR tok_decl(7,0) +#define TOK_BXOR tok_decl(8,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. - */ +#define TOK_BAND tok_decl(9,0) -static void -mklocal(name) - char *name; - { - struct localvar *lvp; - struct var **vpp; - struct var *vp; +#define TOK_EQ tok_decl(10,0) +#define TOK_NE tok_decl(10,1) - 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; -} +#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) -/* - * Called after a function returns. - */ +#define TOK_ADD tok_decl(13,0) +#define TOK_SUB tok_decl(13,1) -static void -poplocalvars() { - struct localvar *lvp; - struct var *vp; +#define TOK_MUL tok_decl(14,0) +#define TOK_DIV tok_decl(14,1) +#define TOK_REM tok_decl(14,2) - 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); - } -} +/* 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) -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; -} +#define TOK_UMINUS tok_decl(UNARYPREC+1,0) +#define TOK_UPLUS tok_decl(UNARYPREC+1,1) +#define PREC_PRE (UNARYPREC+2) -/* - * 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. - */ +#define TOK_PRE_INC tok_decl(PREC_PRE, 0) +#define TOK_PRE_DEC tok_decl(PREC_PRE, 1) -static int -unsetcmd(argc, argv) - int argc; - char **argv; -{ - char **ap; - int i; - int flg_func = 0; - int flg_var = 0; - int ret = 0; +#define PREC_POST (UNARYPREC+3) - 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; +#define TOK_POST_INC tok_decl(PREC_POST, 0) +#define TOK_POST_DEC tok_decl(PREC_POST, 1) - for (ap = argptr; *ap ; ap++) { - if (flg_func) - unsetfunc(*ap); - if (flg_var) - ret |= unsetvar(*ap); - } - return ret; -} +#define SPEC_PREC (UNARYPREC+4) +#define TOK_NUM tok_decl(SPEC_PREC, 0) +#define TOK_RPAREN tok_decl(SPEC_PREC, 1) -/* - * Unset the specified variable. - */ +#define NUMPTR (*numstackptr) -static int -unsetvar(const char *s) +static inline int tok_have_assign(operator op) { - struct var **vpp; - struct var *vp; + operator prec = PREC(op); - 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); - } + convert_prec_is_assing(prec); + return (prec == PREC(TOK_ASSIGN) || + prec == PREC_PRE || prec == PREC_POST); +} - return (0); +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; -/* - * Find the appropriate entry in the hash table from the name. - */ -static struct var ** -hashvar(const char *p) -{ - unsigned int hashval; +typedef struct CHK_VAR_RECURSIVE_LOOPED { + const char *var; + struct CHK_VAR_RECURSIVE_LOOPED *next; +} chk_var_recursive_looped_t; - hashval = ((unsigned char) *p) << 4; - while (*p && *p != '=') - hashval += (unsigned char) *p++; - return &vartab[hashval % VTABSIZE]; -} +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); -/* - * 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'. - */ + if(p) { + int errcode; -static int -varequal(const char *p, const char *q) -{ - while (*p == *q++) { - if (*p++ == '=') - return 1; + /* 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; } - if (*p == '=' && *(q - 1) == '\0') - return 1; - return 0; + } + return 0; } -static void -showvars(const char *myprefix, int mask, int xor) +/* "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) { - struct var **vpp; - struct var *vp; - const char *sep = myprefix == nullstr ? myprefix : spcstr; + register char arithval; /* Current character under analysis */ + operator lasttok, op; + operator prec; - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) { - if ((vp->flags & mask) ^ xor) { - char *p; - int len; + const char *p = endexpression; + int errcode; - p = strchr(vp->text, '=') + 1; - len = p - vp->text; - p = single_quote(p); + size_t datasizes = strlen(expr) + 2; - printf("%s%s%.*s%s\n", myprefix, sep, len, - vp->text, p); - stunalloc(p); + /* 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]); -static struct var ** -findvar(struct var **vpp, const char *name) -{ - for (; *vpp; vpp = &(*vpp)->next) { - if (varequal((*vpp)->text, name)) { - break; + 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; + } } - } - return vpp; -} -/* - * Copyright (c) 1999 Herbert Xu - * 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); + /* Push this operator to the stack and remember it. */ + *stackptr++ = lasttok = op; - 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; + prologue: + ++expr; + } + } } +#endif /* BB_ASH_MATH_SUPPORT */ + -#ifdef ASH_MATH_SUPPORT -/* The let builtin. */ -int letcmd(int argc, char **argv) +#ifdef DEBUG +const char *bb_applet_name = "debug stuff usage"; +int main(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; + return ash_main(argc, argv); } #endif - - /*- * Copyright (c) 1989, 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. diff --git a/busybox/coreutils/basename.c b/basename.c similarity index 90% rename from busybox/coreutils/basename.c rename to basename.c index c15afd533..bdbcec17a 100644 --- a/busybox/coreutils/basename.c +++ b/basename.c @@ -2,8 +2,8 @@ /* * Mini basename implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/applets/busybox.c b/busybox.c similarity index 91% rename from busybox/applets/busybox.c rename to busybox.c index 33efb5d84..f6e06425a 100644 --- a/busybox/applets/busybox.c +++ b/busybox.c @@ -18,28 +18,19 @@ const char *applet_name; * this should be consistent w/ the enum, busybox.h::Location, * or else... */ -static char* install_dir[] = { - "/", - "/bin", - "/sbin", - "/usr/bin", - "/usr/sbin", -}; +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 *); -/* - * 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) { @@ -116,7 +107,7 @@ int busybox_main(int argc, char **argv) } /* link */ - busybox = busybox_fullpath(); + busybox = xreadlink("/proc/self/exe"); if (busybox) { install_links(busybox, use_symbolic_links); free(busybox); diff --git a/busybox/busybox.h b/busybox.h similarity index 94% rename from busybox/busybox.h rename to busybox.h index f79dac8c8..1ef90bbd1 100644 --- a/busybox/busybox.h +++ b/busybox.h @@ -101,6 +101,12 @@ extern const struct BB_applet applets[]; /* Pull in the utility routines from libbb */ #include "libbb/libbb.h" - +/* Try to pull in PATH_MAX */ +#include +/* for PATH_MAX on systems that don't have it in limits.h */ +#include +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif #endif /* _BB_INTERNAL_H_ */ diff --git a/busybox/applets/busybox.mkll b/busybox.mkll similarity index 100% rename from busybox/applets/busybox.mkll rename to busybox.mkll diff --git a/busybox/applets/busybox.sh b/busybox.sh similarity index 100% rename from busybox/applets/busybox.sh rename to busybox.sh diff --git a/busybox/examples/busybox.spec b/busybox.spec similarity index 86% rename from busybox/examples/busybox.spec rename to busybox.spec index 5cf13ca37..c44823acc 100644 --- a/busybox/examples/busybox.spec +++ b/busybox.spec @@ -1,6 +1,6 @@ %define name busybox %define epoch 0 -%define version 0.60.2.pre +%define version 0.60.3 %define release %(date -I | sed -e 's/-/_/g') %define serial 1 @@ -12,10 +12,10 @@ 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 +URL: http://busybox.net/ +Source: ftp://busybox.net/busybox/%{name}-%{version}.tar.gz Buildroot: /var/tmp/%{name}-%{version} -Packager : Erik Andersen +Packager : Erik Andersen %Description BusyBox combines tiny versions of many common UNIX utilities into a single diff --git a/busybox/applets/applets.c b/busybox/applets/applets.c deleted file mode 100644 index f3e56a9f3..000000000 --- a/busybox/applets/applets.c +++ /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 -#include -#include -#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/archival/ar.c b/busybox/archival/ar.c deleted file mode 100644 index 7f3396c8c..000000000 --- a/busybox/archival/ar.c +++ /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 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 -#include -#include -#include -#include -#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,"!",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/gunzip.c b/busybox/archival/gunzip.c deleted file mode 100644 index 430bc630e..000000000 --- a/busybox/archival/gunzip.c +++ /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 - * based on gzip sources - * - * Adjusted further by Erik Andersen , - * 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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#include -#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 index 54bb72745..000000000 --- a/busybox/archival/gzip.c +++ /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 - * "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 , - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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-1 -# error cannot overlay head with tab_prefix1 -#endif -#define HASH_SIZE (unsigned)(1<= 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)<= 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 index ee746216d..000000000 --- a/busybox/archival/libunarchive/decompress_unzip.c +++ /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 - * based on gzip sources - * - * Adjusted further by Erik Andersen , - * 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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#include -#include -#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 index ee746216d..000000000 --- a/busybox/archival/libunarchive/unzip.c +++ /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 - * based on gzip sources - * - * Adjusted further by Erik Andersen , - * 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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#include -#include -#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/busybox.c b/busybox/busybox.c deleted file mode 100644 index 33efb5d84..000000000 --- a/busybox/busybox.c +++ /dev/null @@ -1,181 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#include "busybox.h" -#ifdef BB_LOCALE_SUPPORT -#include -#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.mkll b/busybox/busybox.mkll deleted file mode 100755 index 4e15e1611..000000000 --- a/busybox/busybox.mkll +++ /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 - -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 index 9ab0f4bdb..000000000 --- a/busybox/busybox.sh +++ /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.*\/\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 index 5cf13ca37..000000000 --- a/busybox/busybox.spec +++ /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 - -%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/chgrp.c b/busybox/chgrp.c deleted file mode 100644 index fbc1036a8..000000000 --- a/busybox/chgrp.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#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 index 9139b3f4d..000000000 --- a/busybox/chmod.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#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 index d1e52deda..000000000 --- a/busybox/chown.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#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 index de6a2ea50..000000000 --- a/busybox/chroot.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#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 index c76e9c780..000000000 --- a/busybox/chvt.c +++ /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 -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -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/cmdedit.h b/busybox/cmdedit.h deleted file mode 100644 index 83893572a..000000000 --- a/busybox/cmdedit.h +++ /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/console-tools/clear.c b/busybox/console-tools/clear.c deleted file mode 100644 index 503bafa16..000000000 --- a/busybox/console-tools/clear.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#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/reset.c b/busybox/console-tools/reset.c deleted file mode 100644 index 755c4c335..000000000 --- a/busybox/console-tools/reset.c +++ /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 , - * and Kent Robotti - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#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 index c3c7e09aa..000000000 --- a/busybox/console-tools/setkeycodes.c +++ /dev/null @@ -1,72 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * setkeycodes - * - * Copyright (C) 1994-1998 Andries E. Brouwer - * - * Adjusted for BusyBox by Erik Andersen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include "busybox.h" - - -/* From */ -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/cmp.c b/busybox/coreutils/cmp.c deleted file mode 100644 index 6d579461d..000000000 --- a/busybox/coreutils/cmp.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#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 index 82d43adff..000000000 --- a/busybox/coreutils/cp.c +++ /dev/null @@ -1,114 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini cp implementation for busybox - * - * - * Copyright (C) 2000 by 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 -#include -#include -#include -#include -#include -#include -#include - -#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 index 3ed264870..000000000 --- a/busybox/coreutils/cut.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * cut.c - minimalist version of cut - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Mark Whitley , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include /* getopt */ -#include -#include -#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(<ok, "-"); - 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(<ok, "-"); - 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/du.c b/busybox/coreutils/du.c deleted file mode 100644 index fb649aee5..000000000 --- a/busybox/coreutils/du.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#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/env.c b/busybox/coreutils/env.c deleted file mode 100644 index 8bb690b72..000000000 --- a/busybox/coreutils/env.c +++ /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 , - */ - -#include -#include -#include -#include -#include -#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. - * - * 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/head.c b/busybox/coreutils/head.c deleted file mode 100644 index 688c250b1..000000000 --- a/busybox/coreutils/head.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#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/ls.c b/busybox/coreutils/ls.c deleted file mode 100644 index 8d0282dfe..000000000 --- a/busybox/coreutils/ls.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You 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 " 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#ifdef BB_FEATURE_LS_TIMESTAMPS -#include -#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; idstat.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; idstat.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=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; iname) + - ((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; rowfullname); - } - 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; inext; - } - - 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<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; inext; - } - - - 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/uniq.c b/busybox/coreutils/uniq.c deleted file mode 100644 index 53e3c64f2..000000000 --- a/busybox/coreutils/uniq.c +++ /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 - * Rewritten by 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 -#include -#include -#include -#include -#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/cpio.c b/busybox/cpio.c deleted file mode 100644 index 7f68715eb..000000000 --- a/busybox/cpio.c +++ /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 -#include -#include -#include -#include -#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/date.c b/busybox/date.c deleted file mode 100644 index 6db3e2838..000000000 --- a/busybox/date.c +++ /dev/null @@ -1,247 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini date implementation for busybox - * - * by Matthew Grant - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#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/dd.c b/busybox/dd.c deleted file mode 100644 index d46db82a0..000000000 --- a/busybox/dd.c +++ /dev/null @@ -1,154 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini dd implementation for busybox - * - * - * Copyright (C) 2000 by 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 -#include -#include -#include -#include -#include -#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 index 15cd0c9b9..000000000 --- a/busybox/deallocvt.c +++ /dev/null @@ -1,43 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s) - * Renamed deallocvt. - */ -#include -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -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/df.c b/busybox/df.c deleted file mode 100644 index 8cb13fa6d..000000000 --- a/busybox/df.c +++ /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 , - * based on original code by (I think) Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#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 index b534e6950..000000000 --- a/busybox/dirname.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#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/docs/busybox.net/.cvsignore b/busybox/docs/busybox.net/.cvsignore deleted file mode 100644 index 88825af14..000000000 --- a/busybox/docs/busybox.net/.cvsignore +++ /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 index 123f3811412c978f9a13b26c95667dbe1a167650..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11697 zcmcIqTW{Mq7Jk>S;64;cfOVp~?Yy<|6pP&i6C|nkp)**>w&DouSRP4E+X?dD=R3Se zlp|7h#_e2cis$;B3n_{p{&90R__)Yt>A*j8oev-Gvuc%Iu-Uf!G0VRXmPP)pdOX{d zn7S;|q{@p6wp?#FtGr^tS;S5@MT#HsDcdB~{Be~&rzpIbT=h1v>%#dU1-0Px*Ge$kxkG`S%MJxh!;9 z6oqU!By)c)GVml7G+eN&WW6Zo$tK0bO|nc|Vt!dKF7qeSP&()EV3Ex$=J_t;KNjhO zqaM!EWwv(CFY{Giu&RK`G<$xRud;n3Oth%@{B!x3 zJydKE#)5vaVlTksX}fwA4<0ww|5)GwTtVL+VwQ0VHOZcdfRC=(%TxZGR{1NNW$T4_ zc*S1Goc6<8_ENkho#N?RTFCcF3G>Ow+D4zu(4SqEkNG$D!sgqe0L+^_TUV^Civ0g6 zyLK3JnRNY@aZ2g#Z4cXGyCEsa00H$T->`MM>=t(U4q*cyIq=*q@5>DwA`3XkdvljCT;?tUE|D3Bm+XVj|;S%Cst$vpG*ck#sNQ^Vi>BS@r-F zF~3O4NA~J4K0%Z8pM{n<(^Z)&b)QI`3{5LTMTnuH$zW;WM>7kd*TwRMSX$yaQtbj! zm?_h4G(By~E)`ezGw6UjUw;QO^be4f7GK>bn1kJ4J%%DflvhNg;1lE+)nM0rF8E*v zWO{F8dU7t*WfGaL*q214lLb;SdR~htkVM=%Uhc4uB(=#xNrrYHoWQ*1j<-V|>GqLo zK`x9S;*S(OT61Po+qsDx+;P2i|N-Bn2evt(2# zQ3$Ulik}TO+p%lKuL&ShMPMV$Rj^H&X5~Y+S}Fa6naO~kjn3$liaXdqyvs@C9{>;=zHFo@uhS%Ma4v!W}L>%!*EjE^KN6jpO{(}Qw@J)k`( zyjw$VRV3?jg$+OQkLu}~Va*%*tjMvmR}ZgVS&?q=1_FlNhQgMrtLse_`b~ZxK{I!? z)+?dD%!>IcwR$aabXgF)EGg!y4QZAODJI(qp@v&W{F3%9YA>X=IkEu6W}k<1jCUx! zM{(u)i^3&sZ4B&KTj`IG0vGrnDVhs)8N`x1O>D?CMJhQYsdBxcZP`J)Cxabk1EAg; z9nA#Vn;mSzQ7xct-@z6T0{-x5D9~Q=U>j5>sL;0(aOWY0msx&+v@}LlTYOQ+fwW(+r0o7A7%g#Jy}4#sJC(KWdTl6j2N`C zu-0w&zQwbXxn$6BTaIUGzvi~r*K=$>>`j<&(`tIHf+*=;&UY+vv$`HjCHhlo>=;~hi9 z2`}?F$xOea0n4LF{NgV+a;WN(HmMCwcay&RW1HaBU!3TXV%?BWrJ5xdTd%$Pz-Lm5 z&U1B-q-zn3M12HjuKEotQU7^0c1y;im{p_6ix zB|O`qqghb?_8GZ$R&CNMooe3Q+6Mo+N&djK7}c7ZSo1Hh%Od$9Hvjbs#lO1q=M8Q1 zb>hE2wGgDSZ4dDM)1>v7RnV!MO2DN2=ahiSjLBYR94-Gl&7kBrnep!AZ)>X4P|JLi z$~T$c7S%M-&-5KsRRF!fnQ~vS;4&L-rQs6V4GuT*rM#hb0WNRn;+b$7hobnmu6oBk z^KijT{2zDRR;h!79`S+9aoHepaV<`xrW+7cZ;m`xaZdh~u5dFfn_y{cYx8w1gcAGgjxJ_v`gq&RU;8NbcN zxjZ+DEo_509FxRb=LDX$7~`?OA0w^~>WqHikM?5>b{NNTxF2KKX2eOG4I0hIsLdGq zxcO+tRAYn&-N$f*52JfA4jV=<3OpGjmmzFZq)Zr$#sD9=BOeUH$fqYK+(&+q&hbZn zv_B&^RWOEhvr^>E9vVkvs$h&lY`*qpMCR0-@z5O|z{zt*=rkpK2&gIL;R&$84}?WN zQe|<4Nk7I_&TFT2|73TQS{Ew>QpTL%TF2S)PgZ7srtG(q|IB_nRS2kVymZd>0#wUH=P#NdBB&lW%$9z`ta^pf6CB2Nvh!DPu@hIZ1`D%XPk2%4( z_7y1w>8@gkNjVWIp9sYOu8DCd)B_+f4$vy6j@WrPbzEsFplhldTv5h4a9&%|>7ixK_#{d8T diff --git a/busybox/docs/busybox.net/images/busybox.jpeg b/busybox/docs/busybox.net/images/busybox.jpeg deleted file mode 100644 index 37edc9614648070b96a748a08368c168eb5195f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9023 zcmb7|J2~_Kub+cLrq0XLqh`w)6y|;Ff!27Gw`ypGjj;?2@47G2?#*M z6{H}da$*7kP&H|}>xwWKOjt_ehPslrf-+3$e-H{V7|cM=z{AMMqa-3AqV)f*t04d@ zEd>>YIgmmWK*>r0WTm(o1qc8Dl)!&yPyqg)C@29y5EV5I?LSwW1wa9$1pQx8Qv&}* zDE^HCML=wda4JieKz7mCTxzA-E)FrP9U6q|OHSpWh4W9kaa=I;ziD0y!2i(y5B$GQ zLHUpU&yrvTP*VO|{BJqnf7t(Pv9gH(72%d3c2So=4n*wL27uvz305F0;1=Lh$860ot(6)>&o_oUb071=~4457S=kJ$Q%l;mUVLRK~CA zh#!}h{2C}_HX%rUL}$y8w@>Vp z=)L)YNpOBUV30C1GUJfP2A^;BQI;lKg=Q1w?61)%dztM6ftKz#ZB{;} z2~4=UShqZW`S&Y09gFRULCPcSHnN?dgwZJLy^CsVP~IJ?T} zK_J82?};8G?~&S>d4p9&h^zpEN;XU zic?w_%~L#rZ8)dg;4~wYBSeg|Cbn*HDgB8aHCA%n7^6~>w{Jc+9Le8`_?Hnjo! zqE2HZ?LOjBK+qT;x^!?rQD}WJG0kiqDD<18L_ZN!wH@*Ou!Z~rclE^cnN=2sI_l&~ z=yvVOd+mo=xOFo$m)qGTB7E3P2iyIxO+e;|4SSNM4#(pO<`PJJsJ+h{1jR{@=I>`K zvY=@k&wTr-#7xE-eaS1K*nr`jUu^KB#-`!1jzy}u759i|aa$=al_s?w_bThVF*01` z^=OX<`~eUkm*8OO5vnHe+{;LN*gI^!`wEEL5UjgJBw-Vab1NcXUJo=4? zf`gqU_l50{YCGtQ)CC}`Y}>o!PmlbxMsT;5A6tBP`pAB}zsfZG((bwKBV$MOLm~fH zSd&VMDEnIs+ote}XL~2&*8yw1b;=5F~F{ zamK5c-{xJx%z$!|mw{*Gfhrrpcf}VUGA1l5M}dT$+In$NY_O|`dsL55#mcd7)%Q5Pw_B{!9XSl{*#0y}F964?shS#v>m0+V@q1t_`3YLtH(8$Mq}EMR_F(XNAN$yH zKC)orR_SY+V;RStuZ`fFSyXD%HO!%H$kaZg?yu@GaXxX3jt>0u=s#=5*~9&cK97lm z8a#ieVxqbA6?l8b2Y1gp?KV~9nZ6Z%wLCwhb2k&fh~38vpFW-++V1?Arfx5Hx>E20 zvhWaA?KRWl;=3!zaeU*|AH_?jHfGA*tbt*T_JiG9TTyjKEMg1N3UAJOt^j!p4KbYe zBk%rIOmEY^z^OG9hF(j+dCuNpdB0HIe>;V{y5v4V(0KMQs@fnuj&`?aCxB-ySu;0M zm=NH_^wJ7HqYMeRe?8cUS1V*LGVfmFpymYzJ;pOl%p?GMr##T55u@mEvsBZpw3%LG z2WWR8W$Dy;IE{1vEq>uqi$)tcjV6ik5$88&120%DIn^Cfxw&PVQ|p)M!seEr|!=}p?l--66P?e(!wqN4_1Vee_L{x%%hG-SRhfb~-C2p&1A zc&uA?rYFB-UQb%#98~pK`p^MOg764wZ;6WKmni!U44B> zR-b>F(_h~3K(Sno*WSPyR%}i@bQSodz~+M5Yeit*z8+&vQg2cyzhlT?!Z`9s*kfTh znsJoKOZ*8-wqbiXz4)7Z%r5hL4CMOHFfr@~Q*Y9Tyy#iM=x9Z+qLF9@o)|6OW=Y_m zHM8nrN0s=ws@f}nrLgN0jm$@2FXFJ{XEjF_#f9xn)p%!@lA}L1zuGhF5haYxh;l;% ze61)gzJZ>nuzWus<`@W9aiq2|0{Z6_^Juo%Ylsvra)^_CWJe{#QBGX><%8brj}`!s z6fB10`bq6xg=#>215b9S9Tn$(f>tZ-=?#voda{XIU02|sxOrVf*CCmDi2H@RH$v~@ zX%hk_-J33~FS$W+R1}vB0!mO(kPH{tJ5sIqK){%8Q0S#q7$0Fi4sFlR!2jRTz;Dm0 zhx{1FAI3*|>kkTTn>>dxe&&UD$G^EukfL9~sb3$IW-3J4Q%&`;4R2(n;IY58n0HrI z7j3<|0H5ZIk3lSV^Esj3T(tAA^S(#uQ*?`5S@f3srurlgL9l5s34 zV7OSBoANKQ%hT$gTsph3(u1PMayJ#Lgsw47#b5BNhe3zdop=?+WincuP_?{afq{2u zEm{?JzIO{=0ru@_x*WB`sdgQ&zm{V7)^m}b9r_WjRoIlJ&?vbF!8C<>7$n1faxO7N z-Vd7l^!^HfK5%VZ8Tege&)qwI&crp%3(7%(PR_y`EA`ht4sIg}m4`8^ZE7C{C5Lk)Nbk`2%ws;Et~b z;eMIi&ThDsrqz`%3lEcSVvAYvu&n!1qYdG9lSOq|#pgeJT0YTz_qqxEio2r^p+0VE zJ-EeW-5mQpDW2#7C>i`&h+s6-WG?%VokxB%I>sv8%`FL#xDLs@ndYH9>AV|~UR;)w zWt)dA)Dj0>rz~2W*c9Z*g<4y&WKD2Q&VvqEa!HMT^uXF@W(|!B>@5aJ|2!>+1SnbL zL|j67)@(xm3J`M4>>@D|5*In;`nCnuu&Bc$IT<7+2{V!4qZ6kRHLH~y^skeDYZ*gb zC-@(2oSKa77eguOO9QwLwT8^w#c%5NJNDXy=iYmd6DG?r(QB!T=Mjna;yhBJPm(Rq zTPAps2OZzzQUoG10sEqde~YFt;|6Dx&C1oB?u-Y9?&n!XPoXrw3;8@J7sWw-90^VL z>p5ij(Sxis)kFYr5Mp+$@+V!V--5DQr+~fNXRIb$PpTB9l|Tz>It{_2SnoaiZ@9z< zb}re|y6C&r6+uIeV58UD2Qitv4iu8j8rd~TyiX#WQdzyLu^(3QR1OIoiM`d0(q~O= z(rw}rhWAIa{#vHThsp;?;lNMHIn=XqliF;L(Zqb;}y{`SKj&;9@E&cAJF zJ_;XtF79t{I@}*S8~FP5TkYr@y6}8=v%v>!T_5ii5KanETjHs>c&6MaMj1{K~KC5ST_Cu5~@ zF0f_I7tDHCsvb*dL?%DkHS}J%%nJ_2xHi|J%~J#P{x7L|#~btTZ;m6jU(As|oJt0; z67!|`8Kjt$r4|7xR2Q)}%hw%wO4wyq>53hi36ilKS!wZm#XifEUvC5{*qe5JJGJ2` z%X9R*r{KTPXHThHomYwDYOTYtLH_#unm+~UMr++4{?aE~Tmeqq0Aik76xll*gnWZ? zqPDjqZ9&3b?zAUg&s9Fm*sn6+M-Jtm6^G&T6O0CuN3cyb)0;p%BUlcIK>L>q&TE2I`iMdZ#;YFpR z&%o}qGHkr(rv6Q|_On&f%fIDq3irI9#7$f7jE9|(GB`^Ix;|-}u>E8TeruEov`KD# zzdE{1*kxM`(Yj`uH7*RAZ+iK_NzE}EoY?0@Jb9mHs3u;nd96v;k9dCSOncVLI~`I+ z%YXJb$RPB*019mD2vA`XNZmv#+ zI+@M}gK_H}y6g9BbJoiO7DF7?Plxq#$sW*hL`YNs@RMwbzMLWM_IP2~nsbz+k=C{B z#~W-S_n8=9oj9LRV-qhXx+;LHHU%wPcplEyaw$v{(9Iv?hF zT0F)tw#{89kq#l7wtIh)=#Nx;wtQ-u<-w3c%bZ zc+J;-X@Ei|=OZtDrDg%X^lAHZCcg5Nc1I?c_`fS&g7`)k_zKhLdQTk}?zdS(yU_}n=dQv znp_R4jW8MsCHo*UaFnV#uo+Qezz z5}8L-II)^@k4p~Tvz?l=A}}fiRQ^m+!&rCPaG){@9ZDuwEb~I`+pIi5pN z^2XBZ9Kqf3eBs72(;;RFwx~Y2HcsiHr{#!MPgttm38jC{5qi|{7Q5~^j@mzvUKNB5 zu9)c%X$^kqTep9c_n^=Ukh(g>SGNrjXB2PtO~@FHRkQa&`;K-?g_h3VQxs~IwrM(E z`1+b1r4@^AO^6akzJT#4J??HUa(qfN5*_piG@e@Qa$@&!mHSBxPGhz;In0MsVNunw z$52n)-Y361&x~NZqpQFO@6mOw;>yw9I*=^^1)Js_Z?Aa< z_^n11Ne@$n!yXou&}$KwBNc)-&9Qb9?@AZQ)~BW-4b@m5n3;Y@m@|b^gITNM*ice- zs7Y6LSXQFVSGldCU!ppcP98JA^$}j9*umC{=<%qAZ%kR`T^#mqutJBfOme5DLiAU? zxE)`~d`2;cu1CVM4^{$3m&0Col$*}a0Wm6WU0b%pgcX+HMsX1cMWps(-u*fR3jtDh zhgfW}-eL|RR=`dso(~|CJCB%+eQ>j?0QEC!j6%H@A$NOpcy_Icz=3gbfsp2)PG-F0UFuv9dHM%qZ%J#0AuW`iJap_h>RiV8rl^YP zR}^?JYThgzQIsEdiC;IV_79Hq!k zWBmj|<|DHdPpkJ-4b{Z`h^!RxDW6Qc1y0ECcY1=Uj33Cs(Yl>N6U7r4h0JC?gUn0p z6OPNf52sae>!QqhWqx7FDv|#!n8qAST2Sg3X+_oQC#7fQhS~uH|6t~(By_wE5~$<& zW46GWF(LFdjlrqUceGqmogtO`G@#%&{2kH8&fyJ1CV` zL?XVzOYHCQCN*nMYrJCi6zjJP# z`LCua=4*Oh?i;eflP1;BH1klRE3knfiH)NV97%VA#X1EYEGLq@kSFB!a*G$m*JFD;6{hAWXT42%{a zdDq;BDORjdMXx~rUC&H+`$e2ihS>}G&F|g^wa5J(xjZTHCRy&3oLqX)?Ef*Kxpa^| z=UY&b?Wzxq{3Xeig^c`g78~-`=3zDUP^U2KT;v}~NIOG){7Cln2uUc&7zO=O(D^;> zK-wzm@N3-T#qIv7hyDh5vD_SeIE~yhZ+&O&``SF64!KuVl^{ zL2XNn7z_?uI;u@UOh6OA8GGSOnqE@gM?9?_HrfscCE8tB3#w%6+wJ9yTlRsm8b-H66K8WIr{_Oy%=)go9rZV!mNVKQ>dSE5 zwYLR9@(e9&v8virjW0XqA-q#lB#(K1w-$Vr!Cnmw6kPGv>!b?FX$0DM=^30bG`LW7 zE)MEwlssIKMVaze^5Z$pr}!wJw`)Z&ax%H$4`l{VS%dk4fLw<%FB==t#<~jFJcDnx zJ>Gpgbt&r;_WEOgif=qhtjl!X;cp4Zr1yz5D$!9_2N*$Li1_`tV&iO_D$7?WZ1R^c z+AQKB^nAwQg(Ts#dbx`5Za8aW_AadRYwd1no;~tUang<%kY)bRQ1%i0ui*DI@+XZd z)#8GDBwC1nV#kXT-noG#b@r$2O3$~P)i&K&YpzWg-WgpQLF4|`mY+SQ`#}Ln$};UX z3zRmP(=x=rub_zHN5!C%H>{^(m@U0$?{JrVc9yL>X}+iqHK_`-%*EtN-#Zi518#p$ z{yEbw+9PdWsEQVz7jb8jiXuprmAk^USR4b6&xjAK!haI?zDOf4Ohqz$gj~RoV3X%~ zY4Ni%&YCNL8irP9VxBD4T)o1_m&f0tQ##+sciTAOqPtv2_uWZCl{cKfF;A3z79voP zyn<8)LEhK-_{s5(?M?;@vU~CiyEhCi9`CKEpwbg>`y+6DQw2}F6MAKI#K)&*q+Ywz z@)1)Mo~`uXm3{rYqb$c>!_imvL+Voncr!tDKXh?7;Rz?Df2VDQ(RIXInb(m8ITVyC zdi35Rjtp<4E%JX_r%6hHE_KR}+CHDLLJVRp{K2jYBGQ70=usa^MNK=a(Cs(M1C=Z0 z-g^(Yhy`zrQba^tD9_pQyToK^iiVfEBT16JLCHL{Jh3xvc5QGL>d&Q>H&ax)U2o(A z;Ho#L9AKyy+9aUhQZHRi7*V8yhzi*RVu^#7(D^*my;xbObZ^ z<=^A14t>SAp5-+_ZnNcTfx=hhN-#OLN^ggvq$zZXxwwKDNSBv0o6mh&2z&u^$f#x@ zCr|N;VB_-8#(Y@@Y%`yW{5G(N)rSNvjEu7cX5&FYb`wl@f3&24$O0#~BL;w0qp| zMaZmF=|FTAv16s~T5ff-lYC7cc*fb~66A_@dV1%8jssnNf+q)ITAlBnj9z*<; zas6EH{z_K#jk&%u>cZcgO9&O83OCes-4QM(a=+|0&W$7Z?61!ad&Jbzv$A_D%+ z2@!gS(L3YVk`AQaS91lHizpQ7uK>6ePg)4+jVKc$jLBF&Yrz-4-ddv50Pn+&62?2v zw}%}K<(HJxZZ<+Wf?gkD+t`&0<_k}NDG>^gISDi&dDBT}*b$kkS!Zh>FzDtzZ2eO@ zSmy-8^&IOKOKsHWo^=CkI+6IWV4`{pN%t-xBDuS++#Yta!0~) zcWM4a4AGO(gnD4r+uEW%kXcj-U(iigP?l|x3f0B0a{VNg;Ue05%r=X)Kh)59FLlMn zDLhM}tO=v4*ohc+{rt>}E<&ApZox}Np8sWcvIzn;FKRjKzp8JsSyN*HqBrJid=b~A zE<(A>Sg_QGQ3kq}y@&@Z6&Z?ypA%(k!1s<~qwVJt5J`tMXkC#I&9w_-I5o2S9yLMG ztu0K(HjaW+2ml<1Xu}7jg`G0kj4lu;|6={TBOBE|o?4XM&S(r&mMTE=5V&I*D7@m) zolq*@5MJ>KWGf@%id&?39U(aNFf)qkRVlmz$IF&d{PRO5;n7ZzPzsIOUC)DR_Ya)l}iMMWZoC4HUkUb0CpVz+X2ettvH zn(a33~_<4iaS-B62jILYChu4*Y(_QH@Ifg@_4tD_ zIxERFy8-<~i-FAz&njoW$W%KMp=o=K!uD}Jgq7FSu|SdEhLVB9`1Hd0U~NBKGRm)? zxyi0YB<#DBq63}Y@q&p5c|}DJ^@d<98>a%cGse9{L9csT%NLdG%!;{|A6T~en&B@^ z*YuXh8EXE!uz)d6Q4RUHh!E#hShsj%y}CiKKQIPJBsWA~*lPkqHXePiojys-_}c_vR1DOQrKzdL8Vk(lI~$#0O{gW^(u%Dj~v$2OJMc`y_WWb0WyU{XkI zI{)ceXi9QYV7UU&YSfT}P5AUjt9%W(g-t+fo`DK~6hkv=X5YiY*IgO}e?S~59J!KRqH}eZv>rWBVU|N-D~-PU zw4`x|*k_LQ+s_YxD0 z`z?n!d71?PTym<7tu{WX(*yD0EXhSvTKQRC-}YI&TUXUle^H+~F_x@%mb0utvg3A& z3)3;{yR;DNBLEDq*xVQdH_Rr0WN#!%uZvrYLUY{E#pb@(0MWJ2;KtxsoPvu$izcw zPK^XDn^c@r{X_~_%q2KbN!D-jw`h1Yp>;gNOC>?4?M#e*`&D}_b-Z=-dSA`C*+V(d z$8w?vFuh&@wX8HKL6pY{;N41%g4Ve@#>$o52D zk}5%xS$;vEljD`!q@jj<`LC8bRKwVh#}+&+s+M~A(n%^SK`|pseJJ(Jwu;aMjb?z? zzqAOu;!K71aGDIl_1S2RqmHFss%|G+=uhY&?+p%1M(+inMk;cb&6UIQnx6f+LGlrC qy2SApw64beEjm`KkOK~FU)=&1au^Y%W^|-0<{1ktJtuRo$o~h}A}@LX diff --git a/busybox/docs/busybox.net/images/busybox2.jpg b/busybox/docs/busybox.net/images/busybox2.jpg deleted file mode 100644 index abf8f0610b6d87a97accc655ff4ff5f9948b3e24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8204 zcmd6McUV)~(s!^RAgD+$g3>!uLJe?40Ygco1rpjpI+5P{QADH*gbv}-2~~Ovpi~J$ zganW-9YT@b%jdbzd%yRdd*Anu@45ecv-h*t%$nJ=_MYE7v)5Yt>ig9Xz&%ZMusVQ@ zj0~Xh>i}F`0+^n<+gN(qSU>b}@U(wuU~ltK1FZAnY7+1iKtWD^i~J_Vty{M!DJiI^ z>1n8M-==1{Pj{F80V^lR16FqShdg5Z54l9R+1UkT1w|f9NJ~p|^2;m9NrJ?rq$U4! zLPkkRNqw7|nTCd0@)7$Z$^U1%`UIe*Ad@1SyH3UhxJFBMotEsX3&0K_16;fQ=X?BL zBD;3|2Kmif6u-2p_W;+(u3x)x{pL;b8`mlSH2G6Y`$*y@`TZxlmTq)hlCR@$(R1fi zF{tXj{5-@XDAFRK8|8;=B`?yK|OD976OL>j##;=p?`pv&T z0ogU$>o@K{l8}6&dy~uZwW?dy5Z%-Gob9U#0QL1>#|>PdM=3$Vd=jRz;+6g z?pm`CID6E^ofrr~$DZO#2aQDA?Nn*as*!P810h}Box)uwOU}0QUNy%hw@-BQ^dl?` z{CvEO^3!E{|F+n+6;5z8)y=QbE91hB7a7I6PN+PXR!QvJgG1b%2Hg__>URxBJ?Vb( zklLce?B*n#g4V@p)|mEXU->3g-Y*iI7|~zzO&IS!$y@3p`JWf~2(i2AyE`(ZXu+os z*<0^0?@U!SxN%sm{&D>)Sz^|*v$!yGPYlaTC!6-`q2UZ|c_2b_Ny4}nmb)@4zdw;< zGp_Rb3RWenVzYI!#KJc`){V!Dk)6;fzMW?{oN+M`MGoITPYnp2xFIMgQkWimBlVBJ zhVUN}^Yj1W$Xf%}Ou~55uOm8R6~XK`8#IdZo-% zzw#i;iiA`M*4ocflw{9sNU)GvIgk&1Z-Ae#&3=tBdT%yzT#El?A@Z}?Vc%i;MQB&a z=fDB~sh1t^{I?!u-`EXYHWbpD&&)0r81=Dj+?U!)_hIm>=($V#6+7UFozuEBV}hne!8#xSplDLe;)HK809 z!T@iF>ATao&3AIX;Ap`{KY9xeqIi_>Wh#s99xqw`<_*S&G5q#hh>o&iH%$ia=HmB{ z4-~xSfLQC)8uxDG25pe8jt?(Zq%{V@1~;lIkUml`dTbGde}^wL&K#xPOPzBL`rta% z?Y-5QbA3MNzkar&OvmsLlwT=*OAsU!w zE8Er*^6hGhlus8F_y2+QKetceI>^e`Jc4RizKm-S6SR26hOd(#Vl+vlerb4nMq+k( zFn{MHcfj2BcB5+gtZq4bw{b82M&DEI02G}>D4NB3!i ziLWegRZ-YaP;M}9DC)fa(7@lsM8EOaFt$l5w+{9@Zgp~%z0#2QV;hB@U|*4Olbf0r zGFVC_7@s8nI5(FuZE>T%xjL`uRe0oADH_wCIg?v8COsC@f5uA{=VK9sQdbj zI&~T1;kyX?P({WhX5M?$9^HP4wzBsT-~(}`v9CuWe#wV3v|);G=j+3Is;&T2bs92h z^4qT#Ys`hlSQ6I`1G_Cf=OA86F%C{Fm0nmo@GHFW@up%Vsy4bdpqrHaWxYwAbZDdl zY4J{oWf0^WPKh@0_h&KXYhYgLwkxs+NLl}L{Qu<16O97^Hy!!b`qbv?a<XzYbVbk8m_oGXtlLbF$j+Xlb|7aATvvb~ z5osS(Ww~5=n1%~XDms?{CdCal)Td)i7dQj&4w-NPZSAxH! z#A3#%Ijc>#$c#87sikKAptvqB2#rc+GbfK@YzcFgI4TLDd6w4N95uMk-}-L12Z6ic zLrfyk@F4OUdCSTv#JOrI5`fynYTm#cN=D%tajyD=Cyr6T9K$?ut`=4Pj{ymX+V$~u zPvmIqO`cD%P%~>Ju`e z*#mLB$+j43;`SHa4v8uUgHK}n!f%qrh05M^2Wf909#xY+?@QMD%{qzkP;Cy0$m?>z znZNG@%;rL0m zEM!n&Y02i|pxdWWE*>tm~+LWFyDsX_VHte&+Re)&?`p_ON5f_xpN8 zp3zG_8@28x(Uv^PJfX_Md+tFWtF6%boWMYzAkb+`Ikny(6af-zIi4e|h*Ax9%tW_$ znGxRX68BC*bk}?@R#YlgHdZ@BQ^boBW9ODO{O?zO#`JX?mcn$mW9hg8ZATLzli^RW z=lb!>yO#~!Aj_EcQ_qEAn@htyR-mJ$Y9=}`Ce<|n7f*715f_cVaq@0UuqQH%xot>2 z3?l3Yy8{&C2OZC`!!OH;Hak7)grWuX)=cRf48@(1aVoK^9WF+rs3g{x0WG6n5?`fRhPP25Pfm0sC{Cv%U^!maNBIQm?pT>U4*R z$Z6(9#$nyyg-oeAtg?&*Zr4|Bt2Awx|DM&^6Tvkqvp3IFTfVj~l<=IuB0DdbR5i3~ zC)yun9yDKX*vgk(s$BOiM5p-7ZiA?B! zO3oY7`RPc(1iM}Y>IR*QQiRTom=0KQmz_LGnWOdOCF@}K4vbD6RMF#??l7zkwmzq%NnQ+^+1#rSY4}>ez zfrJMad*-}g&lc|T@DL=`g*3FIopeRCuEF&r8$ou>d~V|@krO>RX{);3B{3`uBoq;&Jc0E7iBVI{p?X^6-CA~=QV&=i zYHiP1T}h>K8hu|@me%Eb+x);6m2r%IfmS;DgPhipgV_+RwnsKPbt8hZh1~3wm^YQo zIsETmxICC@|2~I57|ghR=96*?Js|}8iX+d5_C0S0>$tVg>@F z7iSnPB7(D|L4y_}&4W-TQRu=Ipnj4gBb>9SPCrgn(!8TX)W;)P2N^5xXYwNjj)=Qr| zT9iM!mM4zW;xOd95xbEoz?MEZwAAM$DZu%+5m`!|wGqtZMdo&dsfFgH+qnWlLz(|h zo=}|?L|7Ed6W6$#LUWP!Nk9+fCNG9zbF*4;4h}qs&6}c`lOY?P|DW>p&%Qf%H}xix zAm%v;@y;8;|n z(L~FUJH<%G>X_^np=rt31f<%0P^|nw$XzZBt2|Os#p?>74l5@w7PK<%r=G4V7?GPK z>VV5tsy3jZhFRrygi1{`T3F+P^J}3gfx6D{aM|GZEDb?{Wiy4;EwNYS^R4AeqKupn zi+w4#42xz1*Njg6%=AH(fZO|a{PJF=;3klAZ`fFH=|CKCVZJ%>*#CiwPOod49mkTh zywwIuprZ~hwi~H?p(EQPHYEYgO_o`U4KYopU4@2xY3_|!+&y4FZwGB&PN(kd;A15v zA*AK%ZUiAEHuZwqsjn*aC|OApH;?kd*#SFV)=l(btys({>NzCB_kcFO2WuUVHL*+B zC>?IEwuv6o1VN$woU@+L%yd7e)EaS>97$p;XY0_Q?A~YitcJaY^TtqrpQ+C)zqWo8 z$(B<7=H53FxU!uVVozSlCx4J!45bHYRz;T>DI0e!7TV>=hDq#okEv%*i7?Ie%qsaJ zic(+7zcW|n{51G|YKIpGH^hA(enC058(G>5)2y#{(VsIiWNJ|>ILDLQyE<6yAl3ZT zXckWNS|Pvv*qIOXHgwdGF3%(G&Cg^L&$u)Nd8_51H5DunT%dX_zo0@Et)t%H_;}#p zHfiCw(XVm~aC7{B%g$TEhaav0Kg4*K*Fp|Ikz%bjsi=y0+$fYuch{t^069#<-_PPg zi;6sef?j>v_zCmlCmsc^%Qm zFULQ89=(e*#%`Z-a#>UeQX({S4?lo=dvASP+ZIP^JU&iHmRRB33J#iMS8u1BH*mHe z=jWN5&SAZgyw6$L1_T|p=n8UUlo* zUePi5RuzT=L4{pppg-$(ynBFSpZGf?zO$8Ob(1Ya-o1T(8VxyX?@dK@o8>5>^ds)l z{@Y(m-poS(mcV9>+vzwEIv8IWiH~C{%3;y<4-V~6Ox6)~jjT@`d}||fAT;WUSWH`T zD5*}zN63@>@8t=uG1s5Rlmv1e7V>UPL|v>&r;vbj#l%E&KH1RmqEDxKNyzuS=V`WG zzBXaNT9RM?#k)mAyk%QYx8m)RD2aw_=#D3rW7nX#y`zAllHKlr&ujUtGFMcxEAEl2 zRs_$Af~&bZ@q75qhBv{(*rIa`o0!hrVjj9uUfAXo;XqsWF(;f#9(jz`3a~HdhGd2i zZnQspiJF`g>6uOBZca)!Y_4+=>D>ep*pBI4Zj0{=-%MNOuT`u7mo0d~Vi|d~)$ET0-}r<(qWjQy+~}xR*nq zPwbJ^j&?w=q?GKJN2h(uI-`#QJA|!dQKJ@MW$kw|3s&F0-_u9cf6+G{b9w5XLf&3p zryO?vlYB!yfOBP0$@O1oyI65MiL%5TS%dlOyrr>fH(3nKl)gAwk`NPOhO*}B3F|{vWs8`Qt|ZH% ziwWoz02R`-FSQaFaZAjy8Ex{SVGUoFa;W^?dv3>XYW6Vz{^1`P_1`TSjSX=A#vi{r zn4Q4m~xbWJF)AWjjRn^fvt;zFZAk#ECu&=Xd`w^jxQE*lkK zNw9&8s&DT2`ZPMD7b&!^~+fE zVNNa2S2I=CN~@@ii-aTiI)fFenKI75IMo|@DkN^G8@ZwO-s-DYD`M&<`{1;N?l7IT z24Y%`L#Ijmmr7`GmzS18-N9YMXvUEzF)CAev68zG>9GTWqi->6Ji`Re_~fC0-Hx&S z$Mp&0HKHwg?#bwv2tRKXyP?d+a9T{9o2rBho_Aay5)=qw^^&!^&UXyuoJ3wj1f;fm9brNiqkyO`lercZ0 z_ziDpJJ6<7Yg6bkwOPJg;PPN5BNHepq`|>&>A=rszqK#;a(Hw&xvBH?!_xYJ(60>$ z){cIEhKVza%IWW6N}8e#)>s}PP#Ui1x%)O;Xi+LG9!SUN4rduGU_aQ9N(*`ELsKO0 zcgOGe{m9Xy^((-WN!r@AH*CR=>>j*F4$z6b(d+3pO&^h*I7We`)xNL|X^4O)4rkNdOsKwpB&kqwQ7$x zttCqpMZ7L!qqib}>!#WS>ept2vh@!G6*lu*Pp2&sEWT~rF^cDorPDK)Qpjt$8|{~w ztpKc6rmS{~S@CRi6fA@DFoTN>c!v#Tx@WB;Jhg8JpJ|6VA-1k;k zrAJNeT2hw0^ghB-uQJA#)H#(Rl3U7FehbFfDA-(2ASSPcgUU7Q(NYNhSI(aULFl#htKXy(_@sQ?2^!$3(XklFYM)Ro&Ht z&%!J{RPse4zenk{IGt--uINyC@kcuws_Xf0Xy@+se{x?ly9_gxMtn>zXwY?>hWq|p zG*Xs$vc#X9W?pXe(z7~FQSN;;E}E@&1a(yY>>K46 z%P&)0eQJYJjp;Ln99IDD*#aAr$r?9fqb>IiO< zKI8b&Lq^~$%&gzq0NnUzl>e1icEe|8P;CXma7sWQ3`5PHvSS5rwxxxT?vPAy90me> zI47Nn=+r*Z0J(?eA&k7goy%5aMV~yLO+GhG-~LgeuH}i;>V#tIgsR^@5GtK9c}~z# z@-#0}&ho(d*C}kV@e5O|CoQ_)HEdRhrBm4k^EbRko0u!{jDba$9NW3s4$j}fl(|Jk zn*FqRWQ-)If4AeXsu9OYH@jTs1G9V{^<4pO_fcYx=-Ar@wfsM@1`B|=#$KqKaKUjq zymjBBm+B*(c^q(vc>dUl6Gu3{065jDFa#B*a3uQM610Qg`t0rrssp!p@>DZP;EmjB zf0Vpcv>7&NoM0|xQ#Fq}H4@XdYu?LxUapv0WKJ6#e9OV^FfcRk2)E_BmA93p6E3!m zW@9)CVAVukS}%-<{FFU)B-O@gxBkl{=o z9;y=$hQBVh7cB=pX0z&y6_F%KRY33?XKyF#gd@h95@t)x1kdA#5ZjZ&%mOBe;rxW& z7W!=B1bLY=>`dYhz;FMG*1yXy8ykwe)D23yH6@K5(thJ)TY(q_N-mA&>721Rrpu+H z@^*MDb51pP2g44q#isiDZtnE&(qcBUNn!OWNh9_+F^UWNJbjenZJH~?j z8gXgyB1+FaBB#qxUJDOo4(NoEO&30SNx^*FqB{JKMRod>IlIKOf52f#Y^H0Jl~g}b z4F~m#=o9ObFKAKFQhwgn7@6cC1U}pf7!8c*bN~vYOE!Zy(C=!B@ZztkNsrOlvOcu# zYq6D|*+#M4krtpAHJCUS5l&d`k12&-6QqLlY-D6#b8cR>*0(W^6qc>3{*rdxy$rG6 zS{oC5Qm9ahJ;EZZqD^$6FHklLdL?5!*u}NaZE{v|#hqfN)kg@TTu?#1QcSCym2+yw z!~gwj_3t?RnzV?E3d|w~XKLwlfbY^W$#(8IER~#J+tPn)BMir4c(+fa`sZ{sJl z&!#tH+V9n6wGRB+wFSOQmn+G(C0cru5N4WL@-F1nmVKS=5+l8MOj)LnUgYczHG^^< zjDF_iB}3xsAt$IZozp3@Ieh579V_##P)TJeuo-i}DUkC?uAGRndeV9E z{76(8?<_QL6%V(QO+{ht2+mhN7S{~vp3+Q|R_ diff --git a/busybox/docs/busybox.net/images/fm.mini.png b/busybox/docs/busybox.net/images/fm.mini.png deleted file mode 100644 index c0883cd34c35133634e52808ba6dcbf0a047361f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7708 zcmWle2{e@78^>QlQ^X`crpQu?$u=Wpgk%aCB$LP_(qtP=lI(kpWG{`K$u=Yn*~yk| zM%L`h#K@FMjBP^p|NPH;?t9OD&wI}Mp6A~0_ul98MBcn%bmZ`f!vFvrF}{8c&FwMV zCJ*A}-e1mq{>kn5ob}E00iZNqaL0k4J3jQ}x{W6Q2#Wr{@eE7`?{FU;d}eHBaIl}B z7mQH8aoM6408SPeU(>hr%`o%#`-ry=nsPS_xV+uH@!ijN!)&zAeVKC}!s`UfG5dJ< z_^~Vt3>24UrHH-@bCc4ikteErqXh(sy2NFE%X2 zIe&NVb6b$1Wht{m)(0*Ju-7uz(i@i|Ue#53(@TS!>`Nl53{)iD@sCKCyhM)=KCbS| zxHS0KOUydfFxrAe-CD!7RzJeUK%ro04{{rJZJb=878*@0EwBim2`w})AaV>a^AW9cXXf0 zgPsS6JXv3`5v%GAS~0P&VOLe!Eq!_L9#a$}a6qoBb}ltDQ`h1tRr!q)_9kS+b~G*_ zo2gEKvB>B&a17i6g-N<6R=af2;7wgI&CeKAiLX;O>D}Z*bd`bRP=#Mr$VBj|Uk^p1 z&^VhUu@iF7!2=kjGcj<&Dda0WJ+~humqipe&c! zZf@n{@565|O;nDy!an}H(Df8F-S3j&i0yoyV|ujec==Ivq9_%FG@ZB;#n zx!L&h)H@b=Nse;Ypavkhm}Us{noSbf(FWxa1E;3IyCDJq86lfj@ePBGfu4pO1Mo5D zqJ|*G&{l}DWB|zo1ob1a=6-%WB$r1-LFI_(&MGLNNC_v}K6FicYIjZr1ZS?i@_ZcQ zA!UN1aq8ubi|y(jTB$W?lYA@DYHEAdS5m;}Ld&R}-_Ir{6b~4>sr>iE zF5lHEDIA_vsV<-#trh1+7e|gku7Xk_5^`-Eol!416{7^rleyz?=Yk=vlsYDx$3tXk zL$qVyG!FRh-Zpo1C0vuMH@hlWkC7A`E zrk!7Ef^Qpbb0dSuJ}ItF{9)vZd_dPe6admjw$V{Y>(l2 zC&P{?v>Y}Do?m$d#EqG9SDA9ubM%mlrTbL9Ym6l(@A%aY*=sNX?CXpCEuzO4fFH1fS}{p5sn=t&A^; zwXpCwKUdmitx@Fi^1s;V_@G~I?{=ciA3uKV9iV-t@40M7X6Edv#3)y$Y>YxO+)%Rk z2pE?V4!R&HD5&SR7-5h~Z~!Y1zz=Ok+C0XD$wIC@%3Ylt9kW}|Gh_jW*iUT`Nh~Ol zfCKQMlGCBEvjp|?QCldEEU4mWs8Gvt`Y6Xv2#J$w3`0@(tc3 zI`(R@>Jk2be|L5srusTNM{rs=^|&52zqI_qfiqrGZUL+$_y^r#(?PkLwuf5Pg6BB# zd%L+JdOOQ~q>$p_IoXfl-8ElYEk@U&jvZx@JkbA`&lSmM8}FCx+#l2R+G-xGNX}I8Ko>Ri3#2(5opwJa)&eCFiU5c@amU_Bh{;t{RIJWK zTdUbi_x1EtVpK-G!WB6>)ogJx0sWzJw*F=(tm{4!B`q0?U>U2c`h|g4b zPIA;1`N+;PYHd%g5fqXO(nr3}=@<}GY)7Tq#iM!e-kk@flF3@C?=M=qL9ZPG-0z2d zQ^V3EvFh>g&S*<$HW5w*0Nw{&b!TY%s7Ae%P`fvivwUFGgOZ~d(dy#kqbJmAm^=Hq z*s@;ntxjJ!*X^KQN#e{EMC7gBGsw2G`tel$Giy^*Ve=Ej2de61`Ibv3L})9aPBv7n zQA5Li(3SJ_pq(Q7v!QzneR>}IyBkYOi}xCRSK8k-_-?bS^|lv0-|a3q>#e@o_oYv) zu!6UCW=DEPOKgh>d)kYBqp9Z$i0UDm%LS@-H9Ly|jIaFr(-D_H!J3FpE9>i4<>Pm3 zZ4pm@zGC^_rQelMwRO3e?lb8(8k?>u9rU-~yDn(;=hv$d!e-`X_Me~5NiqWKF%(lX zGe*Et!`i3D+MxOD2;wSN2-s*3*9ngT9qHOI#I=5|GaBerv;HR^*SM7Ndf^WX*dVqz2%1_ z#}#?~xYM1hsm>&x(B0i#r}8j3FD%w+EmEOzJzPy^b)& zv9)_M_Qu`?FKF-oWgnFGozALDmXB-W#JEE|+5TbdaXKgLL!7jwZV{YC)WJYf{c|UM&fGi8jQQZ2nyR_dd61;4*&yGJ^ z`;{i`-%HOlROg6J+20&GVm<7p(x zn>ajUVtylMcsRFdPmSTjaR1&^Q&ZM78Zt+=u5xGJH{}WSysT9P!P=HwQ10S=p)W~& z1YTXCH3$J=3-!vOn z9!eF6=>A<%ApLVvd9<*wfOlUSneS1uF5dfX)E7rvSz%UZ>V^C$Tnbs@{?J~h63bbe zLyOP!og>?ekpowpoBr)>1Ya-Am50OzOlG&+j#BOB(^`#NvDL-1E%hTP~8R2~4k26BXMe1G!c!tNg>iR9#Do+mc% zCo>GG%Se%aO|gnH#W&=v+{uQZ$KF~dzg)zW$T2IN3|8tixdNX9wL+N) zbKS6c$*(V{PBLCCpgs4Um{k4&JWb zXSWL`$LdpNhh+AC$asltiCq3i^T`Y-Cr-HV0fU+2T&9JE|0W$^CFh4T`R3>EwmRq+p4Zj2r}z)!j)n4mDbU*;J$Ue7gs_UVZq);!#{HnC z%?`%p)k5>#Uut%Hn*%eez3Z2Og~ew~54dJ^jsNel?(Xi{*(9uW{)E-EGfDEH-y;pR z!^VZ)Qc5P#xkjTp)tHB{6HZnC)x_b2LbDaz^(Ju_o<{{?chPq8B=c0WYlUUXxx0H= zb|p%V6KrqMKKVJ=9~xDb5(XdP9)H>0lGuuoFnf#641~vO#~ZA}o$cm9M$?Aw{)|sB zi$S4KCVdz|iKw+k#y>B*w@McefP~1!h<-Z}Sb~I|zSGmAsv*ht?@4`k_d8t|IN+Ml z*QfG4%%^EycYc0e=3mdo-HRVA&jHJcC4ssp&SbnG!hXk-L+9qSXvG4-?E6hJu?at5 zf26M^W??8+$w@ea)Ms@8#+L@p-4gvT{59_=9zQ$Zu+x>OnNvMEJw24H zmRWI36+T+sBq3&fyPv?afxCgVWWkM=MD~Qjz zKEK^Y+vhzEww1BF*9w~AEN&BSs?{&I95WA$RoBthW(GK%aml>w#X9M1t~ozk23x7= zI3M;#L!jZ`Otj%(Ympnrvj~lYdVmoE66PUG0p@|smBg!_=gVWS7SSM%#zeDIg0)Nb zyYp9-Ok!pvHH&!%B-1syX0d}>-Vs!@ZSr7N9aAuo+o)?T8XbjtdfEXOXy#H&B1R$m zi6!;x6XBAY?!viysYKZ5p!4D#ZSTMz-6sqF#MXvy<`zqehvyFowmM}zOjfn8 zl1g%7PEAkudiq={PG^z9)RJ%YkpF(U__)uTxqs&Tn>fnw0U3ns|1#p4-q>qhvYu zm^F!V-B@pDL@$tHv!R?m)beMeaepX~WmrB=%Cy;9iMRViK^0ldZ5ZuNfv`IZ<|Ou! zDnPKWI@jYJ_#^Rz(Oh$Ig{Rvy?Cw@}Vx>GggtZ^!uJK0_+nX8iHlb!RZFke8hIlA|Ra(X)cQwq4e%K|*gXHK=AUCo+HS~}oKlQrP z8`)*0>?Qw;a?~#bRbDE@OR7NGgyL0AHyg01#AK34aXB53^7{Hm^!3?UClZTd6^%X& z*d(=kSc;t!YPBl*#ST`mSC#4hNc!y10^91Tf7bM{(ji#z)u9%PUcxm|uuLPqa=&q zQ^_90yGi9WHKvLgP0KC!VYYYDJ`CdwNSma;^?)4m6%R~*x~Hd4htn$9=x#onsKIv& z`6@vG+o=`LM3~(=lU_^%pjSY|ehhOe%N#49akq2k=BU&s6$aQGlWHG)jj>%2Y4UT5N z^mNrY*OeeEc-je0dl0vDn^*72Nj>fch#=ji4C9j6;}>UI^1BZQO2vvO&)zWW`I-8q zCaKrXu*UtU3^EmfSMSvHA zO-tklOPyKi-6NsN&6j#kIoY_9PDjD0NTu6iMD&Y({U)PQZz)>U_cAd*_2v33ajRC; zWLdon(Q-#;`6}J}^T7u1^6Gl^!Fea5ma+Q9X<%AM%?~Qs1B=7b*7Lr^j3ZN&`TM;1 zM>CR*kqC(@HtvXx)%EP{hV1rp!>_{~*4iT9-Wp828sQ8$gHrF(4?2+JK7r9Lrz@=d zEPj&DMJY#}>JzNwMMYXI-=n!lBKQ0#bsZ&}2g-2M(uJ&G*K*X-LZ zA}lP>`r<}`qm5O`Xp!Z)HU9?XHW!UQ-gU0kk`*}MzD*KqD5!cS;J@fM&G*0KhA@=5 zx!#2*5Lf;<=2%saRyBLe@}T=;8*0iYG&3Wf_VvfH<&9x- zjaDx`i}Svg#fU0_TFSoVI(&bm0e&rSyuL2{vj0ZNCw9#cM@dpr(lI-Rn)C~9NKlMc zzm56HMMbr60qi+G$N>V7>_1}!r}~j-9)A!c@?328`w5~A5>I2U`0D()Y&)vbm4LpK zjW1Vzi%fQe5`ew~p*nrKM%#_}b!vaC}_r+eJfj5;;yrNuJNxZ#t3^p5LcVuH1O z(3;xi&4OV5N3gNR>bSAM*X7jfYdRS!exe1X9}lq_civ2F3|jEaYtl zQZj{GU!z~bSH4FrZKH90rGpjMnL0vO$=y#Njy9#AAVla6XQe3oECCV<7vQQ;4hRK{ z8R#pXi+Ug>vc0?aec`#73+xqW{R@nIM(!c*LuJi(VdTPg6|>gi4xJ&{#(d_t`E7mO zJB_;J%c5`Z9)KE189AmNOhnz}u?w|?Im9Ro#K`!@wF-e$+J16ezSa(P$^r!7^cN7g zg*aA>rN^K#NsdroJ8`tq7l?*0$-2-IS_!G*n$YwnDp}l<^U*XxS;!6aB#mm5bQC## zq#A#g%bMUA$wRMB5so6?KJS2B0l{7-BvJYfAK;WTfxMj6=UF``C`duTn=>e$`M%njrOI= z+8>8nKBP;)0RiL(hs+ydFv2&24=)e8vrPHkXy#7XTY8RS%*Yk!^o|yVvInHKVKgU3nO#zUGFL_drmXxdppLoHv6ceX zmF3I++RTF&x@hQOr+5bZJg38FqY6(i8BU9HgBvPG_jW(SP+pFFU@XmsC$gv;A27*E zN<|9hq+oWXb<;m`AEl&3Mz=~`YE4UGUb7@ZK|2vvq4?K7XE62B?~AshM_NA(&earW zva}TWL7in>;B5?5Fcx%#m7chX%aNDFp3NsfhdV?2&-NT6Q<*Ehy*HW|_Lz^F>D-zG ztB>KkwxcvZFG*q{;&T53$tjX;Zv;jd`j$C6#tayu+7D%?z)rs*2_hCGgii@Ih zOhgj?E_3DgpJAoULVi^Fje^ShGT+sq$X-*jVg%8FAws8U8D?TAZyd+V`z~*+cB$PJ zpWE0zqo!CoGV0D}S7+15auQDzrM^x~OsrdK-2UBv71Qcga2BA!b? zoTP=h-&OT`rE>JfTeu>nFacADbWzP#)K|*V_&fg<;s0Zk<(vOl&x7ib;WEaUs`dNT z8NRmW<}>BzoNM!+j`=`#81E-OWk4bncn#d7{PN?UI8+ProDyZv`u;VH+^n6a@(01B~lwap_#-uSGzU6P~C z?Awb+$d)?NX7z`V*I%i}F_p~|(Z=d~w>whWPOI<(2$KE7aWyyj6tRISe6j%#2u=mb zAwlh0;2A&CxlMVIQv?|G?4^!8nTMxF8Z07j9R>u#9Bn#Nxc*24LXRH+RQPiKTAznt zZIbo_z2peuyx_wvH$fIo#{r#x3L!`zZ*PGY&3W1d7>byI9NBcRLb*$)kE6rPFwZ&7 z3e5Rt`p^ORhB<+iqRA0VWsf1h{LDSdyZUk!1bG4PF5{Nsl=TbMy8!G>l;W9S{Ox%~xkNGaAsq6^Pjk1OSs$;FL3o%roao2$S>@8F{_}Fi5 zbQ8GzaA9%rtnt8yVLY9brvhQZgt)8+Lm8Q!o&A|=eB6R!B^hf-KB20j0;f|UG>`9W zZ=+lbnxs2$s#)*9y*7W>t!V$ke R+)6HBY;faRG4lTN{{e4=7E=HK 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 index d583140348966d345f223c002abb7efb899f071e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3955 zcmV-(4~+1MP)~Z4)94tK~#90?V3MmBujqBKU&w_*5Zb(2OV@E@C1Xeg9#?sU;+gb zC{VD$7%ottU=16LL4kq|6udye2Ex2Rm<=}AK*0tAZ=hhoGANip!2|-&!5I1u1&tZF zen<0Ot!b>%yLvkgs=K;pG?Er`?+kaZK$`BJ>Ri91n=>A4;{_w0n{V;~Pwe|U5JkV)oXt!E_Ri+jI|$ru=8qCQT#MOSAYm1zi8gW@+jrq{aq!`TDY2yD2fbS zfDnpSJ0=XH1(2(8AJ~;~mUXrk@?4Wl$E0bBHQKMGu#%!M2*87!=h+u6^uEPCGz1!B z?+5(0Tm#7Rlk)g}!&nOfgGG{SgA@{hCeMCHp8bv>{ClD(@=UJ4eu&kzUdHP;n`Pu# zLZLH^1#1kI>RF~SrUbg$LjTvTeV3)(cZ;A{5-jrvpyDv}? z6d3}L@|WnsP|PM66B9)dQc8p{2q72bt{Q$F7K%cXXBm0+Ta3NNnv&swHGf>t=~45< zS@z5R9#W)IHp|j`nYRjHHw@MqhQr~4JSVF@UY6aISA8d?L>nhV3W*et5Ui2U5~kA$ zvsp$_xLs|G`>SMEfAuxcT9YIb(yK|izH2H9Tfo{!Sbjlae^KjIDc59WmSvou|J%X> zc6R>p)`C1ZRs(7Q5P;EW#QFJ%!^1ntpRH&j3Li8w#X1-4QuCAyUSWr zx{W_#?T@7nipt%2*U^l?Z{8fSv-5&ZCtg^@+1VNA=OaM#%{OnEPA5zz|3RLAVt04Q zU@#yI6;Y(v+#C?cF-J#7?Ccnlg`wiZhg0G>rqhWRcI2Ybs2iF0%&S-Xbh}*uwzs#vF)EiJ#2S;y#BZTI*Z$$1 zPM6AzDLqA0=`L$KZ=j9Q$Z9utHSn_B~dKzSpzS}~nYmk%FK$Y#GSeQv||+W*1YwMI~! zHyFEC;{24rvsnT9Hlu}r!^1=N_xB0Ih%C$KcDrnEZ*zWrRth(4ZuZ&VcLsR>{)D}~ zJ@PzbI2>ZFlQEf0h@uEC`{>li$W8I5rK+$*6VZr@xLgFYruHlYwV2!*MhM(2+E>UN-%Q_5-Dp>;)p0+ z!J@TGuxGQyJo=%OZ!(#XWm)M`H1FRZv$wam;P0D^yK6Kvl`jc&Ns=%cjTjDxXstOt zJ@xm^W*J&*+U*woUWfkXb7Y{rE6lQ#^Yam{R?9PgGMR9BIp)KMQ#zerF&zFA0B0Zn zl{EcNtSM^^bAu_aG4=-R+_4-OaU@bD5VGj=?!R%ap~P{|F#;Odb>E^*XhJ; zZuS8eoHjSN{QZ?XS`M_$`|IaP5At0(Y*R)UDt`TI=Qbvj2>{QZ4;Tyvbh}-olw4h< zTu!E>Y2uA@b(PR+#V*~`wR;p%w3xmk>d zOY87HdU;XH052B@P4-nFG_#ath9mDGJTe(Gf-A$RmU#&ogvUlzKiY{q#-gpRZj4 z0wC7V#Wlu&k}fTjQkFW@{gXROj|$xCv&b@L7bA3%cp$<~OnWd`%)u{4%r3?}+uvW3 z*es(L8N3ScCdjL@3Tq8oYtPKf%Sq|}zI8#b%!l(_b8&G-YrRElU6Ljv^1J|GmZr4Y zG5vm@>C`d)<;x*KAel}k=&B`QZ?N28%pAcSW7j-#*3L17L6mN&0@=9^S?*R-2gCbD zIvR0#cu0FNp!0Hw3>8 zkBcHhN{I?2GH?Zh&NWH#8-#p{;0J{GjJ1y#ouAOveZr{4*I)1Bs=kb5I$=6-?!?$f zE`_smu*Rowmd6NgFcyrR6HtTP{99mjom6XVqr$V+kX?+qJUpbgzfZK$^9yYc21LCc zK^WEd3y`6rUHVU*BxK_;?VarfnTw#;_gV`k&%Cj22jj)&l2R`4TwSGPSynE}u}KCl zAW5kxjAOm9Amn3Y*?A}m!+1O*kO4vl?wZcXa*Zi_7FvJj^|h=yzyVR}Z;HCicTBFH zTQ#XlR@cliWml~R!03$e;US$DFNijJx3+Q+MJ)T_>APd}Rl?@Gw_Kf`VzfqnJR?sM zgn;$u15~@ksv!hiy+3isN|9fVF}X%6#rpFtTF(bdK@_^(u4_$}JEyr&=RW3W4H$zI z&P;`vBUp2~n;Qx~VePf=ya5>dh(dpd)}IK1r&uJ`YOF1blClIZ%r!yqqy(BJMmN@0 zD}CE<&d$dGo}tVBa&|HD{(F6+=b317P1UQ=NrFxi5ANjf5E&};Rq9yTZqa$Qk5tMl zm5s;9P|@1jLMTO%rd+*0K_>~_SNjWK$8k)n)k2qz{bgpEBEuA)uwsr8kC3)(nN~g) zS5aGxFQ;t@@+>!~phU|U4|3%;a%~W-l?HaZM@otGeUiHMy1?k=<2*@NZ@7yJxaqsM z9;j-_P_e!ddGNqEz?7o9zmICSn0-8BdVGuw72Ul(EO2#v%;nenY`l5vpDmT5dvHKd z8qW3%K|5x8bmWW{$6m)EP;6}UnNBA@2nNC9lFg9K{u@(VBjj4?C;tX3-NOB5v~@{s z%#Y~e6Iu2>DpW-4e}}b@%~J0+z>pUPW3CB;ugYgCQ~*IB5mGI5IeiK4P`@4hg@AmT z+%7hRr2Tvg6~~xdGd(^o1sU{Jf@;V9p7`Yp&*o@ri|O$(t>**6Ue6olVt3EqCxk@B zaSd|i63SkL(fXF2?RLw7nq_|R)*7-bqtM@BF<4U;Z{{(={0E|VC6j~5XCB@+3-Bd)wV>tE8Vs0S?2}!Lh&K8N z0V7G@J8*u@bN_a!B1RBMqDT>i5lShr#s@^KA=d_7XoPr7 z5J>;$!ER(4RsY&rxjK)o6bsuiQLo44H%D}|ruDpT;uKj%a(qlS9uvQKfdKN-oe04~ zzFj@IxJt?gEau(SA}ZzdRZ2b{d)DXUF|)HX+B@4`-l|kkN=dujA_yc&l2FVvv)S*< zV#5VMR{<^>yh;ZHrBH!H1%HcF5duw;8VdahW9FsdObN1c8BKtlpDtf8$T|gG$U2&% zxrk@``&=F#GJSW<^xZL0uZPjv1KEDQMeDgMy~B13sg(aN>h%^&$sMu?*VZ6IXduJONMx-B49q@5XYjX?3Qh@P2l{!lDKmJ zftnB~(;n4s5ymg-MFOjc<+nD**ZNHs*2PF2eATnA2g{Ttb zcJoDU^Zsf*%RP+c3b0Bg>)26MDzZ^^d!e@l8?4DD$1;Tw4p!TeB!yW^xmciauQWJ=~C%BiK%Whz~ExPJ?tD98Ia~7LbQ2*Sm`LlugX9TO&Y^IOP zz}KJ7-K^?1rm5?}6oo;|W+|7K6HZT0nNBC(4^@*ZYc(TkbHR7@s_z2lA%Gt0BsRfY zC2Lhz@V@h9dCP`hmfHmXp&eQ!8PN##rE5#$kqHD5N-wC!4?2X?u{x8ri5!RQZiLC$t N002ovPDHLkV1iRUmPr5r diff --git a/busybox/docs/busybox.net/images/ltbutton2.png b/busybox/docs/busybox.net/images/ltbutton2.png deleted file mode 100644 index 556f72a6c15c3f53d2ea0f481e7cb425daa863cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6799 zcmV;A8gS)_P)0T3Vw5+Jym)J8G#N}CzaOeQnZ$aa;Tv6PxB+fTO2 zFE0Bb53U+7dXb&P&e#=Cl2N2_B55LOWJ$3`E=iUxkrV-vG8d5G0s;gYz2E(wB@f5y zp;DF1DOA^8&-u^)f8Y22_Z+~96DKN_3II?_;r)gXqLdOs2q6H#7&A>%AJ97*Ap~QL z5Ylhe>vaGql}d~;0MM^sj7`%tO;bOH5W*M(fMFQLVo@KI%VphzZQB6gd7l1tT^9f> z%L0IEwWw6$8q#DDW!&CXxp?6g+f7FMSb6Y z@WBTwl?r1_N~zv&gph8x>$)x>B+qlpvZR!Go)ba_6Vu}=iBY}=;&x1$GXEPinJH>aA}$fAq>N?Z5tt!=Q-y*P17w~wq#kx zIgg^q_kG>7c7&8tN(lf`N+E=l(zb2GFm!JSAw5u%B%bFvj>9?6vMf#0JkJY-0z&9V zKl%|`US4iCn+Fdblv3(<03gdU!!Uv%&?Y8HVi*SJ93doxKp$+{7kQrBwjD*0<2X`E zjByx-mSyF6E`-q0(_JBiOw-guWLY-AAONIk${0(M#BrP;2r$Nu_0A zvQjRWF~)hG51^yX62~!|IdkUv_3KKhD2jBDHD%&BzH#Hm zH@@)=%d%Y8bsVQwtNrw+Kjj~6d7f*?DWy)GIyE&lrM+|T;K5g4eRaUTEX(vfbxV>Y z3`2caN~ycjew0!sNfJd-6h&be_Ika3zn^7U5CntQg%D|)>g(F4gIjSNYh#im5kd^E zr)jF0l_W{4)f!xHHk-F+HHw?oxO-gB==NeX;i2xACaih@~8XD51KnS_6t8u4g zdoUJbOi$9XtSrkc%hK%Aoy2jh2{qu0X_}gDj4{qRV@yja0CYMX{aY*+wTf%F*|tqJ zGPV5b18s4?-_P@0-!)Bh;ORT1bReQSEaT(jk3Rb7`1rV#G6({Vl%b)aTeog4EiLJ& zYUU3O4RtylAw;9m=yto))6*LEcinYY5CmF5&!0cPwzgI-m-9ULJg;7_o2F?PhEnRi z_ukWV(172uV@IV@X|-AxE?m$=&}4L7cYb~z09IC3*4Ni9%hI9kbUItMY@w7Yr8Lo^ zC@PgoQc5^^^5msUm$EF=3f%Aa2gGSMo8SKSw+9)4G4{d>FQjRzALg8k_nU_6>#x7Q zfB$|Rful!{zWCycN~w*FjmI8)Oh?A^Jm2?+hll6p<}Aw^1Yc*n+1c4Q-+WUutJmv& z{_~%Q_p|l%^z=(Fy|li*u9Vu`+PN(zo%P)WGQ=if))^%OR z*k?cc*`=kWMx*hSuYAS#eaCTh$d4R362~#;JV}xyNi?~nl*M8ZYkg*n>1i8=p);J$ z#;sNhA;dY?aM0-hW1J+3RwLcgGzEZKt=4L_w3Sg5xvndvtkr57bUFn_QM9?a$vMXu z&&C&a|eCIow7q)FTo6S3!B7~?`t4gU-siY-Po1}%%w(Vobj(zWY-#dQ% zxK7M@onVHm#h$}3;} z>Q@Vef|OG0OO|EbZWjPJ=elapz4dxM?N*J=Mx&u;qNmjB^>iIDH#hgqZ+`RW(W6FI@qh2zJM4-XFuA#@7Y)q}2U@SUaCz!wOiG)>bqwJb{r zk!6|Ys^d69h$xD*=nj&(es@p^4La1PI!6rdmP(~Pd-f=$3WdVG_ui`u2dzX1AW2>>KK%2a|9oO%qTOz%X{rfQC=>wT zvBw^J{`u#9-(Oi-(HTSAqwA^Pu4+SY@rBczIXw0|U?U!D9Nn6!!xAg=x(1Z}@&Ydfl%dYE| zN~Nt^x1Kn0;tOB+LZi`;QtAMBo<|7z!4H1${qKLj(P#{+{^8+a(=>G+)Ul)kINX^v zwF@}sypM3JiKmM`)1Pa4Y``EVa&wcK5U;5IQw2!rL>ZX|)$Fc55kD}#< zF;=Nm!Z7rGzuj(kyIm<|zuzC!+JjVT7)Gzx+t}F9a9dbdXti2eO5-@zj_CDz#bPlG z!>@hqYfnG@bhTRTcDr#LhheCtx=<)wx^(IB#~**>kw-K=+wJzC!qSsfO3{Jr4Zc1G zBBE0fy#Gl80B^qerVzq$oPn_GT0nDQfQvzInqL}djInaL+-Nj(4XQ`!cDub^uib8I zr`KvV{qdG%+3f7>*x1Z*3)i4!N5mzUSp)})jgq=iBuNs_@wV6)l$$xnXr)KgF8 zdEV`I8DkGU^w1-ZJff6({PD+s^PAsbj60pq@#Du29Xj;&uYbK>uTx63j%ub*O0mR9 z5X1pE#tMKaz+B*5K$f}$Y>Su{Rx$%2hU@|rf&!QXBPo@XQi7Dw>GXIekdR17%q0cD zTp|uwASIw5L>v@gl=HmX?-#P|NOK6_#b}Ac^1bp zGmS#2_!nP%^w_aa?cKZokN)UiRfeik$y~{I-Z}N$-#_2(2gEc|!GVyNCmBxxB!EP( zo_f0<1lxDbA|Y*o%p@%%EW!XA5aaxvi;JhvpBI_*z_k-(8D@yHej1jlwe@BP8#WhW zyk4Iit>1so-51WCJ$H6tv(dts)`mxR&dp8D&ZGq1I{DV(!n+mU>$ck_BlY^kM?d^g zBC*M=&9%n6@19y&y@^dCiFAGM6URSIC}Wg%Za4C7aQgMP@^0YTPCre#!Aj%f#cH+N z4_fO@918@}wCU`gUAuSfTwFYJ?!q}mP!PwK>)BS}lgIw0$(YFbW5 z=yxzuahw*MLa!YZi@wFII1U8}V33KB5lR%!!q}juXW89Gvs(1AK!7onO3h9?M2fne z6aWHTM5#h~7TJ!GWN{D&naZeTSdPncND^Lj3qda|l}Z4z(Oma@hhP>5sb$$2l8Ojw z(j<$Kkd=~;GcmJc2dz84FvV1<9CzazmzQoVp7oN{L&{=Os4NB{5C%j+FdHn_u-fe= zvaHqO(&e?)@JS8{wQrHN@83!+HDb(sN`q6c{n7%Q40&lP!`NN&1zqTEiW6i0s&@V*c4HOM34y#6y-V2 zRdDsj+kf|Le`T%J3nGdm*ZSBW|AFB#Vb~a`TPT=-D9AJllv30&D8bO>VB01m5>$}I zy7fTHE> z*tQ*lz?E5zP&bV)pL{27wGD&ycxIIi6v(nW#e^B;Br6bO8WF zuF{nAl$gwP9EKrJ1wauH<_=1Tpp*fCl_5waY_z~Ih(Spl5d{$TK|*wKxwWuZK-9-5 z3X(l{?PH!LU78TcdEd;H3kFDO#u*R1|lkf+e?K(S;RREDuxbb*>_#tnliz|<;wQ5b?0q*9!J;J*1odqHNJ;L?yf!6Lx;ezawVBzf^C5mfRH5xv^p!7FUCO__j`hKgEHH;9m}M| z^y)J(RHm*K^jp}*t^`mHgo(Jm8b|qN6s~s~L*-%#lcCw&!`K|nlyBiKA>1+!?U{Ed zMbrp79T&57b#rsIfm&T7PhFeEkTy0uCaJii_2Q9(1%oPr5tkcposMqat~iC2cEgz3 zvg4kEg`yQDu^}bO^W@a&n-?!rzl2JqwJ@68Jy+i~mnEDrDg~mOJjhiV%9tpyOai6@ ziUIFmf918`EnRT3)b&d?!9(L)$}@EsDYWCXTpog)Lm0#LTWjx~hb#};-RGWr4kP55 zwr^QxB6z2Vql8f7o=^XAdEcyg?C?m@1Ds!3SY+4Qa;5#dH%_ zCO22=2j=|o321iL-+A}cFMeq$)JS`UecP*J#q#bMMY1qU8s{%u_=o40&zxOPVpS-5 z6I&lJoch#k!LtMhr4a4riQ`(V;0c~|v&2BcHW}FL;_{LN@H{UFg3UCn7hOD3?aLU7 zZU)lGa!9g#`TC1L`I(840vIV4kYN;Dufz|30ra|&SFO~xPC}^wCgZ?z&J6+b+=XQMW*r-=>#LQ?@wjB)d;Hkc z-o4;@aC-6APyWyB%1vrw%99Ik|8~~{d(7>ljgx0K&McbE$S@0i-uJd``Q)Py+56|S ztCvF~T73PTnW;)=v)?Cly@bZDl52#`cTd%~RJ<^Lid2!v#8fE*G8e)VUoyHB#H3+^0xi^CU)!sY6MB@ zSQU#xe&cul?FT=yR#r!CyY5#qBp>|TXXuCafyp3AU}kFn$L?QBUp@Ku>EW3aQ?`B^*wvRbAVvRtoOe+C9P1KM!8DUf@wuz z=m`o5oO|{~pE|AqjAtYDiQRYK2Rn8G7@lEvqQIsW706J^M#w-?fgGRSO2@~*GQl;$ zwUcYt-+b?E9=1pJ?^-iRX<`&8{Nqcntev}1p|)kok!r0g((3kc!Ezx}((8*(k9UHZ zv8mo>CzWX5y+`U(+ab)t%PZNLYd`&WkMFA0rJ=$yZ9%`jb=czB>RSu*{wNPZZm_Yb ziJc$XmpN2g)FRB^r=GEwEym6{>hd72nAY3Rym;;W(qwgnWO*nuHaY_1b#UAy z;g$tyQ;>+uAjc{9J$JlVXtZ1B-#B^S=r;Jo#~~F9|LK3c{fn0hX|j8K$JOQrt$Nk^ z6bNJW+HKn|nhA21>j-P@)Y8P>71+5=o?SfoiGrwW7RQPar3d-{(tddVcHoO8JKC%o1C3n zFil0+>dn<6F~=vTlZ>_nojP*g#HWtK^b{Bd@KhQGq67d@LID7Qq`jaIhM^Fco>MHA zAcKCV=Ne8BCTS8y2C5evs8qnT1j%y_W`O{81jWLp*IVs?cOBcy^7yI0ed^X<|4bP6 z^tP>jWvGAaMu(u$`PolD@ zW^-!W7@nKQwrNU{pA}sZ(P4oF<7pIEEHP~?eN&45G#rp;1mc0Yv0Tt ze)Zp8`RyAgUw_rLNh)Nc(<_XR$BMjj^IDp8?>oHj;}88I)F)tg5)uvw?*GDPFE5;V z;qRVl$t(~0c4Q%m7%}GNXKzw;Ici- zJAA-7ejiL#c#aT;6o|qA0EtYIkc?3R07#}Q&eB-& z$fbpC6ZYgpj3DA*Q-A~<1fViN39MdQKEE(My(4J%Ew9$@r5uymmMytV6=cp>6+l65 zLZJdl0C@_obMy2m3mY^?IF_Z+djIN;LVcvwSVINc&H^E&k+ZG4=AcplnM0PWUAi<{ z9g2b;vPd^ioLVV}BgT~nG`hA?uq|40TWL0Q@GihqW-9CUEQ3A!SAUgXz6`BR#8YKk zJ3smH0}uaMULS2spr2r&I2||L9z$GZ9C`P6YIR}Y= z7_hwj>l6QQ=8e}22)9}-=GyxoIC9sg|G?O@8w`?2Ac$fG0+dqX_X~GeVFd)?TCGNf zl0+#6*fLDPIRJ1ITYfdsyS5ksMo1|H5=)5zfyxDdzyN>&jKLDI#1a6sDbSk$fDq`o0!RP_fB^nKi|_wz8>~+2)4?{);37f@q=NSs;;EEM zO7y;u;e%`R000O$fIwi{4j@D(CwCs$H!?CjQmL%1t(R)m%FGN*)`2oWfEc#1#Q@O% zH6j22tgo*NA?Sq*7Zw&47SAj&#!9Z2=XnyvdgC4;q!1_s2qA@#LVy%tDL!b?KQn)I z$MK!MfIIed?%e1h3I-STKKY#s(RaQG00KdzfHA@nZgK8oLX!jq@%s9@X_~jM^|R~O xQp=1e>0>3CNlXKh1mr(iGU$0^WTe~e{vYirxhCCM;qCwc002ovPDHLkV1idL`eOh9 diff --git a/busybox/docs/busybox.net/images/sdsmall.png b/busybox/docs/busybox.net/images/sdsmall.png deleted file mode 100644 index b1024501b624641e42d6e9d1e0b3d597da84d93b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1593 zcmV-92FCe`P)RZwdy$XI-reo)?=(zKEi^NPhln(j zl98jMB0N2OuCH2$hckwTIcsWQqNA6=z`nx5M5Cf|qoKCg*L}LV{r&qVOigCGyc%3w zLRwm-rluZxd1QHcM0j_$(9vmXX-!X0B$Jb(wX{Z&ksKu?8-|4%Yii!#-(Fu}M$5SU z00009a7bBm000XT000XT0n*)m`~Uy|2XskIMF-IZ0uVO?Vs~&a000F1Nkll@j_YVZm zGejV=aPahYAGEVuBmf1Rddl+(|RVF8LX(}gC??i$kwyRc3wLXDe3A@v}SsF zKqQqT6%HDjuG?j6u9*=@GDN@ntxcW{Y+9M}~7(KM6xt^D2Fn(=*6F}ZN{S(be zpaXi?8fj)GDR0n70gHJDecf*%=B2F%oNRnwjg_N$YUg^{N8bV-<3j zw@j@6b2NMQjVO-e=vv;<$14tuj_xAkAG>iJk9U(AopPE`sSdG>&}oZkLPig-@O8uk ziJ0JlLR%lj&>Jox{Yb3io9Kka}DmKBAiybc#Qc=I?Wulzibr4d)BEF+{Go&0#6%m3b$=5+E9ubmfbq$F$ zR|#&TURORCfLt;MOFQH03shfEL=%XK!)~-rYq&CnveKGc3}siLMYX9*ITlrLD(dQv zWUNHpq6$v-4J$2#c^}i<)~Q<{c!p@^xT;Tp5w-%X4vPE<ZKY=`on)7pQ%&>?w~s(uly=8t+u{Eimj@>qMgTE91X9khZcl5izL zq*Jxe7|WruBkFuTn;@PQ4<6s9(`lCs2PLcj2aRtxpes3FU`6Pu``|+licM$J%TUv! zeYB!C68}Um(6okU&}CQL+pD?}dGht<`&WwF_g?+@YBC?PC=aS{qQ{-bUX8`X_tttK z)v~{VcIKF^&0VU~-t!hZJP7Nf{stN@+KQj_x5Xk&*J+wA7EsOj{YHET-6qHiD&_?;CY zBztGX|Lb+H=bqQ|JfG+JKA-U(cX1ZxhD;ZEFG3&?CSxN#ORz_RO_ZJ%d|wEcBZ3`` zla84V1X7XAaQyH*IHt9~X{ZM|J^Q?AB;d~iJ&o@BKp+fkXB$-*29*L%()k*j>C=(V zQ?s#4lXfgY94or6?rOG+E8jiN&M@M-?Rt+(aHC!Ds@Z=XWpl7x>7<;iI%ZNA zgwG3|*RuE^yeTBfE}SPl<^qVhar4+^O4;1Km0brn zCjq8YdSbXcF=lGWx-QoeRAp$}X5;ltz3e@|Nl3Agf2+UGo=+K1%iwB>KeyP<4-~kXT}qwrsc@YBlYd82a&lsP%y=Ww@6M`vg||NwiAdgWzhgA_{V@bD#&cyUclW^1dCUEs|5!^6YB8*MBHYXQwY9--TpeXm}DfQW@Z zBPD#=p}GD2=3G$d0f@-T&BfT;M`Dyo8ykud@bK5K`8zVgc1uuV{K-QjBTZ)4#!8+r&xb~F3{wa6;W1t z3tQWyR`kz*`_mHKjFy&`k%IJTX=xT#R#C{(Z&+gf$m2Ti`HS1z+ZwOTX=!N#*Bke_ zd3f>(gcu{yNMz~4LSGIeBjXDr(KO8td!@spBOU<(Cmb#t%RlRAG$yA(UcXzk;hkInJAh<0$ znij^-g2&_A?Ug_s`}+D|M=L~d8N3evZyd4|!F=UvJGs!1yyQDs=i^jDLDEqvp3}l? zJ?MINb*qX~^1hF4tw+y((6ds~R0d_nQ)43##>m7ZWXzs?eUBTopncAZnI9&}FzCF2 zYh+0ii7%M-`&d>cY|LKc{=;(Z%LDlx+;s@;(};qC0=K#tWGPppT{2ks&;v@1hBS0N zzjw1vIg6CS}qiv{KlqoommsBw2iLrt(q?7>m<1f^E+NA zslB;4=3ATM=Iz)d|Cyq-Ox+!RB)451TWu|S2AP@(P0ybY=9qJN1Dz4)=&DziHv>P7 zxgO6#n*~|vzYh=V+1OleY;4TE>K6|eY{^n_`ny{m);Bph>0iA4{ml*W%J?KvXj$pO zVz0}%OWysGe|}vF#S<9W{1>wnA(O0z%q=Ej*c%)#X*A%3fXEV%&xxrw!VMI z&hGiplHMhKfE~}e2Wc4@?DRB7grSx3ssv|M6H)foCEo(Fvo#VaoNgkuCekuHE6mBs z$<0XXm|Iz?+>r>{u&}V8m}Tl*h5S16X;A&r#fNG+0>5X?OieuxcODIQi92Xls^MrN zW)(uHm@1>8^eV~E3rJYwm2rIog6@qy<;s@7!l=mm++2e&3$o2Xi(*jwJ#PD*b%(=1uiPD+Ho? zN#p#>KI~%`7xgDokE`7G(=9~8wh-_l@~6{-#rH5T>KE!TDkE`r4AQ2;*B5=*%JO1z z%}<%Hf_t#er@hQpB*O@8=+AaW*);${qN zw4>2!S>Fe&1!fa4!rc!8>Ryt99F~y{K|FV*5iI=eNAn8jB<-FXq@q1pXP&Z1;Ij!A^1#it8`K*8;OwG)|sJEhDfVHP^%W@eR z8DQv(h(tUflJSWN%0YV`l%^$i#Va=a{w1C-{z-v`bej`3BuAq6)`uFXk0AUiUZ=r3 zYQ!SeRqZB>->L3P4m$W684mH2j#5$>>M~$D8PjxKeL6NkZ(AE~UZ_(}!3VDX zZ|y-{5q>W+YJq=#@rXTD%Z`jR$n?Br*PB7ghCHTmV z3x~5{VkzvG=t>RJe5^*RaIKmwBO{ae{5inxyAL0}+E=)a5m@UuC+ix6_oai_!VeCD zK*bfg8Sf$xl>j|p>XD@x@$naXu`1!SuU1qg#~58MG*Nu=c)8K_&3PGwJnY`aL+^vS zL;j#=9Sy1E|7aN)J_-g4oaf$N-MOwD@R6L5kkGKzEpxnA)9e@;YRBcSIygMsjylW}Z4wD)vTDT+kOkItpkS*rNG zTwEOVxW!p@3owR?re>TuVU8q`hrwc_LC!$*fzAQgf+0#^ zBPq?>qBRY@zp7k%c`siE&F)^r{X6vIW2Q?=O3I0~KFgx$ zX6E-L-{T#Eb_bTYIVW)XGFj^|HX?#b)OdDpbpi~2=oUWj=PvGGh9%6%$!W28iKA&RJ z%2AmZa`Q%ip3~l}{sE14rbwzezV8(Aj^XWq(8OZjrwHeSj>v&U-I9^5so?dB;C*)> znwo(dZz{8XutcGCQ$^<=u>9()C@W(w8TmjX{kRGlv{^-&&=K-vqoGPSDcX?>yykN5 za+1N*G1t(ar`nb97fHNw5ScMq%sQ@HIH392S0Q-BFHW^vhi&3|B_odkjz>mD{{9Os zAWH%V3X0%n94<(IiIY=mmqDQc0>5_;3fy2Pf3PX}@B8;sgOA2aS!kawtF@J))pC?_ z`t*d^fRnMdwbd`Otf;N+0>bBBW1|U|l>LS70rnIy)w9`Idtkk#6cjq`D>hD!)&U-YwH$apSakklcGJUeA9v>ec+c|f}U4@3p1t66rUtob8*CupC zQBdm4uQt5fdI?=Qw#v75u$QN?wdFHg2O%NLHq*lV$>rB7E3IW!)z$GNjM@{bQbdVf zgu44Adp}g=1qE8{N)Z`d^#_{d z|K(Li1{Yw@8BcEDWps7Vx!2@?5=6(uu<56qqhsFaRT;2Ap>DzW3H9~abDd!MPowe~ zTSc)+LGd&br*o!M6I$Je9$$BMRGkK1|Lg74^jTnxfTNuZ@1L3hdobIlK7HKVdHelc z8fq$Z(vn8l39R{eUO{`i^_0TO95c^gocfl63bXxCUXIH7-*H$_?fm>HgkRaIFr}&Z RIrtX?VythjS9Sv(`F~ZGgO~sS diff --git a/busybox/docs/busybox.net/index.html b/busybox/docs/busybox.net/index.html deleted file mode 100644 index e606238d4..000000000 --- a/busybox/docs/busybox.net/index.html +++ /dev/null @@ -1,394 +0,0 @@ - - - - -BusyBox - - - - - - - -
- - - - -
- - B u s y B o x - -
- BusyBox
- - - - - - - - - - - - - -
- - The Swiss Army Knife of Embedded Linux - -
- -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 is now maintained by - -Erik Andersen, and its ongoing development is being sponsored by -Lineo. -

-BusyBox is licensed under the -GNU GENERAL PUBLIC LICENSE. -

- - -

Screenshot

- -

Because everybody loves screenshots, a screenshot of BusyBox -is now available right here. - - -

Mailing List Information

-BusyBox now has a mailing list! -To subscribe, go and visit this page. - - - -
- - - Latest News - - -
- -
    - -
  • 23 August 2001 -- BusyBox 0.60.1 released -
    - - 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 too - 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. -

    - The - changelog has all - the details. As usual BusyBox 0.60.1 can be downloaded from - ftp://oss.lineo.com/busybox. -

    Have Fun! -

    - - -

  • 2 August 2001 -- BusyBox 0.60.0 released -
    - I am very pleased to announce the immediate availability of - BusyBox 0.60.0. I have personally tested this release with libc5, glibc, - and uClibc 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. - -

    - - Those wanting an easy way to test the 0.60.0 release with uClibc can - use User-Mode Linux - to give it a try by downloading and compiling - buildroot.tar.gz. - 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. -

    - Another cool thing is the nifty - BusyBox Tutorial contributed by K Computing. This requires - a ShockWave plugin (or standalone viewer), so you may want to grab the - the GPLed shockwave viewer from here - to view the tutorial. -

    - - Finally, In case you didn't notice anything odd about the - version number of this release, let me point out that this release - is not 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. - -

    - The - changelog has all - the details. As usual BusyBox 0.60.0 can be downloaded from - ftp://oss.lineo.com/busybox. -

    Have Fun! -

    - - -

  • 7 July 2001 -- BusyBox 0.52 released -
    - - 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 many 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). - -

    - The - changelog 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 - ftp://oss.lineo.com/busybox. -

    Have Fun! -

    - - -

  • 10 April 2001 - Graph of Busybox Growth -
    - 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 right here. - -

    (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.) -

    - - - -

  • Old News -
    - For the old news, visit the old news page. -
- - - - -
- - Download - -
-
    - -
  • Source for the latest release can always be downloaded from - ftp://oss.lineo.com/busybox. - -
  • A new snapshot of the source is made daily and is available as a GNU - gzipped tarball right here. - -
  • BusyBox now has its own publically browsable - CVS tree, - anonymous - CVS access, and - for those that are actively contributing there is even - CVS write access. - -
- - - - -
- - Documentation - -
-Current documentation for BusyBox includes: -
    -
  • BusyBox.html. - 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 lot of time updating these docs and trying to - make them fairly comprehensive. If you find any errors (factual, - grammatical, whatever) please let me know. -
  • README. - This is the README file included in the busybox source release. -
  • BusyBox Bugs. - Need to report a bug? Need to check if a bug has been filed? -
  • If you need more help, the BusyBox - mailing list is - a good place to start. -
- - - - -
- - - Important Links - - -
- - - - - - -
- - Products/Projects Using BusyBox - -
- -

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: - -

- -

Do you use BusyBox? I'd love to know about it and I'd be happy to link to -you. - - - - - -

- - - - -
- - - - - - - - - - - - - - - -
- - Mail all comments, insults, suggestions and bribes to - Erik Andersen
- The Busybox logo is copyright 1999,2000,2001, Erik Andersen. -
-
- This site created with the vi editor - - Graphics by GIMP - - Linux Today - -

Slashdot -

- Freshmeat -
- - -
- - - diff --git a/busybox/docs/busybox.net/oldnews.html b/busybox/docs/busybox.net/oldnews.html deleted file mode 100644 index d97bb2684..000000000 --- a/busybox/docs/busybox.net/oldnews.html +++ /dev/null @@ -1,465 +0,0 @@ - - - - -BusyBox - - - - - - - -
- - - - -
- - B u s y B o x - -
- BusyBox
- - - - - - - - - -
- - - Older BusyBox News - - -
- -
    - -

  • Take me back to the BusyBox web site. -
    - -
  • 10 April 2001 -- BusyBox 0.51 released -
    - - 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. -

    - - 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!). -

    - You can read the - changelog for - complete details. BusyBox 0.51 can be downloaded from - ftp://oss.lineo.com/busybox. -

    Have Fun! -

    - -

  • Busybox Boot-Floppy Image - -

    Because you asked for it, we have made available a Busybox boot floppy - image. Here's how you use it: - -

      - -
    1. - Download the image - -
    2. dd it onto a floppy like so: dd if=busybox.floppy.img - of=/dev/fd0 ; sync - -
    3. Pop it in a machine and boot up. - -
    - -

    If you want to look at the contents of the initrd image, do this: - -

    -	    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
    -    
    - - -
  • 15 March 2001 -- BusyBox 0.50 released -
    - - 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 - changelog. -

    - 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 - Larry Doolittle's website. -

    - - -

  • 27 January 2001 -- BusyBox 0.49 released -
    - - 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 changelog. -

    - 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. -

    - Special Note
    - - 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 Larry's website - and help out if you can. This shell will be included in the next - release of BusyBox. -

    - -

  • 13 December 2000 -- BusyBox 0.48 released -
    - - 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. -

    - The curious can get a list of some of the more interesting changes by reading - the changelog. -

    - Many thanks go out to the many many people that have contributed to - this release, especially Matt Kraai, Larry Doolittle, and Kent Robotti. -

    -

  • 26 September 2000 -- BusyBox 0.47 released -
    - - 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 changelog - for complete details. - - -

  • 11 July 2000 -- BusyBox 0.46 released -
    - - 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 changelog - for complete details. - - -

  • 21 June 2000 -- BusyBox 0.45 released -
    - - 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 changelog for - details). -

    - Also, some exciting infrastructure news! Busybox now has its own - mailing list, - publically browsable - CVS tree, - anonymous - CVS access, and - for those that are actively contributing there is even - CVS write access. - I think this will be a huge help to the ongoing development of BusyBox. -

    - 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. -

    - Many thanks go out to the many people that have contributed to this release - of BusyBox (esp. Pavel Roskin)! - - -

  • 19 April 2000 -- syslogd bugfix -
    - Turns out that there was still a bug in busybox syslogd. - For example, with the following test app: -
    -	#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);
    -	}
    -
    - 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). -

    - Karl M. Hegbloom has created a - fix for the problem. - Thanks Karl! - - -

  • 18 April 2000 -- BusyBox 0.43 released (finally!) -
    - 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 - changelog. - Oh, and as a special bonus, I wrote some fairly comprehensive - documentation, complete with examples and full usage information. - -

    - 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. -

    - - You can grab BusyBox 0.43 tarballs here. - -

  • 9 April 2000 -- BusyBox 0.43 pre release -
    - 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. -

    - The pre-release can be found here. - Please let me know ASAP if you find any bugs. - -

  • 28 March 2000 -- Andersen Baby Boy release -
    - 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). -

    - 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. -

    - 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. - - -

  • 11 February 2000 -- BusyBox 0.42 released -
    - - This is the most solid BusyBox release so far. Many, many - bugs have been fixed. See the -changelog 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. - -

  • 19 January 2000 -- BusyBox 0.41 released -
    - - 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 here. - -

  • 7 January 2000 -- BusyBox 0.40 released -
    - - 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 here. - -

  • 11 December 1999 -- BusyBox Website -
    - 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. - -

  • 10 December 1999 -- BusyBox 0.39 released -
    - 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 here. -

  • 5 December 1999 -- BusyBox 0.38 released -
    - This release includes fixes to tar, cat, ls, dd, rm, umount, find, df, - and make install, and includes new apps syslogd/klogd and logger. -
- - - - -
- - - Important Links - - -
- - - - - - -
-

- - - - -
- - - - - - - - - - - - - - - -
- - Mail all comments, insults, suggestions and bribes to - Erik Andersen
- The Busybox logo is copyright 1999,2000, Erik Andersen. -
-
- This site created with the vi editor - - Graphics by GIMP - - Linux Today - -

Slashdot -

- Freshmeat -
- - - - - diff --git a/busybox/docs/busybox.net/screenshot.html b/busybox/docs/busybox.net/screenshot.html deleted file mode 100644 index 8424fcef6..000000000 --- a/busybox/docs/busybox.net/screenshot.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - Busybox Screenshot! - - - - - - - - -

Busybox Screenshot!

- - - -
- - -
-
-
-$ ./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
-
-$ _
-
-
- -
- - - - - diff --git a/busybox/dos2unix.c b/busybox/dos2unix.c deleted file mode 100644 index cb30c568b..000000000 --- a/busybox/dos2unix.c +++ /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 . - * 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 -#include -#include -#include -#include -#include -#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 index 48c392894..000000000 --- a/busybox/dpkg.c +++ /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 .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 -#include -#include -#include -#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/ 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/ files */ - remove_files = xmalloc(11); - all_control_list(remove_files, package_name); - - /* Create a list of files in /var/lib/dpkg/info/.* 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 .conffile to .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/ 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/.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 index a933c6948..000000000 --- a/busybox/dpkg_deb.c +++ /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 -#include -#include -#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/dumpkmap.c b/busybox/dumpkmap.c deleted file mode 100644 index 22652a5e2..000000000 --- a/busybox/dumpkmap.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini dumpkmap implementation for busybox - * - * Copyright (C) Arne Bernin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -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 */ -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/echo.c b/busybox/echo.c deleted file mode 100644 index 31c031528..000000000 --- a/busybox/echo.c +++ /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 -#include -#include -#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. - * - * 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 index 709fb13a8..000000000 --- a/busybox/editors/sed.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include /* for getopt() */ -#include -#include /* for strdup() */ -#include -#include /* for isspace() */ -#include -#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/examples/bootfloppy/bootfloppy.txt b/busybox/examples/bootfloppy/bootfloppy.txt deleted file mode 100644 index 575c93fcc..000000000 --- a/busybox/examples/bootfloppy/bootfloppy.txt +++ /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 index 399d326d9..000000000 --- a/busybox/examples/bootfloppy/display.txt +++ /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 index ef14ca2cc..000000000 --- a/busybox/examples/bootfloppy/etc/fstab +++ /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 index 4f29b923f..000000000 --- a/busybox/examples/bootfloppy/etc/init.d/rcS +++ /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 index eb3e979ce..000000000 --- a/busybox/examples/bootfloppy/etc/inittab +++ /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 index e9b11e90a..000000000 --- a/busybox/examples/bootfloppy/etc/profile +++ /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 index 03a1a8550..000000000 --- a/busybox/examples/bootfloppy/mkdevs.sh +++ /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 index b59b57af0..000000000 --- a/busybox/examples/bootfloppy/mkrootfs.sh +++ /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 index e25417353..000000000 --- a/busybox/examples/bootfloppy/mksyslinux.sh +++ /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 index 0d8090824..000000000 --- a/busybox/examples/bootfloppy/quickstart.txt +++ /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 index 8d407cad4..000000000 --- a/busybox/examples/bootfloppy/syslinux.cfg +++ /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/inittab b/busybox/examples/inittab deleted file mode 100644 index 8e7e945b3..000000000 --- a/busybox/examples/inittab +++ /dev/null @@ -1,86 +0,0 @@ -# /etc/inittab init(8) configuration for BusyBox -# -# Copyright (C) 1999 by Lineo, inc. Written by Erik Andersen -# , -# -# -# 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: ::: -# -# : 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. -# -# : The runlevels field is completely ignored. -# -# : 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. -# -# : 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/expr.c b/busybox/expr.c deleted file mode 100644 index d6cc82e3e..000000000 --- a/busybox/expr.c +++ /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 . - * - * this program is free software; you can redistribute it and/or modify - * it under the terms of the gnu general public license as published by - * the free software foundation; either version 2 of the license, or - * (at your option) any later version. - * - * this program is distributed in the hope that it will be useful, - * but without any warranty; without even the implied warranty of - * merchantability or fitness for a particular purpose. see the gnu - * general public license for more details. - * - * you should have received a copy of the gnu general public 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 -#include -#include -#include -#include -#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/findutils/find.c b/busybox/findutils/find.c deleted file mode 100644 index e814c97b9..000000000 --- a/busybox/findutils/find.c +++ /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 , - * Reworked by David Douthitt and - * 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 -#include -#include -#include -#include -#include -#include -#include -#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/grep.c b/busybox/grep.c deleted file mode 100644 index 3254868be..000000000 --- a/busybox/grep.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include /* for strerror() */ -#include -#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(®exes[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(®exes[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(®exes[nregexes]); - free(®exes[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/hostid.c b/busybox/hostid.c deleted file mode 100644 index 68a2cc659..000000000 --- a/busybox/hostid.c +++ /dev/null @@ -1,32 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini hostid implementation for busybox - * - * Copyright (C) 2000 Edward Betts . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#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 index d87851509..000000000 --- a/busybox/hostname.c +++ /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 - * - * adjusted by Erik Andersen 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 -#include -#include -#include -#include -#include -#include -#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 index 0e619f80e..000000000 --- a/busybox/hush.c +++ /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 - * - * 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 , . - * 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 /* isalpha, isdigit */ -#include /* getpid */ -#include /* getenv, atoi */ -#include /* strchr */ -#include /* popen etc. */ -#include /* glob, of course */ -#include /* va_list */ -#include -#include -#include /* should be pretty obvious */ - -#include /* ulimit */ -#include -#include -#include - -/* #include */ -/* #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<, 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 ' 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 && nargv[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; inum_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; igl_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) - rdata, 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<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; numlength; 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 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; iquote); - } - /* 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 index 85b288c0c..000000000 --- a/busybox/id.c +++ /dev/null @@ -1,97 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini id implementation for busybox - * - * Copyright (C) 2000 by Randolph Chung - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * 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 -#include -#include -#include -#include - -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 index 5f8b0eed6..000000000 --- a/busybox/ifconfig.c +++ /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, - * - * This program is free software; you can redistribute it - * and/or modify it under the terms of the 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 -#include -#include // strcmp and friends -#include // isdigit and friends -#include /* offsetof */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#ifdef BB_FEATURE_IFCONFIG_SLIP -#include -#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 index 7d7517385..000000000 --- a/busybox/include/applets.h +++ /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 index f79dac8c8..000000000 --- a/busybox/include/busybox.h +++ /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 -#include -#include -#include - -#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")" - -#ifdef DMALLOC -#include "dmalloc.h" -#endif - -#include - - -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/libbb.h b/busybox/include/libbb.h deleted file mode 100644 index 30f0bb9a7..000000000 --- a/busybox/include/libbb.h +++ /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 -#include -#include -#include - -#include - -#ifdef DMALLOC -#include "dmalloc.h" -#endif - -#include - -#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/usage.h b/busybox/include/usage.h deleted file mode 100644 index 4d38c43bb..000000000 --- a/busybox/include/usage.h +++ /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]") " [
]" -#define ifconfig_full_usage \ - "configure a network interface\n\n" \ - "Options:\n" \ - "\t[[-]broadcast [
]] [[-]pointopoint [
]]\n" \ - "\t[netmask
] [dstaddr
]\n" \ - USAGE_SIOCSKEEPALIVE("\t[outfill ] [keepalive ]\n") \ - "\t" USAGE_IFCONFIG_HW("[hw ether
] ") \ - "[metric ] [mtu ]\n" \ - "\t[[-]trailers] [[-]arp] [[-]allmulti]\n" \ - "\t[multicast] [[-]promisc] [txqueuelen ] [[-]dynamic]\n" \ - USAGE_IFCONFIG_MII("\t[mem_start ] [io_addr ] [irq ]\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" \ -" :::\n" \ -"\n" \ -" : \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" \ -" : \n" \ -"\n" \ -" The runlevels field is completely ignored.\n" \ -"\n" \ -" : \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" \ -" : \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" \ - "\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/halt.c b/busybox/init/halt.c deleted file mode 100644 index d66e28d0e..000000000 --- a/busybox/init/halt.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini halt implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * 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 - -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 index 45b510fa1..000000000 --- a/busybox/init/init.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini init implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#ifdef BB_SYSLOGD -# include -#endif - - -/* From */ -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 */ -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 - #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 -#include -#endif - -#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) - -#if __GNU_LIBRARY__ > 5 - #include -#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/reboot.c b/busybox/init/reboot.c deleted file mode 100644 index 35afd74ff..000000000 --- a/busybox/init/reboot.c +++ /dev/null @@ -1,49 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini reboot implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * 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 - -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/install.sh b/busybox/install.sh deleted file mode 100755 index d163a2ef8..000000000 --- a/busybox/install.sh +++ /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/length.c b/busybox/length.c deleted file mode 100644 index 73becd28a..000000000 --- a/busybox/length.c +++ /dev/null @@ -1,13 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#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/arith.c b/busybox/libbb/arith.c deleted file mode 100644 index 04c45ec3d..000000000 --- a/busybox/libbb/arith.c +++ /dev/null @@ -1,263 +0,0 @@ -/* Copyright (c) 2001 Aaron Lehmann - - 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 -#include -#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/concat_path_file.c b/busybox/libbb/concat_path_file.c deleted file mode 100644 index 86dd2fbbf..000000000 --- a/busybox/libbb/concat_path_file.c +++ /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 -#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/fgets_str.c b/busybox/libbb/fgets_str.c deleted file mode 100644 index 33d8d00cc..000000000 --- a/busybox/libbb/fgets_str.c +++ /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 -#include -#include - -/* - * 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/get_last_path_component.c b/busybox/libbb/get_last_path_component.c deleted file mode 100644 index f1ddfbde0..000000000 --- a/busybox/libbb/get_last_path_component.c +++ /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 -#include -#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/gz_open.c b/busybox/libbb/gz_open.c deleted file mode 100644 index ef30ff894..000000000 --- a/busybox/libbb/gz_open.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include -#include -#include -#include -#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/mk_loop_h.sh b/busybox/libbb/mk_loop_h.sh deleted file mode 100755 index 71c987376..000000000 --- a/busybox/libbb/mk_loop_h.sh +++ /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 -# 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, 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 ' - 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 ' -else - echo '#include "real_loop.h"' -fi - -echo '#undef dev_t' - diff --git a/busybox/ln.c b/busybox/ln.c deleted file mode 100644 index 7412a86fd..000000000 --- a/busybox/ln.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#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 index 3fb4e7665..000000000 --- a/busybox/loadacm.c +++ /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 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 index d66500195..000000000 --- a/busybox/loadfont.c +++ /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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 index 4f217d630..000000000 --- a/busybox/loadkmap.c +++ /dev/null @@ -1,89 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini loadkmap implementation for busybox - * - * Copyright (C) 1998 Enrique Zanardi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#define BINARY_KEYMAP_MAGIC "bkeymap" - -/* From */ -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 */ -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 index 9f730915f..000000000 --- a/busybox/logger.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" -#if !defined BB_SYSLOGD - -#define SYSLOG_NAMES -#include - -#else -#include -# 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. - * - * 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 index 0924b2471..000000000 --- a/busybox/logname.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini logname implementation for busybox - * - * Copyright (C) 2000 Edward Betts . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#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/lsmod.c b/busybox/lsmod.c deleted file mode 100644 index 76ed2fdd8..000000000 --- a/busybox/lsmod.c +++ /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 , - * - * Modified by Alcove, Julien Gaulmin and - * Nicolas Ferre 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 index b8c6dd1d8..000000000 --- a/busybox/makedevs.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * public domain -- Dave 'Kill a Cop' Cinege - * - * makedevs - * Make ranges of device files quickly. - * known bugs: can't deal with alpha ranges - */ - -#include -#include -#include -#include -#include -#include -#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 index bb4d115ca..000000000 --- a/busybox/md5sum.c +++ /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 */ -/* Hacked to work with BusyBox by Alfred M. Szmidt */ - -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#if defined HAVE_LIMITS_H -# include -#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 , 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 index e3c160d87..000000000 --- a/busybox/miscutils/adjtimex.c +++ /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 - * - * 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 and Jim Van Zandt - * (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 - * It will autosense if it is built in a busybox environment, based - * on the BB_VER preprocessor macro. - */ - -#include -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -#include -extern int adjtimex(struct timex *buf); -#else -#include -#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 index 8d7a92a28..000000000 --- a/busybox/miscutils/dc.c +++ /dev/null @@ -1,182 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#include -#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 index df7f64d30..000000000 --- a/busybox/miscutils/dutmp.c +++ /dev/null @@ -1,64 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * public domain -- Dave 'Kill a Cop' Cinege - * - * 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 - */ - -#include -#include - -#include -#include -#include -#include -#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/mkdir.c b/busybox/mkdir.c deleted file mode 100644 index 03c49f098..000000000 --- a/busybox/mkdir.c +++ /dev/null @@ -1,64 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mkdir 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 -#include -#include -#include -#include -#include -#include -#include - -#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 index ca217fa23..000000000 --- a/busybox/mkfifo.c +++ /dev/null @@ -1,60 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mkfifo implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#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/mknod.c b/busybox/mknod.c deleted file mode 100644 index b4d4b82a1..000000000 --- a/busybox/mknod.c +++ /dev/null @@ -1,92 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mknod implementation for busybox - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#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 index f72c7009a..000000000 --- a/busybox/mkswap.c +++ /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 - * - added Native Language Support - * - * from util-linux -- adapted for busybox by - * Erik Andersen . I ripped out Native Language - * Support, made some stuff smaller, and fitted for life in busybox. - * - */ - -#include -#include -#include -#include -#include -#include /* for _IO */ -#include -#include /* 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 index bc47d0af0..000000000 --- a/busybox/mktemp.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#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 index 05b40c53f..000000000 --- a/busybox/modprobe.c +++ /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 -#include -#include -#include -#include -#include -#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 index 413af5ce7..000000000 --- a/busybox/modutils/insmod.c +++ /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 - * and Ron Alder - * - * Modified by Bryan Rittmeyer to support SH4 - * and (theoretically) SH3. I have only tested SH4 in little endian mode. - * - * Modified by Alcove, Julien Gaulmin and - * Nicolas Ferre to support ARM7TDMI. Only - * very minor changes required to also work with StrongArm and presumably - * all ARM based systems. - * - * Magnus Damm 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 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 - * - * Based almost entirely on the Linux modutils-2.3.11 implementation. - * Copyright 1996, 1997 Linux International. - * New implementation contributed by Richard Henderson - * Based on original work by Bjorn Ekwall - * Restructured (and partly rewritten) by: - * Bj�rn Ekwall 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 - - 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 - - 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 -#include - - -/* 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/modprobe.c b/busybox/modutils/modprobe.c deleted file mode 100644 index 05b40c53f..000000000 --- a/busybox/modutils/modprobe.c +++ /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 -#include -#include -#include -#include -#include -#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 index 7596d0232..000000000 --- a/busybox/modutils/rmmod.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#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 index 780cddf66..000000000 --- a/busybox/more.c +++ /dev/null @@ -1,217 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini more implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * Latest version blended together by Erik Andersen , - * based on the original more implementation by Bruce, and code from the - * Debian boot-floppies team. - * - * Termios corrects by Vladimir Oleynik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static FILE *cin; - -#ifdef BB_FEATURE_USE_TERMIOS -#include -#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 index af57a7623..000000000 --- a/busybox/mount.c +++ /dev/null @@ -1,498 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mount implementation for busybox - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 - * 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 , . - * 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 , Borrowed utils-linux's - * mount to add loop support. - * - * 2000-04-30 Dave Cinege - * 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 -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#if defined BB_FEATURE_USE_DEVPS_PATCH -# include /* 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 -#include -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/mt.c b/busybox/mt.c deleted file mode 100644 index 49dc70ac6..000000000 --- a/busybox/mt.c +++ /dev/null @@ -1,121 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#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 index b890abf6e..000000000 --- a/busybox/mv.c +++ /dev/null @@ -1,168 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mv implementation for busybox - * - * - * Copyright (C) 2000 by 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 -#include -#include -#include -#include -#include - -#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 index 5335872e5..000000000 --- a/busybox/nc.c +++ /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 -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#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 index 9b7cb645c..000000000 --- a/busybox/networking/nslookup.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#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/route.c b/busybox/networking/route.c deleted file mode 100644 index 9d210af64..000000000 --- a/busybox/networking/route.c +++ /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, - * (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 - * adjustments by Larry Doolittle - */ - -#include -#include -#include -#include -#include // HZ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 index ce82a0ee8..000000000 --- a/busybox/networking/telnet.c +++ /dev/null @@ -1,711 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * telnet implementation for busybox - * - * Author: Tomi Ollila - * 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 - * - * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#if 0 -static const int DOTRACE = 1; -#endif - -#ifdef DOTRACE -#include /* 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 -#else -#include -#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 index 999b5d706..000000000 --- a/busybox/networking/tftp.c +++ /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 */ -/* */ -/* Parts of the code based on: */ -/* */ -/* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre */ -/* and Remi Lefebvre */ -/* */ -/* utftp: Copyright (C) 1999 Uwe Ohse */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ -/* General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* */ -/* ------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 index a3abd0a00..000000000 --- a/busybox/networking/traceroute.c +++ /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 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - /* 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/pidof.c b/busybox/pidof.c deleted file mode 100644 index 50dffd387..000000000 --- a/busybox/pidof.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#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 index 5ca5dd9e0..000000000 --- a/busybox/ping.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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. - * - * 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/poweroff.c b/busybox/poweroff.c deleted file mode 100644 index db20a4572..000000000 --- a/busybox/poweroff.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini poweroff implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * 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 - -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 index d579a9b4e..000000000 --- a/busybox/printf.c +++ /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 */ - - -// 19990508 Busy Boxed! Dave Cinege - -#include -#include -#include -#include -#include -#include -#include -#include -#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/procps/free.c b/busybox/procps/free.c deleted file mode 100644 index 2e34a972c..000000000 --- a/busybox/procps/free.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#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 index 3884ebdf4..000000000 --- a/busybox/procps/kill.c +++ /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 . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#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/uptime.c b/busybox/procps/uptime.c deleted file mode 100644 index 6758d959e..000000000 --- a/busybox/procps/uptime.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#include -#include "busybox.h" - -static const int FSHIFT = 16; /* nr of bits of precision */ -#define FIXED_1 (1<> 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(¤t_secs); - current_time = localtime(¤t_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 index 9e96a5402..000000000 --- a/busybox/ps.c +++ /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 , - * - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 /* 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 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/readlink.c b/busybox/readlink.c deleted file mode 100644 index c46ebd108..000000000 --- a/busybox/readlink.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#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 index 35afd74ff..000000000 --- a/busybox/reboot.c +++ /dev/null @@ -1,49 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini reboot implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * 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 - -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 index ec35bdcde..000000000 --- a/busybox/renice.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Mini renice implementation for busybox - * - * - * Copyright (C) 2000 Dave 'Kill a Cop' Cinege - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#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/rm.c b/busybox/rm.c deleted file mode 100644 index 51c9f4ceb..000000000 --- a/busybox/rm.c +++ /dev/null @@ -1,77 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rm 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 -#include -#include -#include -#include -#include -#include -#include -#include -#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 index cac27cac9..000000000 --- a/busybox/rmdir.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include - -#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/rpm2cpio.c b/busybox/rpm2cpio.c deleted file mode 100644 index 8d639d6ad..000000000 --- a/busybox/rpm2cpio.c +++ /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 /* For ntohl & htonl function */ -#include - -#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 index e65f07b68..000000000 --- a/busybox/scripts/depmod.pl +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/perl -w -# vi: set ts=4: -# Copyright (c) 2001 David Schleef -# Copyright (c) 2001 Erik Andersen -# Copyright (c) 2001 Stuart Hughes -# 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 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 -Copyright (c) 2001 Erik Andersen -Copyright (c) 2001 Stuart Hughes -This program is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. - -=head1 AUTHOR - -David Schleef - -=cut - -# $Id: depmod.pl,v 1.1 2001/07/30 19:32:03 andersen Exp $ - diff --git a/busybox/scripts/mk2knr.pl b/busybox/scripts/mk2knr.pl deleted file mode 100755 index aaf4963b1..000000000 --- a/busybox/scripts/mk2knr.pl +++ /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 index a72e1e2ba..000000000 --- a/busybox/scripts/undeb +++ /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 " -echo " undeb -l package.deb " -echo " undeb -x package.deb /foo/boo " -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 index 376286a6f..000000000 --- a/busybox/scripts/unrpm +++ /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 " -echo " unrpm -x package.rpm /foo/boo " -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 index 709fb13a8..000000000 --- a/busybox/sed.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include /* for getopt() */ -#include -#include /* for strdup() */ -#include -#include /* for isspace() */ -#include -#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/shell/ash.c b/busybox/shell/ash.c deleted file mode 100644 index c0d47559d..000000000 --- a/busybox/shell/ash.c +++ /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 and - * Vladimir Oleynik 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if !defined(FNMATCH_BROKEN) -#include -#endif -#if !defined(GLOB_BROKEN) -#include -#endif - -#ifdef JOBS -#include -#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 -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 . - * 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 = ≈ - 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) "ef; - (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, "", 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("\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); - } - 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 - * 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. - * - * 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 index 16ec2f823..000000000 --- a/busybox/shell/cmdedit.c +++ /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 - * - * Used ideas: - * Adam Rogoyski - * Dave Cinege - * Jakub Jelinek (c) 1995 - * Erik Andersen (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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#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 -# 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 -#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) 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= or PATH=: */ - *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; /* : */ - } 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; /* : */ - } 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 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 -#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 index 83893572a..000000000 --- a/busybox/shell/cmdedit.h +++ /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/lash.c b/busybox/shell/lash.c deleted file mode 100644 index b3f7cb6a8..000000000 --- a/busybox/shell/lash.c +++ /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 , - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#include "cmdedit.h" - -#ifdef BB_LOCALE_SUPPORT -#include -#endif - -#include -#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 ' 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=" - ** 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 index e16d6f304..000000000 --- a/busybox/shell/msh.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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) ℘ -#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) ℘ - (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; itype == 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 - * 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) ℘ - (void) ≈ -#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; iw_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; iw_nword; i++) - DELETE(cl->w_words[i]); - DELETE(cl); - } - for(i=0; iw_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; iw_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; kw_words; - for (i=0; iw_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= 0 && fd < e.iofd); - for (i=0; ih_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 index 3bcab88ee..000000000 --- a/busybox/sleep.c +++ /dev/null @@ -1,38 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini sleep implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#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 index 4f4979cc5..000000000 --- a/busybox/sort.c +++ /dev/null @@ -1,106 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini sort implementation for busybox - * - * - * Copyright (C) 2000 by 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 -#include -#include -#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 index 2e00a496d..000000000 --- a/busybox/stty.c +++ /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 - - Special for busybox ported by Vladimir Oleynik 2001 - - */ - -//#define TEST - -#include -#include -#include - -#include -#include - -#ifndef STDIN_FILENO -# define STDIN_FILENO 0 -#endif - -#ifndef STDOUT_FILENO -# define STDOUT_FILENO 1 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#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 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 ""; - - 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/sync.c b/busybox/sync.c deleted file mode 100644 index ee22ae109..000000000 --- a/busybox/sync.c +++ /dev/null @@ -1,35 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini sync implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#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 index d7b54e9c8..000000000 --- a/busybox/sysklogd/klogd.c +++ /dev/null @@ -1,153 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini klogd implementation for busybox - * - * Copyright (C) 2001 by Gennady Feldman . - * 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 , - * - * Copyright (C) 2000 by Karl M. Hegbloom - * - * "circular buffer" Copyright (C) 2000 by Gennady Feldman - * - * Maintainer: Gennady Feldman 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 -#include -#include /* for our signal() handlers */ -#include /* strncpy() */ -#include /* errno and friends */ -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -# ifdef __alpha__ -# define klogctl syslog -# endif -#else -# include -#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') 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/logread.c b/busybox/sysklogd/logread.c deleted file mode 100644 index d3349625c..000000000 --- a/busybox/sysklogd/logread.c +++ /dev/null @@ -1,144 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * circular buffer syslog implementation for busybox - * - * Copyright (C) 2000 by Gennady Feldman - * - * Maintainer: Gennady Feldman 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 -#include -#include -#include -#include -#include -#include -#include -#include -#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("\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/syslogd.c b/busybox/syslogd.c deleted file mode 100644 index 25bc68f20..000000000 --- a/busybox/syslogd.c +++ /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 , - * - * Copyright (C) 2000 by Karl M. Hegbloom - * - * "circular buffer" Copyright (C) 2001 by Gennady Feldman - * - * Maintainer: Gennady Feldman 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */ -#define SYSLOG_NAMES -#include -#include - -/* 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 -/* 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 -#include -#include - -/* 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 index 90cc2a6ef..000000000 --- a/busybox/tail.c +++ /dev/null @@ -1,251 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tail implementation for busybox - * - * - * Copyright (C) 2001 by 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 -#include -#include -#include -#include -#include -#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 index 389d7f02e..000000000 --- a/busybox/tar.c +++ /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 , - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 (; sizetarFd, "\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 index 439cf7dc5..000000000 --- a/busybox/tee.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * 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 -#include - -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/test.c b/busybox/test.c deleted file mode 100644 index 9c66cbb87..000000000 --- a/busybox/test.c +++ /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 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 -#include -#include -#include -#include -#include -#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 ::= -*/ - -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/touch.c b/busybox/touch.c deleted file mode 100644 index 1718da71e..000000000 --- a/busybox/touch.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#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 index 5b7b8d091..000000000 --- a/busybox/tr.c +++ /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 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 -#include -#include -#include -#include -#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/tty.c b/busybox/tty.c deleted file mode 100644 index 4510c2996..000000000 --- a/busybox/tty.c +++ /dev/null @@ -1,44 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tty implementation for busybox - * - * Copyright (C) 2000 Edward Betts . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#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/uname.c b/busybox/uname.c deleted file mode 100644 index f7e2291a8..000000000 --- a/busybox/uname.c +++ /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 */ - -/* Busyboxed by Erik Andersen */ - -#include -#include -#include -#include -#include - -#if defined (HAVE_SYSINFO) && defined (HAVE_SYS_SYSTEMINFO_H) -# include -#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/update.c b/busybox/update.c deleted file mode 100644 index 27a04ddee..000000000 --- a/busybox/update.c +++ /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 . - * Copyright (c) 1996, 1997, 1999 Torsten Poulin. - * Copyright (c) 2000 by Karl M. Hegbloom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include /* for getopt() */ -#include - -#if __GNU_LIBRARY__ > 5 - #include -#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/usage.c b/busybox/usage.c deleted file mode 100644 index dfea1f96b..000000000 --- a/busybox/usage.c +++ /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 index 4d38c43bb..000000000 --- a/busybox/usage.h +++ /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]") " [
]" -#define ifconfig_full_usage \ - "configure a network interface\n\n" \ - "Options:\n" \ - "\t[[-]broadcast [
]] [[-]pointopoint [
]]\n" \ - "\t[netmask
] [dstaddr
]\n" \ - USAGE_SIOCSKEEPALIVE("\t[outfill ] [keepalive ]\n") \ - "\t" USAGE_IFCONFIG_HW("[hw ether
] ") \ - "[metric ] [mtu ]\n" \ - "\t[[-]trailers] [[-]arp] [[-]allmulti]\n" \ - "\t[multicast] [[-]promisc] [txqueuelen ] [[-]dynamic]\n" \ - USAGE_IFCONFIG_MII("\t[mem_start ] [io_addr ] [irq ]\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" \ -" :::\n" \ -"\n" \ -" : \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" \ -" : \n" \ -"\n" \ -" The runlevels field is completely ignored.\n" \ -"\n" \ -" : \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" \ -" : \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" \ - "\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 index 6023bf430..000000000 --- a/busybox/usleep.c +++ /dev/null @@ -1,38 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini usleep implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#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 index 73de6d1ae..000000000 --- a/busybox/util-linux/dmesg.c +++ /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 - * - added Native Language Support - * - * from util-linux -- adapted for busybox by - * Erik Andersen . I ripped out Native Language - * Support, replaced getopt, added some gotos for redundant stuff. - */ - -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -# ifdef __alpha__ -# define klogctl syslog -# endif -#else -# include -#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 index 5ccd80e79..000000000 --- a/busybox/util-linux/fbset.c +++ /dev/null @@ -1,424 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini fbset implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#include -#include -#include -#include -#include -#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 index 28f5cb68a..000000000 --- a/busybox/util-linux/fdflush.c +++ /dev/null @@ -1,47 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini fdflush implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -#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 index cf25fae6a..000000000 --- a/busybox/util-linux/freeramdisk.c +++ /dev/null @@ -1,65 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * freeramdisk implementation for busybox - * - * Copyright (C) 2000 and written by Emanuele Caratti - * Adjusted a bit by Erik Andersen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#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 index 952968d85..000000000 --- a/busybox/util-linux/fsck_minix.c +++ /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 . - * - * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by - * Andreas Schwab. - * - * 1999-02-22 Arkadiusz Mi�kiewicz - * - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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<> 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 index 95ecba6e6..000000000 --- a/busybox/util-linux/getopt.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * getopt.c - Enhanced implementation of BSD getopt(1) - * Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You 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 Mikiewicz - * ) - * Ported to Busybox - Alfred M. Szmidt - * 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 -#include -#include -#include -#include -#include - -#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 \ */ - *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 index ccc0e85d7..000000000 --- a/busybox/util-linux/mkfs_minix.c +++ /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 -- - * removed getopt based parser and added a hand rolled one. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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<> 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/nfsmount.c b/busybox/util-linux/nfsmount.c deleted file mode 100644 index cd722acc3..000000000 --- a/busybox/util-linux/nfsmount.c +++ /dev/null @@ -1,977 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * nfsmount.c -- Linux NFS mount - * Copyright (C) 1993 Rick Sladkey - * - * This program is free software; you can redistribute 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 : - * Omit the call to connect() for Linux version 1.3.11 or later. - * - * Wed Oct 1 23:55:28 1997: Dick Streefland - * Implemented the "bg", "fg" and "retry" mount options for NFS. - * - * 1999-02-22 Arkadiusz Mi�kiewicz - * - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#undef TRUE -#undef FALSE -#include -#include -#include -#include /* 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 : change errno: - * "after #include 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 index b3d5a51e6..000000000 --- a/busybox/util-linux/nfsmount.h +++ /dev/null @@ -1,242 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * This file was originally generated using rpcgen. - * But now we edit it by hand as needed to make it - * shut up... - */ - -#ifndef _NFSMOUNT_H_RPCGEN -#define _NFSMOUNT_H_RPCGEN - -#include - - -#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 -#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 index ba26b9c58..000000000 --- a/busybox/util-linux/pivot_root.c +++ /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 -#include -#include -#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 index 50be4de8c..000000000 --- a/busybox/util-linux/rdate.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 index ce0e2c6cc..000000000 --- a/busybox/util-linux/swaponoff.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#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 -#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 index 74638d21c..000000000 --- a/busybox/util-linux/umount.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#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 index a4059ddfe..000000000 --- a/busybox/uudecode.c +++ /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 -#include -#include -#include -#include -#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. - * - * 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 index fc037403a..000000000 --- a/busybox/uuencode.c +++ /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 -#include -#include -#include -#include -#include -#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 index 8d7506d0f..000000000 --- a/busybox/vi.c +++ /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 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 textend) { - strcat((char *) msg, "end>textend "); - } - if (dot < text) { - strcat((char *) msg, "dot end) { - strcat((char *) msg, "dot>end "); - } - if (screenbegin < text) { - strcat((char *) msg, "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" - // :! // run 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 - (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 *) "OA", (Byte) VI_K_UP}, // cursor key Up - {(Byte *) "OB", (Byte) VI_K_DOWN}, // cursor key Down - {(Byte *) "OC", (Byte) VI_K_RIGHT}, // Cursor Key Right - {(Byte *) "OD", (Byte) VI_K_LEFT}, // cursor key Left - {(Byte *) "OH", (Byte) VI_K_HOME}, // Cursor Key Home - {(Byte *) "OF", (Byte) VI_K_END}, // Cursor Key End - {(Byte *) "", (Byte) VI_K_UP}, // cursor key Up - {(Byte *) "", (Byte) VI_K_DOWN}, // cursor key Down - {(Byte *) "", (Byte) VI_K_RIGHT}, // Cursor Key Right - {(Byte *) "", (Byte) VI_K_LEFT}, // cursor key Left - {(Byte *) "", (Byte) VI_K_HOME}, // Cursor Key Home - {(Byte *) "", (Byte) VI_K_END}, // Cursor Key End - {(Byte *) "[2~", (Byte) VI_K_INSERT}, // Cursor Key Insert - {(Byte *) "[5~", (Byte) VI_K_PAGEUP}, // Cursor Key Page Up - {(Byte *) "[6~", (Byte) VI_K_PAGEDOWN}, // Cursor Key Page Down - {(Byte *) "OP", (Byte) VI_K_FUN1}, // Function Key F1 - {(Byte *) "OQ", (Byte) VI_K_FUN2}, // Function Key F2 - {(Byte *) "OR", (Byte) VI_K_FUN3}, // Function Key F3 - {(Byte *) "OS", (Byte) VI_K_FUN4}, // Function Key F4 - {(Byte *) "[15~", (Byte) VI_K_FUN5}, // Function Key F5 - {(Byte *) "[17~", (Byte) VI_K_FUN6}, // Function Key F6 - {(Byte *) "[18~", (Byte) VI_K_FUN7}, // Function Key F7 - {(Byte *) "[19~", (Byte) VI_K_FUN8}, // Function Key F8 - {(Byte *) "[20~", (Byte) VI_K_FUN9}, // Function Key F9 - {(Byte *) "[21~", (Byte) VI_K_FUN10}, // Function Key F10 - {(Byte *) "[23~", (Byte) VI_K_FUN11}, // Function Key F11 - {(Byte *) "[24~", (Byte) VI_K_FUN12}, // Function Key F12 - {(Byte *) "[11~", (Byte) VI_K_FUN1}, // Function Key F1 - {(Byte *) "[12~", (Byte) VI_K_FUN2}, // Function Key F2 - {(Byte *) "[13~", (Byte) VI_K_FUN3}, // Function Key F3 - {(Byte *) "[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, " ", 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/wc.c b/busybox/wc.c deleted file mode 100644 index 695e7e7d4..000000000 --- a/busybox/wc.c +++ /dev/null @@ -1,156 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini wc implementation for busybox - * - * Copyright (C) 2000 Edward Betts - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#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 index 59373d1d9..000000000 --- a/busybox/wget.c +++ /dev/null @@ -1,834 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * wget - retrieve a file using HTTP or FTP - * - * Chip Rosenthal Covad Communications - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include - -#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. - * - * 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 index c460ffdd1..000000000 --- a/busybox/which.c +++ /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 , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#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 index c3b1140e6..000000000 --- a/busybox/whoami.c +++ /dev/null @@ -1,44 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini whoami implementation for busybox - * - * Copyright (C) 2000 Edward Betts . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#include -#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 index 48adae90a..000000000 --- a/busybox/xargs.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Mini xargs implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * Remixed by Mark Whitley , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#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 index 7d9596d0b..000000000 --- a/busybox/yes.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini yes implementation for busybox - * - * Copyright (C) 2000 Edward Betts . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 -#include -#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/coreutils/cat.c b/cat.c similarity index 90% rename from busybox/coreutils/cat.c rename to cat.c index aa8528d6a..820b6342e 100644 --- a/busybox/coreutils/cat.c +++ b/cat.c @@ -2,8 +2,8 @@ /* * Mini Cat implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/coreutils/chgrp.c b/chgrp.c similarity index 94% rename from busybox/coreutils/chgrp.c rename to chgrp.c index fbc1036a8..b8ec8fd6c 100644 --- a/busybox/coreutils/chgrp.c +++ b/chgrp.c @@ -3,8 +3,8 @@ * Mini chown/chmod/chgrp implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/coreutils/chmod.c b/chmod.c similarity index 84% rename from busybox/coreutils/chmod.c rename to chmod.c index 9139b3f4d..1d3f33b64 100644 --- a/busybox/coreutils/chmod.c +++ b/chmod.c @@ -3,8 +3,8 @@ * Mini chown/chmod/chgrp implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,18 +44,30 @@ 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, "R")) > 0) { + 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; diff --git a/busybox/coreutils/chown.c b/chown.c similarity index 95% rename from busybox/coreutils/chown.c rename to chown.c index d1e52deda..ae41ec047 100644 --- a/busybox/coreutils/chown.c +++ b/chown.c @@ -3,8 +3,8 @@ * Mini chown/chmod/chgrp implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/coreutils/chroot.c b/chroot.c similarity index 92% rename from busybox/coreutils/chroot.c rename to chroot.c index de6a2ea50..338d9f4af 100644 --- a/busybox/coreutils/chroot.c +++ b/chroot.c @@ -3,8 +3,8 @@ * Mini chroot implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/console-tools/chvt.c b/chvt.c similarity index 95% rename from busybox/console-tools/chvt.c rename to chvt.c index c76e9c780..8136f1c15 100644 --- a/busybox/console-tools/chvt.c +++ b/chvt.c @@ -24,7 +24,7 @@ int chvt_main(int argc, char **argv) if ((argc != 2) || (**(argv + 1) == '-')) show_usage(); - fd = get_console_fd("/dev/console"); + fd = get_console_fd(); num = atoi(argv[1]); if (ioctl(fd, VT_ACTIVATE, num)) perror_msg_and_die("VT_ACTIVATE"); diff --git a/busybox/clear.c b/clear.c similarity index 87% rename from busybox/clear.c rename to clear.c index 503bafa16..ac32c3230 100644 --- a/busybox/clear.c +++ b/clear.c @@ -3,8 +3,8 @@ * Mini clear implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/cmdedit.c b/cmdedit.c similarity index 70% rename from busybox/cmdedit.c rename to cmdedit.c index 16ec2f823..d0dff11ab 100644 --- a/busybox/cmdedit.c +++ b/cmdedit.c @@ -2,14 +2,14 @@ /* * Termios command line History and Editting. * - * Copyright (c) 1986-2001 may safely be consumed by a BSD or GPL license. + * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license. * Written by: Vladimir Oleynik * * Used ideas: * Adam Rogoyski * Dave Cinege * Jakub Jelinek (c) 1995 - * Erik Andersen (Majorly adjusted for busybox) + * Erik Andersen (Majorly adjusted for busybox) * * This code is 'as is' with no warranty. * @@ -43,6 +43,11 @@ #include "busybox.h" + +#define BB_FEATURE_COMMAND_SAVEHISTORY +#define BB_FEATURE_COMMAND_HISTORY 15 + + #ifdef BB_LOCALE_SUPPORT #define Isprint(c) isprint((c)) #else @@ -50,20 +55,16 @@ #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 */ +#endif /* TEST */ #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION #include @@ -86,25 +87,25 @@ # else # include # endif /* TEST */ -#endif /* advanced FEATURES */ - +#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; +#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 #define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) @@ -115,31 +116,30 @@ 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 */ +volatile int cmdedit_termw = 80; /* actual terminal width */ static -volatile int handlers_sets = 0; /* Set next bites: */ +volatile int handlers_sets = 0; /* Set next bites: */ enum { - SET_ATEXIT = 1, /* when atexit() has been called + 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 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 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; /* --- "" - - "" - -"- --""-- --""--- */ +char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ #ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR static char *user_buf = ""; @@ -148,7 +148,7 @@ static int my_euid; #endif #ifdef BB_FEATURE_SH_FANCY_PROMPT -static char *hostname_buf = ""; +static char *hostname_buf; static int num_ok_lines = 1; #endif @@ -162,36 +162,56 @@ static int my_euid; 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 +#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ static void cmdedit_setwidth(int w, int redraw_flg); -static void win_changed(int nsig) +/* 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 }; - static sighandler_t previous_SIGWINCH_handler; /* for reset */ +#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) { - ioctl(0, TIOCGWINSZ, &win); - if (win.ws_col > 0) { - cmdedit_setwidth(win.ws_col, 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 */ + 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 */ + 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 */ + signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */ } static void cmdedit_reset_term(void) @@ -207,18 +227,6 @@ static void cmdedit_reset_term(void) 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 } @@ -229,9 +237,9 @@ static void cmdedit_set_out_char(int next_char) int c = (int)((unsigned char) command_ps[cursor]); if (c == 0) - c = ' '; /* destroy end char? */ + c = ' '; /* destroy end char? */ #ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - if (!Isprint(c)) { /* Inverse put non-printable characters */ + if (!Isprint(c)) { /* Inverse put non-printable characters */ if (c >= 128) c -= 128; if (c < ' ') @@ -274,8 +282,10 @@ static void goto_new_line(void) static inline void out1str(const char *s) { - fputs(s, stdout); + if ( s ) + fputs(s, stdout); } + static inline void beep(void) { putchar('\007'); @@ -287,9 +297,9 @@ static void input_backward(int num) { if (num > cursor) num = cursor; - cursor -= num; /* new cursor (in command, not terminal) */ + cursor -= num; /* new cursor (in command, not terminal) */ - if (cmdedit_x >= num) { /* no to up line */ + if (cmdedit_x >= num) { /* no to up line */ cmdedit_x -= num; if (num < 4) while (num-- > 0) @@ -301,22 +311,22 @@ static void input_backward(int num) int count_y; if (cmdedit_x) { - putchar('\r'); /* back to first terminal pos. */ - num -= cmdedit_x; /* set previous backward */ + 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 */ + 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 */ + cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */ cursor = 0; cmdedit_y = 0; /* new quasireal y */ } @@ -329,6 +339,51 @@ static void parse_prompt(const char *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; @@ -352,8 +407,8 @@ static void parse_prompt(const char *prmt_ptr) if (c == '\\') { const char *cp = prmt_ptr; int l; - - c = process_escape_sequence(&prmt_ptr); + + c = bb_process_escape_sequence(&prmt_ptr); if(prmt_ptr==cp) { if (*cp == 0) break; @@ -363,10 +418,10 @@ static void parse_prompt(const char *prmt_ptr) case 'u': pbuf = user_buf; break; -#endif +#endif case 'h': pbuf = hostname_buf; - if (*pbuf == 0) { + if (pbuf == 0) { pbuf = xcalloc(256, 1); if (gethostname(pbuf, 255) < 0) { strcpy(pbuf, "?"); @@ -395,7 +450,7 @@ static void parse_prompt(const char *prmt_ptr) strcpy(pbuf+1, pwd_buf+l); } break; -#endif +#endif case 'W': pbuf = pwd_buf; cp = strrchr(pbuf,'/'); @@ -408,7 +463,7 @@ static void parse_prompt(const char *prmt_ptr) case 'e': case 'E': /* \e \E = \033 */ c = '\033'; break; - case 'x': case 'X': + case 'x': case 'X': for (l = 0; l < 3;) { int h; buf2[l++] = *prmt_ptr; @@ -433,7 +488,7 @@ static void parse_prompt(const char *prmt_ptr) } break; } - } + } } if(pbuf == buf) *pbuf = c; @@ -454,12 +509,12 @@ static void parse_prompt(const char *prmt_ptr) /* draw promt, editor line, and clear tail */ static void redraw(int y, int back_cursor) { - if (y > 0) /* up to start y */ + 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_end(); /* rewrite */ + printf("\033[J"); /* destroy tail after cursor */ input_backward(back_cursor); } @@ -473,9 +528,9 @@ static void input_delete(void) 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 */ + 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 */ @@ -513,7 +568,7 @@ static void cmdedit_setwidth(int w, int redraw_flg) redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); fflush(stdout); } - } + } } static void cmdedit_init(void) @@ -544,9 +599,9 @@ static void cmdedit_init(void) #endif my_uid = getuid(); my_gid = getgid(); -#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ +#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ handlers_sets |= SET_ATEXIT; - atexit(cmdedit_reset_term); /* be sure to do this only once */ + atexit(cmdedit_reset_term); /* be sure to do this only once */ } } @@ -563,6 +618,20 @@ static int is_execute(const struct stat *st) #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; @@ -570,35 +639,35 @@ static char **username_tab_completion(char *ud, int *num_matches) char *temp; - ud++; /* ~user/... to user/... */ + ud++; /* ~user/... to user/... */ userlen = strlen(ud); - if (num_matches == 0) { /* "~/..." or "~user/..." */ + if (num_matches == 0) { /* "~/..." or "~user/..." */ char *sav_ud = ud - 1; char *home = 0; - if (*ud == '/') { /* "~/..." */ + if (*ud == '/') { /* "~/..." */ home = home_pwd_buf; } else { /* "~user/..." */ temp = strchr(ud, '/'); - *temp = 0; /* ~user\0 */ + *temp = 0; /* ~user\0 */ entry = getpwnam(ud); - *temp = '/'; /* restore ~user/... */ + *temp = '/'; /* restore ~user/... */ ud = temp; if (entry) home = entry->pw_dir; } if (home) { if ((userlen + strlen(home) + 1) < BUFSIZ) { - char temp2[BUFSIZ]; /* argument size */ + char temp2[BUFSIZ]; /* argument size */ /* /home/user/... */ sprintf(temp2, "%s%s", home, ud); strcpy(sav_ud, temp2); } } - return 0; /* void, result save to argument :-) */ + return 0; /* void, result save to argument :-) */ } else { /* "~[^/]*" */ char **matches = (char **) NULL; @@ -610,8 +679,7 @@ static char **username_tab_completion(char *ud, int *num_matches) /* 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); + bb_xasprintf(&temp, "~%s/", entry->pw_name); matches = xrealloc(matches, (nm + 1) * sizeof(char *)); matches[nm++] = temp; @@ -623,7 +691,7 @@ static char **username_tab_completion(char *ud, int *num_matches) return (matches); } } -#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */ +#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */ enum { FIND_EXE_ONLY = 0, @@ -648,11 +716,11 @@ static int path_parse(char ***p, int flags) npth = 0; for (;;) { - npth++; /* count words is + 1 count ':' */ + npth++; /* count words is + 1 count ':' */ tmp = strchr(tmp, ':'); if (tmp) { if (*++tmp == 0) - break; /* : */ + break; /* : */ } else break; } @@ -661,17 +729,17 @@ static int path_parse(char ***p, int flags) tmp = pth; (*p)[0] = xstrdup(tmp); - npth = 1; /* count words is + 1 count ':' */ + npth = 1; /* count words is + 1 count ':' */ for (;;) { tmp = strchr(tmp, ':'); if (tmp) { - (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ + (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ if (*++tmp == 0) - break; /* : */ + break; /* : */ } else break; - (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ + (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ } return npth; @@ -721,20 +789,20 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, /* set dir only */ dirbuf[(pfind - command) + 1] = 0; #ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION - if (dirbuf[0] == '~') /* ~/... or ~user/... */ + if (dirbuf[0] == '~') /* ~/... or ~user/... */ username_tab_completion(dirbuf, 0); #endif /* "strip" dirname in command */ pfind++; paths[0] = dirbuf; - npaths = 1; /* only 1 dir */ + npaths = 1; /* only 1 dir */ } for (i = 0; i < npaths; i++) { dir = opendir(paths[i]); - if (!dir) /* Don't print an error */ + if (!dir) /* Don't print an error */ continue; while ((next = readdir(dir)) != NULL) { @@ -746,17 +814,17 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, /* not see .name without .match */ if (*str_found == '.' && *pfind == 0) { if (*paths[i] == '/' && paths[i][1] == 0 - && str_found[1] == 0) str_found = ""; /* only "/" */ + && 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) + if (stat(found, &st) < 0) goto cont; /* find with dirs ? */ if (paths[i] != dirbuf) - strcpy(found, next->d_name); /* only name */ + strcpy(found, next->d_name); /* only name */ if (S_ISDIR(st.st_mode)) { /* name is directory */ str_found = found; @@ -765,11 +833,11 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, str_found = add_quote_for_spec_chars(found); } else { /* not put found file if search only dirs for cd */ - if (type == FIND_DIR_ONLY) + 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)) + (type == FIND_EXE_ONLY && is_execute(&st))) strcat(str_found, " "); } /* Add it to the list */ @@ -782,7 +850,7 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, closedir(dir); } if (paths != path1) { - free(paths[0]); /* allocated memory only in first member */ + free(paths[0]); /* allocated memory only in first member */ free(paths); } *num_matches = nm; @@ -799,8 +867,8 @@ static int match_compare(const void *a, const void *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)); } + 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) { @@ -814,7 +882,7 @@ static int find_match(char *matchBuf, int *len_with_quotes) for (i = 0;; i++) { int_buf[i] = (int) ((unsigned char) matchBuf[i]); if (int_buf[i] == 0) { - pos_buf[i] = -1; /* indicator end line */ + pos_buf[i] = -1; /* indicator end line */ break; } else pos_buf[i] = i; @@ -827,7 +895,7 @@ static int find_match(char *matchBuf, int *len_with_quotes) int_buf[j] |= QUOT; i++; #ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - if (matchBuf[i] == '\t') /* algorithm equivalent */ + if (matchBuf[i] == '\t') /* algorithm equivalent */ int_buf[j] = ' ' | QUOT; #endif } @@ -870,7 +938,7 @@ static int find_match(char *matchBuf, int *len_with_quotes) } if (command_mode) { collapse_pos(0, i + command_mode); - i = -1; /* hack incremet */ + i = -1; /* hack incremet */ } } /* collapse `command...` */ @@ -887,11 +955,11 @@ static int find_match(char *matchBuf, int *len_with_quotes) collapse_pos(0, i + 1); break; } else - i--; /* hack incremet */ + i--; /* hack incremet */ } /* collapse (command...(command...)...) or {command...{command...}...} */ - c = 0; /* "recursive" level */ + c = 0; /* "recursive" level */ c2 = 0; for (i = 0; int_buf[i]; i++) if (int_buf[i] == '(' || int_buf[i] == '{') { @@ -900,7 +968,7 @@ static int find_match(char *matchBuf, int *len_with_quotes) else c2++; collapse_pos(0, i + 1); - i = -1; /* hack incremet */ + 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)) { @@ -909,7 +977,7 @@ static int find_match(char *matchBuf, int *len_with_quotes) else c2--; collapse_pos(0, i + 1); - i = -1; /* hack incremet */ + i = -1; /* hack incremet */ } /* skip first not quote space */ @@ -945,7 +1013,7 @@ static int find_match(char *matchBuf, int *len_with_quotes) /* 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) == '/' && + while ((int_buf[i] & ~QUOT) == '/' && ((int_buf[i + 1] & ~QUOT) == '/' || (int_buf[i + 1] & ~QUOT) == '~')) { i++; @@ -964,6 +1032,44 @@ static int find_match(char *matchBuf, int *len_with_quotes) 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) { @@ -971,7 +1077,7 @@ static void input_tab(int *lastWasTab) static int num_matches; static char **matches; - if (lastWasTab == 0) { /* free all memory */ + if (lastWasTab == 0) { /* free all memory */ if (matches) { while (num_matches > 0) free(matches[--num_matches]); @@ -980,7 +1086,7 @@ static void input_tab(int *lastWasTab) } return; } - if (*lastWasTab == FALSE) { + if (! *lastWasTab) { char *tmp; int len_found; @@ -988,7 +1094,7 @@ static void input_tab(int *lastWasTab) int find_type; int recalc_pos; - *lastWasTab = TRUE; /* flop trigger */ + *lastWasTab = TRUE; /* flop trigger */ /* Make a local copy of the string -- up * to the position of the cursor */ @@ -1041,7 +1147,7 @@ static void input_tab(int *lastWasTab) beep(); if (!matches) - return; /* not found */ + return; /* not found */ /* sort */ qsort(matches, num_matches, sizeof(char *), match_compare); @@ -1053,11 +1159,11 @@ static void input_tab(int *lastWasTab) *tmp1 = 0; break; } - if (*tmp == 0) { /* have unique */ + if (*tmp == 0) { /* have unique */ free(tmp); return; } - } else { /* one match */ + } else { /* one match */ tmp = matches[0]; /* for next completion current found */ *lastWasTab = FALSE; @@ -1091,49 +1197,92 @@ static void input_tab(int *lastWasTab) * 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() */ + 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'); + showfiles(matches, num_matches); redraw(0, len - sav_cursor); } } } -#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ +#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ -static void get_previous_history(struct history **hp, struct history *p) +#if MAX_HISTORY >= 1 +static void get_previous_history(void) { - if ((*hp)->s) - free((*hp)->s); - (*hp)->s = xstrdup(command_ps); - *hp = p; + if(command_ps[0] != 0 || history[cur_history] == 0) { + free(history[cur_history]); + history[cur_history] = xstrdup(command_ps); + } + cur_history--; } -static inline void get_next_history(struct history **hp) +static int get_next_history(void) { - get_previous_history(hp, (*hp)->n); + 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, @@ -1156,7 +1305,7 @@ enum { * Furthermore, the "vi" command editing keys are not implemented. * */ - + int cmdedit_read_input(char *prompt, char command[BUFSIZ]) { @@ -1164,10 +1313,9 @@ 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 */ + cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ len = 0; command_ps = command; @@ -1176,7 +1324,6 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) 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; @@ -1184,8 +1331,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) # ifndef _POSIX_VDISABLE # define _POSIX_VDISABLE '\0' # endif - new_settings.c_cc[VINTR] = _POSIX_VDISABLE; -#endif + new_settings.c_cc[VINTR] = _POSIX_VDISABLE; command[0] = 0; setTermSettings(0, (void *) &new_settings); @@ -1198,7 +1344,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) while (1) { - fflush(stdout); /* buffered out to fast */ + fflush(stdout); /* buffered out to fast */ if (safe_read(0, &c, 1) < 1) /* if we can't read input then exit */ @@ -1263,24 +1409,33 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) 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 (hp && hp->n && hp->n->s) { - get_next_history(&hp); + if (get_next_history()) 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); + if (cur_history > 0) { + get_previous_history(); goto rewrite_line; } else { beep(); } break; +#endif case 21: /* Control-U -- Clear line before cursor */ if (cursor) { @@ -1288,7 +1443,13 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) 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) @@ -1300,15 +1461,16 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) } switch (c) { #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - case '\t': /* Alt-Tab */ + case '\t': /* Alt-Tab */ input_tab(&lastWasTab); break; #endif +#if MAX_HISTORY >= 1 case 'A': /* Up Arrow -- Get previous command from history */ - if (hp && hp->p) { - get_previous_history(&hp, hp->p); + if (cur_history > 0) { + get_previous_history(); goto rewrite_line; } else { beep(); @@ -1316,21 +1478,16 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) 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(); - } + if (!get_next_history()) break; - /* Rewrite the line with the selected history item */ - rewrite_line: +rewrite_line: /* change command */ - len = strlen(strcpy(command, hp->s)); + 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(); @@ -1366,7 +1523,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) break; } - default: /* If it's regular input, do the normal thing */ + 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) { @@ -1378,19 +1535,19 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) } } else #endif - if (!Isprint(c)) /* Skip non-printable characters */ + if (!Isprint(c)) /* Skip non-printable characters */ break; - if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ + if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ break; len++; - if (cursor == (len - 1)) { /* Append if at the end of the line */ + 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 */ + } else { /* Insert otherwise */ int sc = cursor; memmove(command + sc + 1, command + sc, len - sc); @@ -1404,7 +1561,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) break; } - if (break_out) /* Enter is the command terminator, no more input. */ + if (break_out) /* Enter is the command terminator, no more input. */ break; if (c != '\t') @@ -1414,59 +1571,39 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) setTermSettings(0, (void *) &initial_settings); handlers_sets &= ~SET_RESET_TERM; +#if MAX_HISTORY >= 1 /* 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; - + /* 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 (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 (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 } - if(break_out>0) { - command[len++] = '\n'; /* set '\n' */ - command[len] = 0; +#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 */ + input_tab(0); /* strong free */ #endif #if defined(BB_FEATURE_SH_FANCY_PROMPT) free(cmdedit_prompt); @@ -1477,13 +1614,12 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) -#endif /* BB_FEATURE_COMMAND_EDITING */ +#endif /* BB_FEATURE_COMMAND_EDITING */ #ifdef TEST -const char *applet_name = "debug stuff usage"; -const char *memory_exhausted = "Memory exhausted"; +const char *bb_applet_name = "debug stuff usage"; #ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT #include @@ -1506,16 +1642,16 @@ int main(int argc, char **argv) #endif while(1) { int l; - cmdedit_read_input(prompt, buff); - l = strlen(buff); - if(l==0) - break; - if(l > 0 && buff[l-1] == '\n') + 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); + printf("*** cmdedit_read_input() returned line =%s=\n", buff); + } else { + break; + } } - printf("*** cmdedit_read_input() detect ^C\n"); + printf("*** cmdedit_read_input() detect ^D\n"); return 0; } -#endif /* TEST */ +#endif /* TEST */ diff --git a/cmdedit.h b/cmdedit.h new file mode 100644 index 000000000..991dafcd1 --- /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/busybox/cmp.c b/cmp.c similarity index 94% rename from busybox/cmp.c rename to cmp.c index 6d579461d..57d83d844 100644 --- a/busybox/cmp.c +++ b/cmp.c @@ -2,9 +2,7 @@ /* * Mini cmp implementation for busybox * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Matt Kraai + * Copyright (C) 1999,2000,2001 by 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 diff --git a/busybox/cp.c b/cp.c similarity index 95% rename from busybox/cp.c rename to cp.c index 82d43adff..696b06ea5 100644 --- a/busybox/cp.c +++ b/cp.c @@ -39,7 +39,7 @@ extern int cp_main(int argc, char **argv) int flags = 0; int i; - while ((opt = getopt(argc, argv, "adfipR")) != -1) + while ((opt = getopt(argc, argv, "adfipRr")) != -1) switch (opt) { case 'a': flags |= FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR; @@ -57,6 +57,9 @@ extern int cp_main(int argc, char **argv) flags |= FILEUTILS_PRESERVE_STATUS; break; case 'R': + flags |= FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS; + break; + case 'r': flags |= FILEUTILS_RECUR; break; default: diff --git a/busybox/archival/cpio.c b/cpio.c similarity index 100% rename from busybox/archival/cpio.c rename to cpio.c diff --git a/busybox/cut.c b/cut.c similarity index 98% rename from busybox/cut.c rename to cut.c index 3ed264870..b60c41e7f 100644 --- a/busybox/cut.c +++ b/cut.c @@ -1,8 +1,8 @@ /* * cut.c - minimalist version of cut * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Mark Whitley , + * Copyright (C) 1999,2000 by Lineo, inc. and Mark Whitley + * Copyright (C) 1999,2000,2001 by Mark Whitley * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/coreutils/date.c b/date.c similarity index 98% rename from busybox/coreutils/date.c rename to date.c index 6db3e2838..41ceee29d 100644 --- a/busybox/coreutils/date.c +++ b/date.c @@ -222,8 +222,8 @@ int date_main(int argc, char **argv) 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, %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') { diff --git a/busybox/dc.c b/dc.c similarity index 100% rename from busybox/dc.c rename to dc.c diff --git a/busybox/coreutils/dd.c b/dd.c similarity index 85% rename from busybox/coreutils/dd.c rename to dd.c index d46db82a0..ecacf64ae 100644 --- a/busybox/coreutils/dd.c +++ b/dd.c @@ -45,7 +45,7 @@ static const struct suffix_mult dd_suffixes[] = { int dd_main(int argc, char **argv) { - int i, ifd, ofd, oflag, sync_flag = FALSE, trunc = TRUE; + 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; @@ -74,6 +74,9 @@ int dd_main(int argc, char **argv) } 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); } @@ -106,8 +109,12 @@ int dd_main(int argc, char **argv) perror_msg_and_die("%s", outfile); if (seek && trunc) { - if (ftruncate(ofd, seek * bs) < 0) - perror_msg_and_die("%s", outfile); + 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; @@ -125,9 +132,19 @@ int dd_main(int argc, char **argv) } 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) - perror_msg_and_die("%s", infile); + 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) diff --git a/busybox/console-tools/deallocvt.c b/deallocvt.c similarity index 96% rename from busybox/console-tools/deallocvt.c rename to deallocvt.c index 15cd0c9b9..b7dcc9e22 100644 --- a/busybox/console-tools/deallocvt.c +++ b/deallocvt.c @@ -21,7 +21,7 @@ int deallocvt_main(int argc, char *argv[]) if (argc > 2) show_usage(); - fd = get_console_fd("/dev/console"); + fd = get_console_fd(); if (argc == 1) { /* deallocate all unused consoles */ diff --git a/busybox/debian/Config.h-deb b/debian/Config.h-deb similarity index 86% rename from busybox/debian/Config.h-deb rename to debian/Config.h-deb index 368b5e97c..7b4157447 100644 --- a/busybox/debian/Config.h-deb +++ b/debian/Config.h-deb @@ -24,7 +24,7 @@ #define BB_CUT //#define BB_DATE //#define BB_DC -#define BB_DD +//#define BB_DD //#define BB_DEALLOCVT #define BB_DF #define BB_DIRNAME @@ -51,7 +51,7 @@ #define BB_HALT #define BB_HEAD //#define BB_HOSTID -//#define BB_HOSTNAME +#define BB_HOSTNAME //#define BB_HUSH #define BB_ID #define BB_IFCONFIG @@ -68,6 +68,7 @@ #define BB_LOADKMAP #define BB_LOGGER //#define BB_LOGNAME +#define BB_LOSETUP #define BB_LS //#define BB_LSMOD //#define BB_MAKEDEVS @@ -117,6 +118,8 @@ #define BB_TEST //#define BB_TELNET //#define BB_TFTP +//#define BB_TIME +//#define BB_TOP #define BB_TOUCH #define BB_TR //#define BB_TRACEROUTE @@ -184,7 +187,7 @@ // 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) +// calculate terminal & column widths (for more, ls, and telnet) #define BB_FEATURE_AUTOWIDTH // // show username/groupnames for ls @@ -205,6 +208,9 @@ // 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 // @@ -228,7 +234,7 @@ // //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 +#define BB_FEATURE_FANCY_TAIL // // Enable support for loop devices in mount #define BB_FEATURE_MOUNT_LOOP @@ -239,6 +245,9 @@ // 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 @@ -262,11 +271,11 @@ // // Enable command line editing in the shell. // Only relevant if a shell is enabled. On by default. -#define BB_FEATURE_COMMAND_EDITING +//#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 +//#define BB_FEATURE_COMMAND_TAB_COMPLETION // // Attempts to match usernames in a ~-prefixed path //#define BB_FEATURE_COMMAND_USERNAME_COMPLETION @@ -292,6 +301,13 @@ // 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 // @@ -316,18 +332,22 @@ // Support for Minix filesystem, version 2 //#define BB_FEATURE_MINIX2 // -// Enable ifconfig status reporting output -- this feature adds 12k. +// 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 +#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) @@ -353,9 +373,12 @@ // Support for the find -perm option. #define BB_FEATURE_FIND_PERM // -// Support for the find -mtine option. +// 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 // @@ -367,15 +390,15 @@ #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 +//#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 @@ -383,6 +406,9 @@ // 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 // // @@ -395,16 +421,10 @@ // mere mortals so leave this stuff alone. // #include -#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ +#if defined(__uClinux__) #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 @@ -422,6 +442,10 @@ #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 diff --git a/busybox/debian/Config.h-static b/debian/Config.h-static similarity index 89% rename from busybox/debian/Config.h-static rename to debian/Config.h-static index 094b1f9b4..879642ccc 100644 --- a/busybox/debian/Config.h-static +++ b/debian/Config.h-static @@ -68,6 +68,7 @@ #define BB_LOADKMAP #define BB_LOGGER #define BB_LOGNAME +#define BB_LOSETUP #define BB_LS #define BB_LSMOD #define BB_MAKEDEVS @@ -78,7 +79,7 @@ #define BB_MKNOD #define BB_MKSWAP #define BB_MKTEMP -//#define BB_MODPROBE +#define BB_MODPROBE #define BB_MORE #define BB_MOUNT //#define BB_MSH @@ -117,6 +118,8 @@ #define BB_TEST #define BB_TELNET #define BB_TFTP +#define BB_TIME +#define BB_TOP #define BB_TOUCH #define BB_TR #define BB_TRACEROUTE @@ -184,7 +187,7 @@ // 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) +// calculate terminal & column widths (for more, ls, and telnet) #define BB_FEATURE_AUTOWIDTH // // show username/groupnames for ls @@ -205,6 +208,9 @@ // 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 // @@ -239,6 +245,9 @@ // 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 @@ -269,7 +278,7 @@ #define BB_FEATURE_COMMAND_TAB_COMPLETION // // Attempts to match usernames in a ~-prefixed path -//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION +#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, @@ -292,11 +301,18 @@ // 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 +#define BB_FEATURE_FBSET_READMODE // // Support insmod/lsmod/rmmod for post 2.1 kernels #define BB_FEATURE_NEW_MODULE_INTERFACE @@ -314,24 +330,28 @@ //#define BB_FEATURE_INSMOD_LOADINKMEM // // Support for Minix filesystem, version 2 -//#define BB_FEATURE_MINIX2 +#define BB_FEATURE_MINIX2 // -// Enable ifconfig status reporting output -- this feature adds 12k. +// 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 +#define BB_FEATURE_IFCONFIG_SLIP // // Enable ifconfig options "mem_start", "io_addr", and "irq". -//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_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 +//#define BB_FEATURE_INSTALLER // // Enable a nifty progress meter in wget (adds just under 2k) #define BB_FEATURE_WGET_STATUSBAR @@ -353,14 +373,17 @@ // Support for the find -perm option. #define BB_FEATURE_FIND_PERM // -// Support for the find -mtine option. +// 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 +#define BB_FEATURE_GREP_CONTEXT // // Support for the EGREP applet (alias to the grep applet) -//#define BB_FEATURE_GREP_EGREP_ALIAS +#define BB_FEATURE_GREP_EGREP_ALIAS // // Tell tftp what commands that should be supported. #define BB_FEATURE_TFTP_PUT @@ -383,6 +406,9 @@ // 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 // // @@ -395,16 +421,10 @@ // mere mortals so leave this stuff alone. // #include -#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ +#if defined(__uClinux__) #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 @@ -422,6 +442,10 @@ #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 diff --git a/busybox/debian/Config.h-udeb b/debian/Config.h-udeb similarity index 90% rename from busybox/debian/Config.h-udeb rename to debian/Config.h-udeb index 4fb0597e2..82ec78427 100644 --- a/busybox/debian/Config.h-udeb +++ b/debian/Config.h-udeb @@ -49,11 +49,11 @@ #define BB_GUNZIP //#define BB_GZIP //#define BB_HALT -//#define BB_HEAD +#define BB_HEAD //#define BB_HOSTID //#define BB_HOSTNAME //#define BB_HUSH -//#define BB_ID +#define BB_ID #define BB_IFCONFIG #define BB_INIT //#define BB_INSMOD @@ -68,6 +68,7 @@ //#define BB_LOADKMAP //#define BB_LOGGER //#define BB_LOGNAME +//#define BB_LOSETUP #define BB_LS #define BB_LSMOD //#define BB_MAKEDEVS @@ -86,7 +87,7 @@ #define BB_MV //#define BB_NC //#define BB_NSLOOKUP -//#define BB_PIDOF +#define BB_PIDOF #define BB_PING #define BB_PIVOT_ROOT //#define BB_POWEROFF @@ -106,7 +107,7 @@ #define BB_SED //#define BB_SETKEYCODES //#define BB_SLEEP -//#define BB_SORT +#define BB_SORT //#define BB_STTY //#define BB_SWAPONOFF #define BB_SYNC @@ -117,7 +118,9 @@ //#define BB_TEST #define BB_TELNET //#define BB_TFTP -//#define BB_TOUCH +//#define BB_TIME +//#define BB_TOP +#define BB_TOUCH #define BB_TR //#define BB_TRACEROUTE #define BB_TRUE_FALSE @@ -127,13 +130,13 @@ //#define BB_UUDECODE #define BB_UMOUNT //#define BB_UNIQ -//#define BB_UNAME +#define BB_UNAME //#define BB_UPDATE //#define BB_UPTIME //#define BB_USLEEP //#define BB_VI //#define BB_WATCHDOG -//#define BB_WC +#define BB_WC #define BB_WGET //#define BB_WHICH //#define BB_WHOAMI @@ -184,7 +187,7 @@ // 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) +// calculate terminal & column widths (for more, ls, and telnet) #define BB_FEATURE_AUTOWIDTH // // show username/groupnames for ls @@ -203,7 +206,10 @@ //#define BB_FEATURE_LS_RECURSIVE // // enable ls -L -//#define BB_FEATURE_LS_FOLLOWLINKS +#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 @@ -239,6 +245,9 @@ // 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 @@ -292,6 +301,13 @@ // 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 // @@ -316,18 +332,22 @@ // Support for Minix filesystem, version 2 //#define BB_FEATURE_MINIX2 // -// Enable ifconfig status reporting output -- this feature adds 12k. +// 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 +#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) @@ -345,7 +365,7 @@ //#define BB_FEATURE_CLEAN_UP // // Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) -//#define BB_FEATURE_HUMAN_READABLE +#define BB_FEATURE_HUMAN_READABLE // // Support for the find -type option. #define BB_FEATURE_FIND_TYPE @@ -353,9 +373,12 @@ // Support for the find -perm option. #define BB_FEATURE_FIND_PERM // -// Support for the find -mtine option. +// 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 // @@ -383,6 +406,9 @@ // 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 // // @@ -395,16 +421,10 @@ // mere mortals so leave this stuff alone. // #include -#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ +#if defined(__uClinux__) #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 @@ -422,6 +442,10 @@ #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 diff --git a/busybox/debian/README.debian b/debian/README.debian similarity index 84% rename from busybox/debian/README.debian rename to debian/README.debian index f210a3e39..a43fde4da 100644 --- a/busybox/debian/README.debian +++ b/debian/README.debian @@ -5,6 +5,6 @@ BusyBox is being developed and maintained by Erik Andersen . If you have a problem with BusyBox, send email to the Debian bug tracking -system that lives at +system that lives at Erik Andersen , Sun, 18 Jun 2000 21:52:00 -0600 diff --git a/busybox/debian/changelog b/debian/changelog similarity index 54% rename from busybox/debian/changelog rename to debian/changelog index 4b719e211..236766e96 100644 --- a/busybox/debian/changelog +++ b/debian/changelog @@ -1,12 +1,138 @@ +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 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 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 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 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 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 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 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 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. - * New stable version released. See changelog for details. - * Teaches 'mount -t auto' to ignore usbdevfs, thanks to - Ethan Benson (closes: #111055) - * Removes all the .o files from the source tarball (oops!) - thanks to Matt Kraai, who noticed. + -- Erik Andersen Thu, 18 Oct 2001 22:59:06 -0600 - -- Erik Andersen Thu, 23 Aug 2001 15:44:14 -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 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 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 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 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 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 Sun, 23 Sep 2001 23:32:15 -0600 busybox (1:0.60.1-1) unstable; urgency=low diff --git a/busybox/debian/control b/debian/control similarity index 95% rename from busybox/debian/control rename to debian/control index 3626718da..92551e721 100644 --- a/busybox/debian/control +++ b/debian/control @@ -21,8 +21,8 @@ Description: Tiny utilities for small and embedded systems. . 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!). + 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 @@ -30,6 +30,7 @@ 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 diff --git a/busybox/debian/copyright b/debian/copyright similarity index 100% rename from busybox/debian/copyright rename to debian/copyright diff --git a/busybox/debian/rules b/debian/rules similarity index 92% rename from busybox/debian/rules rename to debian/rules index 1d7413c35..dd0ffa4d1 100755 --- a/busybox/debian/rules +++ b/debian/rules @@ -42,8 +42,8 @@ install: build #(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/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 @@ -67,8 +67,8 @@ install-static: build #(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/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 @@ -103,6 +103,7 @@ install-udeb: build 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 @@ -130,7 +131,7 @@ busybox: install dh_installdirs dh_installdocs -p$@ $(bbbd)/docs/BusyBox.txt \ $(bbbd)/docs/BusyBox.html docs/style-guide.txt \ - docs/busybox.lineo.com AUTHORS README TODO + AUTHORS README TODO rm -rf `find $(bb) -name CVS` rm -f `find $(bb) -name .cvsignore` dh_installchangelogs -p$@ Changelog @@ -152,7 +153,7 @@ busybox-static: do_static dh_installdirs dh_installdocs -p$@ $(bbsbd)/docs/BusyBox.txt \ $(bbsbd)/docs/BusyBox.html docs/style-guide.txt \ - docs/busybox.lineo.com AUTHORS README TODO + AUTHORS README TODO rm -rf `find $(bbs) -name CVS` rm -f `find $(bbs) -name .cvsignore` dh_installchangelogs -p$@ Changelog diff --git a/busybox/coreutils/df.c b/df.c similarity index 96% rename from busybox/coreutils/df.c rename to df.c index 8cb13fa6d..535ab58fc 100644 --- a/busybox/coreutils/df.c +++ b/df.c @@ -2,8 +2,8 @@ /* * Mini df implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * based on original code by (I think) Bruce Perens . * * This program is free software; you can redistribute it and/or modify diff --git a/busybox/coreutils/dirname.c b/dirname.c similarity index 89% rename from busybox/coreutils/dirname.c rename to dirname.c index b534e6950..387233789 100644 --- a/busybox/coreutils/dirname.c +++ b/dirname.c @@ -2,8 +2,8 @@ /* * Mini dirname implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/dmesg.c b/dmesg.c similarity index 100% rename from busybox/dmesg.c rename to dmesg.c diff --git a/busybox/docs/.cvsignore b/docs/.cvsignore similarity index 100% rename from busybox/docs/.cvsignore rename to docs/.cvsignore diff --git a/busybox/docs/autodocifier.pl b/docs/autodocifier.pl similarity index 95% rename from busybox/docs/autodocifier.pl rename to docs/autodocifier.pl index d753300c1..e6e2b0cd3 100755 --- a/busybox/docs/autodocifier.pl +++ b/docs/autodocifier.pl @@ -193,8 +193,8 @@ =head1 DESCRIPTION slightly different formats -- F, F, and F. This is tedious, so Perl has come to the rescue. -This script was based on a script by Erik Andersen -which was in turn based on a script by Mark Whitley +This script was based on a script by Erik Andersen +which was in turn based on a script by Mark Whitley =head1 OPTIONS @@ -280,8 +280,8 @@ =head1 COPYRIGHT =head1 AUTHOR -John BEPPU +John BEPPU =cut -# $Id: autodocifier.pl,v 1.21 2001/04/17 17:09:34 beppu Exp $ +# $Id: autodocifier.pl,v 1.22 2001/11/19 23:57:54 andersen Exp $ diff --git a/busybox/docs/busybox.sgml b/docs/busybox.sgml similarity index 99% rename from busybox/docs/busybox.sgml rename to docs/busybox.sgml index 2d372506b..3dbd85083 100644 --- a/busybox/docs/busybox.sgml +++ b/docs/busybox.sgml @@ -3881,7 +3881,7 @@ MAINTAINER - Erik Andersen <andersee@debian.org> <andersen@lineo.com> + Erik Andersen <andersee@debian.org> <andersen@codepoet.org> @@ -3902,7 +3902,7 @@ - John Beppu <beppu@lineo.com> + John Beppu <beppu@codepoet.org> @@ -3958,7 +3958,7 @@ - Mark Whitley <markw@lineo.com> + Mark Whitley <markw@codepoet.org> diff --git a/busybox/docs/busybox_footer.pod b/docs/busybox_footer.pod similarity index 92% rename from busybox/docs/busybox_footer.pod rename to docs/busybox_footer.pod index 2ab4e166e..6ba8716f7 100644 --- a/busybox/docs/busybox_footer.pod +++ b/docs/busybox_footer.pod @@ -20,7 +20,7 @@ textutils(1), shellutils(1), etc... =head1 MAINTAINER -Erik Andersen +Erik Andersen =head1 AUTHORS @@ -30,14 +30,14 @@ they know it or not. =for html
-Erik Andersen , +Erik Andersen Tons of new stuff, major rewrite of most of the core apps, tons of new apps as noted in header files. =for html
-John Beppu +John Beppu du, head, nslookup, sort, tee, uniq (so Kraai could rewrite them ;-), documentation @@ -148,7 +148,7 @@ Linus Torvalds =for html
-Mark Whitley +Mark Whitley sed remix, bug fixes, style-guide, etc. @@ -166,4 +166,4 @@ Enrique Zanardi =cut -# $Id: busybox_footer.pod,v 1.4 2001/04/17 17:09:34 beppu Exp $ +# $Id: busybox_footer.pod,v 1.5 2001/11/19 23:57:54 andersen Exp $ diff --git a/busybox/docs/busybox_header.pod b/docs/busybox_header.pod similarity index 99% rename from busybox/docs/busybox_header.pod rename to docs/busybox_header.pod index b80b63143..764d6e35f 100644 --- a/busybox/docs/busybox_header.pod +++ b/docs/busybox_header.pod @@ -71,3 +71,4 @@ usleep, uudecode, uuencode, watchdog, wc, wget, which, whoami, xargs, yes, zcat, =over 4 + diff --git a/busybox/docs/contributing.txt b/docs/contributing.txt similarity index 99% rename from busybox/docs/contributing.txt rename to docs/contributing.txt index 2e0049289..7103d3e2c 100644 --- a/busybox/docs/contributing.txt +++ b/docs/contributing.txt @@ -43,7 +43,7 @@ know. Archives can be found here: - http://opensource.lineo.com/lists/busybox/ + 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 @@ -51,7 +51,7 @@ list. A web-based sign-up form can be found here: - http://opensource.lineo.com/mailman/listinfo/busybox + http://oss.lineo.com/mailman/listinfo/busybox Coordinate with the Applet Maintainer diff --git a/busybox/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt similarity index 97% rename from busybox/docs/new-applet-HOWTO.txt rename to docs/new-applet-HOWTO.txt index 1f5c3ebd5..f79504f78 100644 --- a/busybox/docs/new-applet-HOWTO.txt +++ b/docs/new-applet-HOWTO.txt @@ -132,7 +132,7 @@ The Grand Announcement Then create a diff -urN of the files you added (.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 +busybox@oss.lineo.com. Sending patches as attachments is preferred, but not required. diff --git a/busybox/docs/style-guide.txt b/docs/style-guide.txt similarity index 100% rename from busybox/docs/style-guide.txt rename to docs/style-guide.txt diff --git a/busybox/coreutils/dos2unix.c b/dos2unix.c similarity index 98% rename from busybox/coreutils/dos2unix.c rename to dos2unix.c index cb30c568b..f4ce2b829 100644 --- a/busybox/coreutils/dos2unix.c +++ b/dos2unix.c @@ -30,7 +30,9 @@ #include #include #include +#if (__GNU_LIBRARY__ > 5) #include +#endif #include #include #include "busybox.h" @@ -59,7 +61,7 @@ static int convert(char *fn, int ConvType) if ((in = wfopen(fn, "rw")) == NULL) { return -1; } - strcpy(tempFn, fn); + safe_strncpy(tempFn, fn, sizeof(tempFn)); c = strlen(tempFn); tempFn[c] = '.'; while(1) { diff --git a/busybox/archival/dpkg.c b/dpkg.c similarity index 99% rename from busybox/archival/dpkg.c rename to dpkg.c index 48c392894..4ea4dbac9 100644 --- a/busybox/archival/dpkg.c +++ b/dpkg.c @@ -1141,7 +1141,7 @@ void remove_package(const unsigned int package_num) printf("Removing %s ...\n", package_name); /* run prerm script */ - return_value = run_package_script(package_name, "prem"); + return_value = run_package_script(package_name, "prerm"); if (return_value == -1) { error_msg_and_die("script failed, prerm failure"); } @@ -1280,7 +1280,7 @@ extern int dpkg_main(int argc, char **argv) { deb_file_t **deb_file = NULL; status_node_t *status_node; - char opt = 0; + int opt = 0; int package_num; int dpkg_opt = 0; int deb_count = 0; diff --git a/busybox/archival/dpkg_deb.c b/dpkg_deb.c similarity index 100% rename from busybox/archival/dpkg_deb.c rename to dpkg_deb.c diff --git a/busybox/du.c b/du.c similarity index 64% rename from busybox/du.c rename to du.c index fb649aee5..d2b85b404 100644 --- a/busybox/du.c +++ b/du.c @@ -2,9 +2,9 @@ /* * Mini du implementation for busybox * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu + * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * Copyright (C) 2002 Edward Betts * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,6 +41,8 @@ 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; @@ -60,78 +62,6 @@ static void print_summary(long size, char *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) { @@ -142,6 +72,10 @@ static long du(char *filename) 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); @@ -206,7 +140,7 @@ int du_main(int argc, char **argv) print = print_normal; /* parse argv[] */ - while ((c = getopt(argc, argv, "sl" + while ((c = getopt(argc, argv, "slx" #ifdef BB_FEATURE_HUMAN_READABLE "hm" #endif @@ -218,6 +152,9 @@ int du_main(int argc, char **argv) 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; @@ -247,7 +184,7 @@ int du_main(int argc, char **argv) return status; } -/* $Id: du.c,v 1.50 2001/06/30 17:54:20 andersen Exp $ */ +/* $Id: du.c,v 1.53 2002/09/18 19:21:06 andersen Exp $ */ /* Local Variables: c-file-style: "linux" diff --git a/busybox/console-tools/dumpkmap.c b/dumpkmap.c similarity index 100% rename from busybox/console-tools/dumpkmap.c rename to dumpkmap.c diff --git a/busybox/dutmp.c b/dutmp.c similarity index 94% rename from busybox/dutmp.c rename to dutmp.c index df7f64d30..9b9124a07 100644 --- a/busybox/dutmp.c +++ b/dutmp.c @@ -9,16 +9,16 @@ * little endian on x86. * * Modified to support all sorts of libcs by - * Erik Andersen + * Erik Andersen */ #include #include - #include #include #include #include +#include #include "busybox.h" extern int dutmp_main(int argc, char **argv) @@ -39,7 +39,7 @@ extern int dutmp_main(int argc, char **argv) } /* Kludge around the fact that the binary format for utmp has changed. */ -#if __GNU_LIBRARY__ < 5 || defined __UCLIBC__ +#if __GNU_LIBRARY__ < 5 /* Linux libc5 */ while (read(file, (void*)&ut, sizeof(struct utmp))) { printf("%d|%d|%s|%s|%s|%s|%s|%lx\n", diff --git a/busybox/coreutils/echo.c b/echo.c similarity index 100% rename from busybox/coreutils/echo.c rename to echo.c diff --git a/busybox/env.c b/env.c similarity index 97% rename from busybox/env.c rename to env.c index 8bb690b72..40a6001da 100644 --- a/busybox/env.c +++ b/env.c @@ -21,7 +21,7 @@ * * Original copyright notice is retained at the end of this file. * - * Modified for BusyBox by Erik Andersen , + * Modified for BusyBox by Erik Andersen */ #include diff --git a/busybox/coreutils/expr.c b/expr.c similarity index 100% rename from busybox/coreutils/expr.c rename to expr.c diff --git a/busybox/fbset.c b/fbset.c similarity index 99% rename from busybox/fbset.c rename to fbset.c index 5ccd80e79..8daee6605 100644 --- a/busybox/fbset.c +++ b/fbset.c @@ -384,6 +384,9 @@ extern int fbset_main(int argc, char **argv) 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; diff --git a/busybox/fdflush.c b/fdflush.c similarity index 100% rename from busybox/fdflush.c rename to fdflush.c diff --git a/busybox/find.c b/find.c similarity index 83% rename from busybox/find.c rename to find.c index e814c97b9..46dd91410 100644 --- a/busybox/find.c +++ b/find.c @@ -3,8 +3,8 @@ * Mini find implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * Reworked by David Douthitt and * Matt Kraai . * @@ -51,6 +51,10 @@ 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) { @@ -78,13 +82,20 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk) } #endif #ifdef BB_FEATURE_FIND_MTIME - if (mtime_days != 0) { + 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) && mtime_secs >= file_age && - mtime_secs < file_age + 24 * 60 * 60) || - (mtime_char == '+' && mtime_secs >= file_age) || - (mtime_char == '-' && mtime_secs < file_age))) + 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 @@ -179,6 +190,15 @@ int find_main(int argc, char **argv) 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(); diff --git a/busybox/free.c b/free.c similarity index 67% rename from busybox/free.c rename to free.c index 2e34a972c..4a5469b10 100644 --- a/busybox/free.c +++ b/free.c @@ -2,8 +2,8 @@ /* * Mini free implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,15 +37,30 @@ extern int free_main(int argc, char **argv) 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 ( 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(); @@ -57,13 +72,14 @@ extern int free_main(int argc, char **argv) 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/busybox/freeramdisk.c b/freeramdisk.c similarity index 100% rename from busybox/freeramdisk.c rename to freeramdisk.c diff --git a/busybox/fsck_minix.c b/fsck_minix.c similarity index 100% rename from busybox/fsck_minix.c rename to fsck_minix.c diff --git a/busybox/getopt.c b/getopt.c similarity index 100% rename from busybox/getopt.c rename to getopt.c diff --git a/busybox/findutils/grep.c b/grep.c similarity index 92% rename from busybox/findutils/grep.c rename to grep.c index 3254868be..712d8dce6 100644 --- a/busybox/findutils/grep.c +++ b/grep.c @@ -1,8 +1,8 @@ /* * Mini grep implementation for busybox using libc regex. * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Mark Whitley , + * Copyright (C) 1999,2000 by Lineo, inc. and Mark Whitley + * Copyright (C) 1999,2000,2001 by Mark Whitley * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,6 @@ 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 */ @@ -156,7 +155,7 @@ static void grep_file(FILE *file) if(lines_before) { if(before_buf[curpos]) free(before_buf[curpos]); - before_buf[curpos] = strdup(line); + before_buf[curpos] = xstrdup(line); curpos = (curpos + 1) % lines_before; } } @@ -224,9 +223,10 @@ static void destroy_regexes() /* destroy all the elments in the array */ while (--nregexes >= 0) { - regfree(®exes[nregexes]); - free(®exes[nregexes]); + regfree(&(regexes[nregexes])); } + if (regexes) + free(regexes); } #endif @@ -234,14 +234,19 @@ static void destroy_regexes() extern int grep_main(int argc, char **argv) { int opt; -#ifdef BB_FEATURE_GREP_CONTEXT +#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 */ - if (atexit(destroy_regexes) == -1) - perror_msg_and_die("atexit"); + 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 */ @@ -249,6 +254,9 @@ extern int grep_main(int argc, char **argv) #ifdef BB_FEATURE_GREP_CONTEXT "A:B:C:" #endif +#ifdef BB_FEATURE_GREP_EGREP_ALIAS +"E" +#endif )) > 0) { switch (opt) { case 'i': @@ -281,6 +289,11 @@ extern int grep_main(int argc, char **argv) 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; @@ -294,13 +307,13 @@ extern int grep_main(int argc, char **argv) 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 *)); + 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 **)calloc(lines_before, sizeof(char *)); + before_buf = (char **)xcalloc(lines_before, sizeof(char *)); break; #endif /* BB_FEATURE_GREP_CONTEXT */ default: diff --git a/busybox/gunzip.c b/gunzip.c similarity index 66% rename from busybox/gunzip.c rename to gunzip.c index 430bc630e..5a7b10386 100644 --- a/busybox/gunzip.c +++ b/gunzip.c @@ -7,9 +7,9 @@ * Originally adjusted for busybox by Sven Rudolph * based on gzip sources * - * Adjusted further by Erik Andersen , - * to support files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. + * Adjusted further by Erik Andersen 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 @@ -66,64 +66,35 @@ static char *license_msg[] = { #include #include "busybox.h" -extern int gunzip_main(int argc, char **argv) +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 = stdin; - FILE *out_file = NULL; + FILE *in_file, *out_file; struct stat stat_buf; + const char *delete_path = NULL; + char *out_path = NULL; - 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) + if (path == NULL || strcmp (path, "-") == 0) { + in_file = stdin; flags |= gunzip_to_stdout; + } else { + if ((in_file = wfopen(path, "r")) == NULL) + return -1; - 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 */ + if (flags & gunzip_verbose) { + fprintf(stderr, "%s:\t", path); } - } - - /* 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); + if (stat(path, &stat_buf) < 0) { + error_msg_and_die("Couldn't stat file %s", path); } } @@ -138,10 +109,9 @@ extern int gunzip_main(int argc, char **argv) out_file = stdout; } else { char *extension; - int length = strlen(if_name); + int length = strlen(path); - delete_old_file = TRUE; - extension = strrchr(if_name, '.'); + extension = strrchr(path, '.'); if (extension && strcmp(extension, ".gz") == 0) { length -= 3; } else if (extension && strcmp(extension, ".tgz") == 0) { @@ -149,35 +119,85 @@ extern int gunzip_main(int argc, char **argv) } else { error_msg_and_die("Invalid extension"); } - of_name = (char *) xcalloc(sizeof(char), length + 1); - strncpy(of_name, if_name, length); + out_path = (char *) xcalloc(sizeof(char), length + 1); + strncpy(out_path, path, length); /* Open output file */ - out_file = xfopen(of_name, "w"); + out_file = xfopen(out_path, "w"); /* Set permissions on the file */ - chmod(of_name, stat_buf.st_mode); + chmod(out_path, 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; + if ( !(flags & gunzip_to_stdout )) + delete_path = path; + if (flags & gunzip_verbose) { + fprintf(stderr, "OK\n"); + } } else { /* remove failed attempt */ - delete_file_name = of_name; + delete_path = out_path; } 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); + 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 */ } } - free(of_name); + 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(EXIT_SUCCESS); + return status; } diff --git a/busybox/gzip.c b/gzip.c similarity index 97% rename from busybox/gzip.c rename to gzip.c index 54bb72745..413ebd595 100644 --- a/busybox/gzip.c +++ b/gzip.c @@ -9,7 +9,7 @@ * only standard in to standard out with -9 compression. It also requires * the zcat module for some important functions." * - * Adjusted further by Erik Andersen , + * Adjusted further by Erik Andersen * to support files as well as stdin/stdout, and to generally behave itself wrt * command line handling. * @@ -324,8 +324,6 @@ 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 */ @@ -1219,7 +1217,6 @@ int gzip_main(int argc, char **argv) struct stat statBuf; char *delFileName; int tostdout = 0; - int fromstdin = 0; int force = 0; int opt; @@ -1246,12 +1243,16 @@ int gzip_main(int argc, char **argv) show_usage(); } } - if ((optind == argc) || (strcmp(argv[optind], "-") == 0)) { - fromstdin = 1; - tostdout = 1; + if (optind == argc) { + optind--; + argv[optind] = "-"; } - if (isatty(fileno(stdout)) && tostdout==1 && force==0) + 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; @@ -1269,9 +1270,6 @@ int gzip_main(int argc, char **argv) } #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); @@ -1279,73 +1277,77 @@ int gzip_main(int argc, char **argv) ALLOC(uch, window, 2L * WSIZE); ALLOC(ush, tab_prefix, 1L << BITS); - if (fromstdin == 1) { - strcpy(ofname, "stdin"); + 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 */ - } 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; - } + 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 == 1) { - /* And get to work */ - strcpy(ofname, "stdout"); - outFileNum = fileno(stdout); + if (tostdout) { + /* And get to work */ + strcpy(ofname, "stdout"); + outFileNum = fileno(stdout); - clear_bufs(); /* clear input and output buffers */ - part_nb = 0; + clear_bufs(); /* clear input and output buffers */ + part_nb = 0; - /* Actually do the compression/decompression. */ - zip(inFileNum, outFileNum); + /* Actually do the compression/decompression. */ + zip(inFileNum, outFileNum); - } else { + } else { - /* And get to work */ - strncpy(ofname, ifname, MAX_PATH_LEN - 4); - strcat(ofname, ".gz"); + /* And get to work */ + strncpy(ofname, ifname, MAX_PATH_LEN - 4); + strcat(ofname, ".gz"); - /* Open output fille */ + /* Open output fille */ #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) - outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW); + outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW); #else - outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL); + 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); - } + 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); } diff --git a/busybox/halt.c b/halt.c similarity index 91% rename from busybox/halt.c rename to halt.c index d66e28d0e..8f7cc67e0 100644 --- a/busybox/halt.c +++ b/halt.c @@ -2,8 +2,8 @@ /* * Mini halt implementation for busybox * - * * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ 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"); + long *pid = find_pid_by_name("init"); if (!pid || *pid<=0) { pid = find_pid_by_name("linuxrc"); if (!pid || *pid<=0) diff --git a/busybox/head.c b/head.c similarity index 88% rename from busybox/head.c rename to head.c index 688c250b1..ad21e1b95 100644 --- a/busybox/head.c +++ b/head.c @@ -2,9 +2,8 @@ /* * Mini head implementation for busybox * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu + * Copyright (C) 1999 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +25,7 @@ #include #include #include +#include #include "busybox.h" static int head(int len, FILE *fp) @@ -48,12 +48,17 @@ 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 >= 1) + if (len >= 0) break; /* fallthrough */ default: diff --git a/busybox/coreutils/hostid.c b/hostid.c similarity index 100% rename from busybox/coreutils/hostid.c rename to hostid.c diff --git a/busybox/networking/hostname.c b/hostname.c similarity index 58% rename from busybox/networking/hostname.c rename to hostname.c index d87851509..3cb357afb 100644 --- a/busybox/networking/hostname.c +++ b/hostname.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * $Id: hostname.c,v 1.30 2001/06/26 02:06:08 bug1 Exp $ + * $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 @@ -30,8 +30,12 @@ #include #include #include +#include #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; @@ -48,81 +52,79 @@ static void do_sethostname(char *s, int isfile) } } else { f = xfopen(s, "r"); - fgets(buf, 255, f); + while (fgets(buf, 255, f) != NULL) { + if (buf[0] =='#') { + continue; + } + chomp(buf); + do_sethostname(buf, 0); + } #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; + int opt; + int type = 0; + struct hostent *hp; char *filename = NULL; char buf[255]; - char *s = NULL; + char *p = 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; + 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(); } } - if (argc >= 1) { - do_sethostname(*argv, 0); - } else if (filename != NULL) { - do_sethostname(filename, 1); - } else { + /* Output in desired format */ + if (type != 0) { 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 { + 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/busybox/shell/hush.c b/hush.c similarity index 89% rename from busybox/shell/hush.c rename to hush.c index 0e619f80e..56df5e01d 100644 --- a/busybox/shell/hush.c +++ b/hush.c @@ -9,14 +9,16 @@ * * 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 , . - * 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. + * 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 . 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 @@ -115,6 +117,10 @@ #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, @@ -156,7 +162,8 @@ typedef enum { RES_DO = 9, RES_DONE = 10, RES_XXXX = 11, - RES_SNTX = 12 + RES_IN = 12, + RES_SNTX = 13 } reserved_style; #define FLAG_END (1<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 ' handler */ static int builtin_cd(struct child_prog *child) @@ -1045,11 +1075,14 @@ static void restore_redirects(int squirrel[]) 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]); - putenv(strdup(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 @@ -1316,6 +1349,14 @@ static int run_pipe_real(struct pipe *pi) 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; @@ -1358,10 +1399,28 @@ static int run_pipe_real(struct pipe *pi) export_me=1; } free(name); - set_local_var(child->argv[i], export_me); + 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}; @@ -1377,9 +1436,6 @@ static int run_pipe_real(struct pipe *pi) * 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 */ @@ -1402,7 +1458,8 @@ static int run_pipe_real(struct pipe *pi) } /* XXX test for failed fork()? */ - if (!(child->pid = fork())) { + if (!(child->pid = fork())) + { /* Set the handling for job control signals back to the default. */ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); @@ -1468,19 +1525,97 @@ static int run_pipe_real(struct pipe *pi) static int run_list_real(struct pipe *pi) { - int rcode=0; + 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; - for (;pi;pi=pi->next) { + /* 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) continue; + 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) { @@ -1507,8 +1642,13 @@ static int run_list_real(struct pipe *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; @@ -1892,6 +2032,7 @@ static void initialize_context(struct p_context *ctx) 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 */ } @@ -1918,9 +2059,10 @@ int reserved_word(o_string *dest, struct p_context *ctx) { "elif", RES_ELIF, FLAG_THEN }, { "else", RES_ELSE, FLAG_FI }, { "fi", RES_FI, FLAG_END }, - { "for", RES_FOR, FLAG_DO | FLAG_START }, + { "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 } }; @@ -1933,13 +2075,20 @@ int reserved_word(o_string *dest, struct p_context *ctx) 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<code))) { syntax(); ctx->w = RES_SNTX; - b_reset (dest); + b_reset(dest); return 1; } ctx->w=r->code; @@ -1947,6 +2096,7 @@ int reserved_word(o_string *dest, struct p_context *ctx) 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; @@ -1980,7 +2130,7 @@ static int done_word(o_string *dest, struct p_context *ctx) syntax(); return 1; /* syntax error, groups and arglists don't mix */ } - if (!child->argv) { + 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; } @@ -2000,6 +2150,10 @@ static int done_word(o_string *dest, struct p_context *ctx) } else { child->argv = glob_target->gl_pathv; } + if (ctx->w == RES_FOR) { + done_word(dest,ctx); + done_pipe(ctx,PIPE_SEQ); + } return 0; } @@ -2035,8 +2189,10 @@ static int done_command(struct p_context *ctx) prog->group = NULL; prog->glob_result.gl_pathv = NULL; prog->family = pi; + prog->sp = 0; + ctx->child = prog; + prog->type = ctx->type; - ctx->child=prog; /* but ctx->pipe and ctx->list_head remain unchanged */ return 0; } @@ -2217,32 +2373,32 @@ static int parse_group(o_string *dest, struct p_context *ctx, /* 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) +static char *lookup_param(char *src) { - const char *p=NULL; - if (src->data) { - p = getenv(src->data); + char *p=NULL; + if (src) { + p = getenv(src); if (!p) - p = get_local_var(src->data); + p = get_local_var(src); } - if (p) parse_string(dest, ctx, p); /* recursion */ - b_free(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; - 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)) { + b_addchr(dest, SPECIAL_VAR_SYMBOL); + ctx->child->sp++; while(ch=b_peek(input),isalnum(ch) || ch=='_') { b_getch(input); - b_addchr(&alt,ch); + b_addchr(dest,ch); } - lookup_param(dest, ctx, &alt); + b_addchr(dest, SPECIAL_VAR_SYMBOL); } else if (isdigit(ch)) { i = ch-'0'; /* XXX is $0 special? */ if (ichild->sp++; b_getch(input); /* XXX maybe someone will try to escape the '}' */ while(ch=b_getch(input),ch!=EOF && ch!='}') { - b_addchr(&alt,ch); + b_addchr(dest,ch); } if (ch != '}') { syntax(); return 1; } - lookup_param(dest, ctx, &alt); + b_addchr(dest, SPECIAL_VAR_SYMBOL); break; case '(': b_getch(input); @@ -2338,7 +2496,9 @@ int parse_stream(o_string *dest, struct p_context *ctx, b_addqchr(dest, ch, dest->quote); } else { if (m==2) { /* unquoted IFS */ - done_word(dest, ctx); + 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') @@ -2499,30 +2659,46 @@ void update_ifs_map(void) /* most recursion does not come through here, the exeception is * from builtin_source() */ -int parse_stream_outer(struct in_str *inp) +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'); - done_word(&temp, &ctx); - done_pipe(&ctx,PIPE_SEQ); - run_list(ctx.list_head); + 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); /* loop on syntax errors, return on EOF */ + } 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) +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); + return parse_stream_outer(&input, flag); } static int parse_file_outer(FILE *f) @@ -2530,7 +2706,7 @@ static int parse_file_outer(FILE *f) int rcode; struct in_str input; setup_file_in_str(&input, f); - rcode = parse_stream_outer(&input); + rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON); return rcode; } @@ -2620,7 +2796,7 @@ int hush_main(int argc, char **argv) { global_argv = argv+optind; global_argc = argc-optind; - opt = parse_string_outer(optarg); + opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); goto final_return; } break; @@ -2690,3 +2866,106 @@ int hush_main(int argc, char **argv) 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/busybox/coreutils/id.c b/id.c similarity index 100% rename from busybox/coreutils/id.c rename to id.c diff --git a/busybox/networking/ifconfig.c b/ifconfig.c similarity index 98% rename from busybox/networking/ifconfig.c rename to ifconfig.c index 5f8b0eed6..1986adaa7 100644 --- a/busybox/networking/ifconfig.c +++ b/ifconfig.c @@ -15,7 +15,7 @@ * 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 $ + * $Id: ifconfig.c,v 1.16 2003/11/14 03:04:56 andersen Exp $ * */ @@ -135,13 +135,13 @@ #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_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_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) +#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) @@ -441,6 +441,7 @@ int ifconfig_main(int argc, char **argv) } } LOOP: + continue; } /* end of while-loop */ return goterr; diff --git a/busybox/init.c b/init.c similarity index 55% rename from busybox/init.c rename to init.c index 45b510fa1..7e4145a11 100644 --- a/busybox/init.c +++ b/init.c @@ -4,6 +4,7 @@ * * * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 Erik Andersen * Adjusted by so many folks, it's impossible to keep track. * * This program is free software; you can redistribute it and/or modify @@ -46,7 +47,12 @@ #ifdef BB_SYSLOGD # include #endif +#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) +#include +#endif + +#define INIT_BUFFS_SIZE 256 /* From */ struct vt_stat { @@ -58,44 +64,32 @@ static const int VT_GETSTATE = 0x5603; /* get global vt state info */ /* From */ 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]; + 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 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 - #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 @@ -116,7 +110,6 @@ static const int RB_AUTOBOOT = 0x01234567; 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 */ @@ -125,28 +118,24 @@ static const int RB_AUTOBOOT = 0x01234567; #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; +#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. */ -typedef struct initActionType { +struct init_action_type { const char *name; - initActionEnum action; -} initActionType; + int action; +}; -static const struct initActionType actions[] = { +static const struct init_action_type actions[] = { {"sysinit", SYSINIT}, {"respawn", RESPAWN}, {"askfirst", ASKFIRST}, @@ -154,32 +143,50 @@ static const struct initActionType actions[] = { {"once", ONCE}, {"ctrlaltdel", CTRLALTDEL}, {"shutdown", SHUTDOWN}, + {"restart", RESTART}, {0, 0} }; -/* Set up a linked list of initActions, to be read from inittab */ -typedef struct initActionTag initAction; -struct initActionTag { +/* Set up a linked list of init_actions, to be read from inittab */ +struct init_action { pid_t pid; - char process[256]; - char console[256]; - initAction *nextPtr; - initActionEnum action; + char command[INIT_BUFFS_SIZE]; + char terminal[INIT_BUFFS_SIZE]; + struct init_action *next; + int 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 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 delete_initAction(initAction * action); -static void loop_forever() +static void loop_forever(void) { while (1) sleep (1); @@ -187,8 +194,12 @@ static void loop_forever() /* 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))); +#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; @@ -203,9 +214,7 @@ static void message(int device, char *fmt, ...) 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(); + syslog_msg(LOG_USER, LOG_INFO, msg); } #else static int log_fd = -1; @@ -213,16 +222,12 @@ static void message(int device, char *fmt, ...) /* 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 */ + if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) { 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; + 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)) { @@ -236,8 +241,7 @@ static void message(int device, char *fmt, ...) /* 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) { + device_open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) { va_start(arguments, fmt); vdprintf(fd, fmt, arguments); va_end(arguments); @@ -291,7 +295,7 @@ static void set_term(int fd) /* How much memory does this machine have? Units are kBytes to avoid overflow on 4GB machines */ -static int check_free_memory() +static int check_free_memory(void) { struct sysinfo info; unsigned int result, u, s=10; @@ -312,7 +316,7 @@ static int check_free_memory() return result; } -static void console_init() +static void console_init(void) { int fd; int tried_devcons = 0; @@ -372,19 +376,12 @@ static void console_init() /* 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 */ + /* check for serial console */ 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 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); } @@ -397,7 +394,7 @@ static void fixup_argv(int argc, char **argv, char *new_argv0) /* 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); + safe_strncpy(argv[0], new_argv0, len + 1); /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ len = 1; @@ -407,31 +404,60 @@ static void fixup_argv(int argc, char **argv, char *new_argv0) } } - -static pid_t run(char *command, char *terminal, int get_enter) +/* 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) { - 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[] = +#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__) + struct stat statBuf; +#endif -#ifdef CUSTOMIZED_BANNER -#include CUSTOMIZED_BANNER + 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(); +} - "\nPlease press Enter to activate this console. "; +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=/usr/bin:/bin:/usr/sbin:/sbin", + "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++) { @@ -446,52 +472,113 @@ static pid_t run(char *command, char *terminal, int get_enter) } } - if ((pid = fork()) == 0) { + /* Block sigchild while forking. */ + sigemptyset(&nmask); + sigaddset(&nmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &nmask, &omask); + + if ((pid = fork()) == 0) + { /* Clean up */ - ioctl(0, TIOCNOTTY, 0); close(0); close(1); close(2); - setsid(); + sigprocmask(SIG_SETMASK, &omask, NULL); - /* Reset signal handlers set for parent process */ + /* Reset signal handlers that were set by the parent process */ signal(SIGUSR1, SIG_DFL); signal(SIGUSR2, SIG_DFL); - signal(SIGINT, SIG_DFL); + signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGCONT, SIG_DFL); + signal(SIGSTOP, SIG_DFL); + signal(SIGTSTP, 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); + /* 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, "Bummer, can't open %s\r\n", terminal); - exit(1); + message(LOG | CONSOLE, "\rBummer, can't open %s\n", a->terminal); + _exit(1); } - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - ioctl(0, TIOCSCTTY, 1); - tcsetpgrp(0, getpgrp()); + + /* 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(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { + if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { cmd[0] = SHELL; cmd[1] = "-c"; - strcpy(buf, "exec "); - strncat(buf, command, sizeof(buf) - strlen(buf) - 1); + strcat(strcpy(buf, "exec "), a->command); 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;) { + strcpy(buf, a->command); + s = buf; + for (tmpCmd = buf, i = 0; + (tmpCmd = strsep(&s, " \t")) != NULL;) { if (*tmpCmd != '\0') { cmd[i] = tmpCmd; - tmpCmd++; i++; } } @@ -525,7 +612,7 @@ static pid_t run(char *command, char *terminal, int get_enter) } } - if (get_enter == TRUE) { + 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 @@ -534,19 +621,16 @@ static pid_t run(char *command, char *terminal, int get_enter) * 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 + 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); } -#ifdef DEBUG_INIT /* Log the process name and args */ - message(LOG, "Starting pid %d, console %s: '%s'\r\n", - getpid(), terminal, command); -#endif + 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) { @@ -562,18 +646,20 @@ static pid_t run(char *command, char *terminal, int get_enter) execve(cmdpath, cmd, environment); /* We're still here? Some error happened. */ - message(LOG | CONSOLE, "Bummer, could not run '%s': %s\n", cmdpath, + message(LOG | CONSOLE, "\rBummer, could not run '%s': %s\n", cmdpath, strerror(errno)); - exit(-1); + _exit(-1); } + sigprocmask(SIG_SETMASK, &omask, NULL); return pid; } -static int waitfor(char *command, char *terminal, int get_enter) +static int waitfor(struct init_action *a) { + int pid; int status, wpid; - int pid = run(command, terminal, get_enter); + pid = run(a); while (1) { wpid = wait(&status); if (wpid > 0 && wpid != pid) { @@ -585,87 +671,163 @@ static int waitfor(char *command, char *terminal, int get_enter) 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() +/* Run all commands of a particular type */ +static void run_actions(int action) { - struct stat statBuf; - - if (check_free_memory() > 1000) - return; + struct init_action *a, *tmp; - 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; + for (a = init_action_list; a; a = tmp) { + tmp = a->next; if (a->action == action) { - waitfor(a->process, a->console, FALSE); - delete_initAction(a); + 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; - /* first disable our SIGHUP signal */ - signal(SIGHUP, SIG_DFL); + /* 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, "\r\nThe system is going down NOW !!\r\n"); + message(CONSOLE|LOG, "\n\rThe system is going down NOW !!\n"); sync(); /* Send signals to every process _except_ pid 1 */ - message(CONSOLE|LOG, "Sending SIGTERM to all processes.\r\n"); + message(CONSOLE|LOG, "\rSending SIGTERM to all processes.\n"); kill(-1, SIGTERM); sleep(1); sync(); - message(CONSOLE|LOG, "Sending SIGKILL to all processes.\r\n"); + message(CONSOLE|LOG, "\rSending SIGKILL to all processes.\n"); kill(-1, SIGKILL); sleep(1); - /* run everything to be run at "shutdown" */ - run_actions(SHUTDOWN); - 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, - "The system is halted. Press %s or turn off power\r\n", - (secondConsole == NULL) /* serial console */ - ? "Reset" : "CTRL-ALT-DEL"); +#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 */ @@ -682,7 +844,7 @@ static void halt_signal(int sig) static void reboot_signal(int sig) { shutdown_system(); - message(CONSOLE|LOG, "Please stand by while rebooting the system.\r\n"); + message(CONSOLE|LOG, "\rPlease stand by while rebooting the system.\n"); sync(); /* allow time for last message to reach serial console */ @@ -698,51 +860,76 @@ 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_initAction(initActionEnum action, char *process, char *cons) +static void new_init_action(int action, char *command, char *cons) { - initAction *newAction; + struct init_action *new_action, *a; 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")) + /* 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) + 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"); + new_action = calloc((size_t) (1), sizeof(struct init_action)); + if (!new_action) { + message(LOG | CONSOLE, "\rMemory 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); + + /* 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_initAction(initAction * action) +static void delete_init_action(struct init_action * action) { - initAction *a, *b = NULL; + struct init_action *a, *b = NULL; - for (a = initActionList; a; b = a, a = a->nextPtr) { + for (a = init_action_list; a; b = a, a = a->next) { if (a == action) { if (b == NULL) { - initActionList = a->nextPtr; + init_action_list = a->next; } else { - b->nextPtr = a->nextPtr; + b->next = a->next; } free(a); break; @@ -761,9 +948,9 @@ 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; + 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; @@ -772,30 +959,28 @@ static void parse_inittab(void) /* 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); + new_init_action(CTRLALTDEL, "/sbin/reboot", 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); + 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_initAction(SYSINIT, INIT_SCRIPT, console); + new_init_action(SYSINIT, INIT_SCRIPT, console); return; #ifdef BB_FEATURE_USE_INITTAB } - while (fgets(buf, 255, file) != NULL) { + while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) { foundIt = FALSE; /* Skip leading spaces */ for (id = buf; *id == ' ' || *id == '\t'; id++); @@ -815,7 +1000,7 @@ static void parse_inittab(void) /* 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); + message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); continue; } else { *runlev = '\0'; @@ -825,21 +1010,21 @@ static void parse_inittab(void) /* Separate the runlevels from the action */ action = strchr(runlev, ':'); if (action == NULL || *(action + 1) == '\0') { - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); + message(LOG | CONSOLE, "\rBad 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); + /* 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 { - *process = '\0'; - ++process; + *command = '\0'; + ++command; } /* Ok, now process it */ @@ -848,10 +1033,10 @@ static void parse_inittab(void) if (strcmp(a->name, action) == 0) { if (*id != '\0') { strcpy(tmpConsole, "/dev/"); - strncat(tmpConsole, id, 200); + strncat(tmpConsole, id, INIT_BUFFS_SIZE-6); id = tmpConsole; } - new_initAction(a->action, process, id); + new_init_action(a->action, command, id); foundIt = TRUE; } a++; @@ -860,9 +1045,10 @@ static void parse_inittab(void) continue; else { /* Choke on an unknown action */ - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); + message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); } } + fclose(file); return; #endif /* BB_FEATURE_USE_INITTAB */ } @@ -871,10 +1057,22 @@ static void parse_inittab(void) extern int init_main(int argc, char **argv) { - initAction *a, *tmp; + 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 @@ -887,10 +1085,15 @@ extern int init_main(int argc, char **argv) } /* 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(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... */ @@ -907,7 +1110,12 @@ extern int init_main(int argc, char **argv) close(0); close(1); close(2); + + if(device_open(console, O_RDWR|O_NOCTTY)==0) { set_term(0); + close(0); + } + chdir("/"); setsid(); @@ -915,22 +1123,7 @@ extern int init_main(int argc, char **argv) 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 - + message(MAYBE_CONSOLE|LOG, "\rinit started: %s\n", full_version); /* Make sure there is enough memory to do something useful. */ check_memory(); @@ -939,14 +1132,11 @@ extern int init_main(int argc, char **argv) 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); + 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_initAction(RESPAWN, LOGIN_SHELL, console); + new_init_action(RESPAWN, LOGIN_SHELL, console); } else { /* Not in single user mode -- see what inittab says */ @@ -969,56 +1159,41 @@ extern int init_main(int argc, char **argv) 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); - } - } + run_actions(ONCE); + /* If there is nothing else to do, stop */ - if (initActionList == NULL) { - message(LOG | CONSOLE, - "No more tasks for init -- sleeping forever.\n"); + 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) { - 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; - } - } - } + /* 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); - if (wpid > 0) { + while (wpid > 0) { /* Find out who died and clean up their corpse */ - for (a = initActionList; a; a = a->nextPtr) { + 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->process, wpid); + 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); } - sleep(1); } } diff --git a/busybox/insmod.c b/insmod.c similarity index 87% rename from busybox/insmod.c rename to insmod.c index 413af5ce7..c612e686a 100644 --- a/busybox/insmod.c +++ b/insmod.c @@ -6,9 +6,9 @@ * and MIPS. * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen - * and Ron Alder + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999-2002 Erik Andersen + * Written by Erik Andersen and Ron Alder * * Modified by Bryan Rittmeyer to support SH4 * and (theoretically) SH3. I have only tested SH4 in little endian mode. @@ -18,6 +18,13 @@ * very minor changes required to also work with StrongArm and presumably * all ARM based systems. * + * Magnus Damm 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 added PowerPC support 20-Feb-2001. * PowerPC specific code stolen from modutils-2.3.16, * written by Paul Mackerras, Copyright 1996, 1997 Linux International. @@ -63,6 +70,7 @@ #include #include #include +#include #include #include "busybox.h" @@ -79,30 +87,102 @@ #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 +#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(__sh__) +#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 -#if defined(__i386__) +#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__) -// neither used +/* 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 //---------------------------------------------------------------------------- @@ -132,7 +212,7 @@ #ifndef MODUTILS_MODULE_H -static const int MODUTILS_MODULE_H = 1; +#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 @@ -274,7 +354,11 @@ struct new_module #endif }; +#ifdef ARCHDATAM +#define ARCHDATA_SEC_NAME ARCHDATAM +#else #define ARCHDATA_SEC_NAME "__archdata" +#endif #define KALLSYMS_SEC_NAME "__kallsyms" @@ -353,96 +437,12 @@ static const int MODUTILS_OBJ_H = 1; #include #include +#include - -/* 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 +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ELFDATAM ELFDATA2LSB +#elif __BYTE_ORDER == __BIG_ENDIAN #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 @@ -574,8 +574,10 @@ 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); @@ -603,9 +605,11 @@ static enum obj_reloc arch_apply_relocation (struct obj_file *f, struct obj_symbol *sym, ElfW(RelM) *rel, ElfW(Addr) value); -static int arch_create_got (struct obj_file *f); +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 */ //---------------------------------------------------------------------------- @@ -624,36 +628,33 @@ 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; /*======================================================================*/ -/* 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_LIST) - - -#if defined(BB_USE_PLT_ENTRIES) -struct arch_plt_entry +struct arch_list_entry { - int offset; - int allocated:1; - int inited:1; /* has been set up */ + struct arch_list_entry *next; + BB_LIST_ARCHTYPE addend; + int offset; + int inited : 1; }; + #endif -#if defined(BB_USE_GOT_ENTRIES) -struct arch_got_entry { +#if defined(BB_USE_SINGLE) + +struct arch_single_entry +{ int offset; - unsigned offset_done:1; - unsigned reloc_done:1; + int inited : 1; + int allocated : 1; }; + #endif #if defined(__mips__) @@ -681,10 +682,14 @@ struct arch_file { struct arch_symbol { struct obj_symbol root; #if defined(BB_USE_PLT_ENTRIES) - struct arch_plt_entry pltent; +#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_got_entry gotent; + struct arch_single_entry gotent; #endif }; @@ -705,8 +710,8 @@ 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 char m_filename[FILENAME_MAX]; +static char m_fullName[FILENAME_MAX]; @@ -742,15 +747,7 @@ 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 + memset(f, 0, sizeof(*f)); return &f->root; } @@ -765,12 +762,7 @@ 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 + memset(sym, 0, sizeof(*sym)); return &sym->root; } @@ -783,85 +775,163 @@ arch_apply_relocation(struct obj_file *f, 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 - + 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; - struct arch_plt_entry *pe; unsigned long *ip; +#if defined(BB_USE_PLT_LIST) + struct arch_list_entry *pe; +#else + struct arch_single_entry *pe; +#endif #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__) +#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: -#elif defined(__mc68000__) + 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: -#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; + + 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; + + 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; + 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_PPC_ADDR16_HI: - *(unsigned short *)loc = v >> 16; + 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_PPC_ADDR16_LO: - *(unsigned short *)loc = v; + 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; -#endif -#if defined(__mips__) case R_MIPS_26: if (v % 4) ret = obj_reloc_dangerous; @@ -939,60 +1009,92 @@ arch_apply_relocation(struct obj_file *f, *loc = insnlo; break; } -#endif -#if defined(__arm__) +#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_REL32: - *loc += v - dot; + + case R_SH_NONE: break; -#elif defined(__i386__) - case R_386_PLT32: - case R_386_PC32: + + case R_SH_DIR32: + *loc += v; + break; + + case R_SH_REL32: *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; + + case R_SH_PLT32: + *loc = v - dot; break; - case R_68K_PC32: - *(int *)loc = v - dot; + + case R_SH_GLOB_DAT: + case R_SH_JMP_SLOT: + *loc = v; break; -#elif defined(__powerpc__) - case R_PPC_REL32: - *loc = v - dot; + + 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 -#if defined(__sh__) - case R_SH_PLT32: - *loc = v - dot; - break; -#elif defined(__i386__) #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) -#if defined(__arm__) - case R_ARM_PC24: - case R_ARM_PLT32: -#endif -#if defined(__powerpc__) - case R_PPC_REL24: -#endif + bb_use_plt: + /* find the plt entry and initialize it if necessary */ assert(isym != NULL); - pe = (struct arch_plt_entry*) &isym->pltent; +#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); @@ -1035,71 +1137,13 @@ arch_apply_relocation(struct obj_file *f, 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) + bb_use_got: -#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; + if (!isym->gotent.inited) { + isym->gotent.inited = 1; *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v; } /* make the reloc with_respect_to_.got */ @@ -1110,43 +1154,89 @@ arch_apply_relocation(struct obj_file *f, #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 /* 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 - assert(got != 0); - *loc += v - got; - break; -#endif // __mc68000__ -#endif /* BB_USE_GOT_ENTRIES */ +#if defined(BB_USE_SINGLE) - default: - printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info)); - ret = obj_reloc_unhandled; - break; +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; } - return ret; + if (myrelsec) { + obj_extend_section(myrelsec, offset); + } else { + myrelsec = obj_create_alloced_section(f, name, + size, offset); + assert(myrelsec); + } + + return myrelsec; } -static int arch_create_got(struct obj_file *f) +#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, gotneeded = 0; + int got_offset = 0, got_needed = 0, got_allocate; #endif #if defined(BB_USE_PLT_ENTRIES) - int plt_offset = 0, pltneeded = 0; + int plt_offset = 0, plt_needed = 0, plt_allocate; #endif struct obj_section *relsec, *symsec, *strsec; ElfW(RelM) *rel, *relend; @@ -1156,6 +1246,7 @@ static int arch_create_got(struct obj_file *f) for (i = 0; i < f->header.e_shnum; ++i) { relsec = f->sections[i]; + if (relsec->header.sh_type != SHT_RELM) continue; @@ -1169,49 +1260,71 @@ static int arch_create_got(struct obj_file *f) 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_GOT32: + + case R_ARM_PC24: + case R_ARM_PLT32: + plt_allocate = 1; break; -#elif defined(__sh__) - case R_SH_GOT32: + + 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(__mc68000__) - case R_68K_GOT32: - break; -#endif -#if defined(__powerpc__) +#elif defined(__powerpc__) + case R_PPC_REL24: - pltneeded = 1; + plt_allocate = 1; break; -#endif -#if defined(__arm__) - case R_ARM_PC24: - case R_ARM_PLT32: - pltneeded = 1; +#elif defined(__mc68000__) + + case R_68K_GOT32: + got_allocate = 1; break; - case R_ARM_GOTPC: - case R_ARM_GOTOFF: - gotneeded = 1; - if (got_offset == 0) - got_offset = 4; + 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: - gotneeded = 1; -#elif defined(__i386__) - case R_386_GOTPC: - case R_386_GOTOFF: - gotneeded = 1; -#endif + got_needed = 1; + continue; +#endif default: continue; } @@ -1223,55 +1336,54 @@ static int arch_create_got(struct obj_file *f) } 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; + 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 (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; - } + 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_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; + 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_offset) - ifile->plt = obj_create_alloced_section(f, ".plt", - BB_PLT_ENTRY_SIZE, - plt_offset); -#endif + if (plt_needed) { + ifile->plt = arch_xsect_init(f, ".plt", plt_offset, + BB_PLT_ENTRY_SIZE); + } #endif - return 1; + +#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 /*======================================================================*/ @@ -1802,7 +1914,7 @@ old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) return -1; p = f->sections[sym->secidx]->contents + sym->value; - strncpy(str, p, STRVERSIONLEN); + safe_strncpy(str, p, STRVERSIONLEN); a = strtoul(p, &p, 10); if (*p != '.') @@ -2290,7 +2402,7 @@ new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) p = get_modinfo_value(f, "kernel_version"); if (p == NULL) return -1; - strncpy(str, p, STRVERSIONLEN); + safe_strncpy(str, p, STRVERSIONLEN); a = strtoul(p, &p, 10); if (*p != '.') @@ -2631,6 +2743,7 @@ obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, 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) @@ -2646,6 +2759,7 @@ obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, return 1; } +#endif static int obj_check_undefineds(struct obj_file *f) { @@ -2660,7 +2774,9 @@ static int obj_check_undefineds(struct obj_file *f) sym->secidx = SHN_ABS; sym->value = 0; } else { - error_msg("unresolved symbol %s", sym->name); + if (!flag_quiet) { + error_msg("unresolved symbol %s", sym->name); + } ret = 0; } } @@ -3201,7 +3317,117 @@ static void hide_special_symbols(struct obj_file *f) 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) { @@ -3209,13 +3435,13 @@ extern int insmod_main( int argc, char **argv) int k_crcs; int k_new_syscalls; int len; - char *tmp; + 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 + 1] = "\0"; + char m_name[FILENAME_MAX] = "\0"; int exit_status = EXIT_FAILURE; int m_has_modinfo; #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING @@ -3226,7 +3452,7 @@ extern int insmod_main( int argc, char **argv) #endif /* Parse any options */ - while ((opt = getopt(argc, argv, "fkvxLo:")) > 0) { + while ((opt = getopt(argc, argv, "fkqsvxLo:")) > 0) { switch (opt) { case 'f': /* force loading */ flag_force_load = 1; @@ -3234,14 +3460,23 @@ extern int insmod_main( int argc, char **argv) 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 -- */ + /* 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 */ - strncpy(m_name, optarg, FILENAME_MAX); + safe_strncpy(m_name, optarg, sizeof(m_name)); break; case 'L': /* Stub warning */ /* This is needed for compatibility with modprobe. @@ -3259,20 +3494,29 @@ extern int insmod_main( int argc, char **argv) } /* Grab the module name */ - if ((tmp = strrchr(argv[optind], '/')) != NULL) { - tmp++; - } else { - tmp = argv[optind]; - } + tmp1 = xstrdup(argv[optind]); + tmp = basename(tmp1); 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 (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') { - strcpy(m_name, m_fullName); + 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 */ @@ -3333,32 +3577,33 @@ extern int insmod_main( int argc, char **argv) #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 (!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; + 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; @@ -3412,6 +3657,7 @@ extern int insmod_main( int argc, char **argv) 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; diff --git a/busybox/applets/install.sh b/install.sh similarity index 100% rename from busybox/applets/install.sh rename to install.sh diff --git a/busybox/examples/kernel-patches/Will_devps_GoIntoTheKernel b/kernel-patches/Will_devps_GoIntoTheKernel similarity index 99% rename from busybox/examples/kernel-patches/Will_devps_GoIntoTheKernel rename to kernel-patches/Will_devps_GoIntoTheKernel index 33ee8b47e..c541c0f8c 100644 --- a/busybox/examples/kernel-patches/Will_devps_GoIntoTheKernel +++ b/kernel-patches/Will_devps_GoIntoTheKernel @@ -1,5 +1,5 @@ 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 +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... diff --git a/busybox/examples/kernel-patches/devps.patch.9_25_2000 b/kernel-patches/devps.patch.9_25_2000 similarity index 100% rename from busybox/examples/kernel-patches/devps.patch.9_25_2000 rename to kernel-patches/devps.patch.9_25_2000 diff --git a/busybox/kill.c b/kill.c similarity index 60% rename from busybox/kill.c rename to kill.c index 3884ebdf4..499be111e 100644 --- a/busybox/kill.c +++ b/kill.c @@ -3,6 +3,7 @@ * Mini kill/killall implementation for busybox * * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +38,7 @@ static const int KILLALL = 1; extern int kill_main(int argc, char **argv) { - int whichApp, sig = SIGTERM; + int whichApp, sig = SIGTERM, quiet, errors; const char *name; #ifdef BB_KILLALL @@ -47,6 +48,8 @@ extern int kill_main(int argc, char **argv) whichApp = KILL; #endif + errors=0; + quiet=0; argc--; argv++; /* Parse any options */ @@ -56,44 +59,49 @@ extern int kill_main(int argc, char **argv) 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; +#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); } - } - 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; + } 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: +do_it_now: if (whichApp == KILL) { /* Looks like they want to do a kill. Do that */ @@ -103,40 +111,44 @@ extern int kill_main(int argc, char **argv) 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); + if (kill(pid, sig) != 0) { + perror_msg( "Could not kill pid '%d'", pid); + errors++; + } 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; + long* pidList; - pidList = find_pid_by_name( *argv); + pidList = find_pid_by_name(*argv); if (!pidList || *pidList<=0) { - all_found = FALSE; - error_msg_and_die( "%s: no process killed", *argv); + 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); + } + } } - 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; + return errors; } diff --git a/busybox/klogd.c b/klogd.c similarity index 85% rename from busybox/klogd.c rename to klogd.c index d7b54e9c8..75c7e1057 100644 --- a/busybox/klogd.c +++ b/klogd.c @@ -6,8 +6,8 @@ * 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 , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * Copyright (C) 2000 by Karl M. Hegbloom * @@ -55,7 +55,7 @@ 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."); + syslog_msg(LOG_SYSLOG, LOG_NOTICE, "Kernel log daemon exiting."); exit(TRUE); } @@ -76,7 +76,7 @@ static void doKlogd (void) /* "Open the log. Currently a NOP." */ klogctl(1, NULL, 0); - syslog_msg(LOG_DAEMON, 0, "klogd started: " BB_BANNER); + syslog_msg(LOG_SYSLOG, LOG_NOTICE, "klogd started: " BB_BANNER); while (1) { /* Use kernel syscalls */ @@ -89,7 +89,7 @@ static void doKlogd (void) 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); + syslog_msg(LOG_SYSLOG, LOG_ERR, message); exit(1); } @@ -109,7 +109,7 @@ static void doKlogd (void) } if (log_buffer[i] == '\n') { log_buffer[i] = '\0'; /* zero terminate this message */ - syslog_msg(LOG_DAEMON, LOG_KERN | priority, start); + syslog_msg(LOG_KERN, priority, start); start = &log_buffer[i+1]; priority = LOG_INFO; } @@ -122,23 +122,30 @@ 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; diff --git a/busybox/lash.c b/lash.c similarity index 98% rename from busybox/lash.c rename to lash.c index b3f7cb6a8..eb88da311 100644 --- a/busybox/lash.c +++ b/lash.c @@ -2,8 +2,8 @@ /* * lash -- the BusyBox Lame-Ass SHell * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999-2002 Erik Andersen * * 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 @@ -414,10 +414,8 @@ static int builtin_read(struct child_prog *child) if (child->argv[1]) { /* argument (VAR) given: put "VAR=" into buffer */ - strcpy(string, child->argv[1]); + snprintf(string, sizeof(string)-1, "%s=", 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) @@ -888,7 +886,7 @@ static int expand_arguments(char *command) 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; + int ixx=*(dst + 1)-48+1; if (ixx >= argc) { var='\0'; } else { @@ -1212,7 +1210,7 @@ static int pseudo_exec(struct child_prog *child) */ for (x = bltins; x->cmd; x++) { if (strcmp(child->argv[0], x->cmd) == 0 ) { - exit(x->function(child)); + _exit(x->function(child)); } } @@ -1220,13 +1218,13 @@ static int pseudo_exec(struct child_prog *child) for (x = bltins_forking; x->cmd; x++) { if (strcmp(child->argv[0], x->cmd) == 0) { applet_name=x->cmd; - exit (x->function(child)); + _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 + * 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 @@ -1256,7 +1254,11 @@ static int pseudo_exec(struct child_prog *child) #endif execvp(child->argv[0], child->argv); - perror_msg_and_die("%s", child->argv[0]); + + /* 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) @@ -1309,6 +1311,12 @@ static int run_command(struct job *newjob, int inbg, int outpipe[2]) 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++) { @@ -1345,7 +1353,8 @@ static int run_command(struct job *newjob, int inbg, int outpipe[2]) } } - if (!(child->pid = fork())) { + if (!(child->pid = fork())) + { /* Set the handling for job control signals back to the default. */ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); @@ -1455,8 +1464,11 @@ static int busy_loop(FILE * input) 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 (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 */ @@ -1493,7 +1505,7 @@ static int busy_loop(FILE * input) free(command); /* return controlling TTY back to parent process group before exiting */ - if (tcsetpgrp(shell_terminal, parent_pgrp)) + if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY) perror_msg("tcsetpgrp"); /* return exit status if called with "-c" */ diff --git a/busybox/coreutils/length.c b/length.c similarity index 100% rename from busybox/coreutils/length.c rename to length.c diff --git a/busybox/libbb/.cvsignore b/libbb/.cvsignore similarity index 100% rename from busybox/libbb/.cvsignore rename to libbb/.cvsignore diff --git a/busybox/libbb/Makefile b/libbb/Makefile similarity index 84% rename from busybox/libbb/Makefile rename to libbb/Makefile index a9ea76947..2c8ab2b5d 100644 --- a/busybox/libbb/Makefile +++ b/libbb/Makefile @@ -7,5 +7,5 @@ all: clean: - rm -rf libbb.a - - find -name \*.o -exec rm -f {} \; + - find . -name \*.o -exec rm -f {} \; diff --git a/busybox/libbb/README b/libbb/README similarity index 75% rename from busybox/libbb/README rename to libbb/README index 0e36f84b6..38934c292 100644 --- a/busybox/libbb/README +++ b/libbb/README @@ -5,11 +5,10 @@ libbb is BusyBox's utility library. This all used to be in a single file 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, +For now, just trust me that a bunch of people have worked on this stuff, and it is all GPL'ed. Erik Andersen - - + diff --git a/libbb/arith.c b/libbb/arith.c new file mode 100644 index 000000000..e5b3213cb --- /dev/null +++ b/libbb/arith.c @@ -0,0 +1,376 @@ +/* Copyright (c) 2001 Aaron Lehmann + + 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 +#include +#include +#include +#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/busybox/libbb/ask_confirmation.c b/libbb/ask_confirmation.c similarity index 70% rename from busybox/libbb/ask_confirmation.c rename to libbb/ask_confirmation.c index f2922379c..d4d943ad7 100644 --- a/busybox/libbb/ask_confirmation.c +++ b/libbb/ask_confirmation.c @@ -2,27 +2,23 @@ /* * 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. + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public 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. - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ #include diff --git a/busybox/libbb/chomp.c b/libbb/chomp.c similarity index 69% rename from busybox/libbb/chomp.c rename to libbb/chomp.c index 111d4cf77..94404a98d 100644 --- a/busybox/libbb/chomp.c +++ b/libbb/chomp.c @@ -2,27 +2,23 @@ /* * 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. + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public 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. - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ #include diff --git a/busybox/cat.c b/libbb/concat_path_file.c similarity index 51% rename from busybox/cat.c rename to libbb/concat_path_file.c index aa8528d6a..e62b99ef6 100644 --- a/busybox/cat.c +++ b/libbb/concat_path_file.c @@ -1,53 +1,45 @@ /* vi: set sw=4 ts=4: */ /* - * Mini Cat implementation for busybox + * Utility routines. * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ -#include +/* concatenate path and file name to new allocation buffer, + * not addition '/' if path name already have '/' +*/ + #include -#include "busybox.h" +#include "libbb.h" -extern int cat_main(int argc, char **argv) +extern char *concat_path_file(const char *path, const char *filename) { - int status = EXIT_SUCCESS; + char *outbuf; + char *lc; - if (argc == 1) { - print_file(stdin); - return status; - } + 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); - while (--argc > 0) { - if(!(strcmp(*++argv, "-"))) { - print_file(stdin); - } else if (print_file_by_name(*argv) == FALSE) { - status = EXIT_FAILURE; - } - } - return status; + return outbuf; } - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/copy_file.c b/libbb/copy_file.c similarity index 76% rename from busybox/libbb/copy_file.c rename to libbb/copy_file.c index c79fbeb14..f24fa01d2 100644 --- a/busybox/libbb/copy_file.c +++ b/libbb/copy_file.c @@ -2,7 +2,6 @@ /* * Mini copy_file implementation for busybox * - * * Copyright (C) 2001 by Matt Kraai * * This program is free software; you can redistribute it and/or modify @@ -33,34 +32,36 @@ #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 = 1; + int dest_exists = 0; int status = 0; - if (((flags & FILEUTILS_PRESERVE_SYMLINKS) && - lstat(source, &source_stat) < 0) || - (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && - stat(source, &source_stat) < 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 (stat(dest, &dest_stat) < 0) { + if (lstat(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 && + } 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; @@ -117,13 +118,8 @@ int copy_file(const char *source, const char *dest, int flags) 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; - } + /* closedir have only EBADF error, but "dp" not changes */ + closedir(dp); if (!dest_exists && chmod(dest, source_stat.st_mode & ~saved_umask) < 0) { @@ -131,23 +127,44 @@ int copy_file(const char *source, const char *dest, int flags) status = -1; } } else if (S_ISREG(source_stat.st_mode)) { - FILE *sfp, *dfp; + 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()) + 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; } @@ -163,17 +180,11 @@ int copy_file(const char *source, const char *dest, int flags) if (fd >= 0) close(fd); perror_msg("unable to open `%s'", dest); + fclose (sfp); 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; @@ -186,8 +197,23 @@ int copy_file(const char *source, const char *dest, int flags) 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)) { + } + 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; @@ -198,7 +224,9 @@ int copy_file(const char *source, const char *dest, int flags) return -1; } } else if (S_ISLNK(source_stat.st_mode)) { - char *lpath = xreadlink(source); + char *lpath; + + lpath = xreadlink(source); if (symlink(lpath, dest) < 0) { perror_msg("cannot create symlink `%s'", dest); return -1; @@ -210,12 +238,18 @@ int copy_file(const char *source, const char *dest, int flags) 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; - } else { - error_msg("internal error: unrecognized file type"); - return -1; } +#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS + add_to_ino_dev_hashtable(&source_stat, dest); +#endif + end: if (flags & FILEUTILS_PRESERVE_STATUS) { diff --git a/busybox/libbb/copy_file_chunk.c b/libbb/copy_file_chunk.c similarity index 79% rename from busybox/libbb/copy_file_chunk.c rename to libbb/copy_file_chunk.c index c440a6102..63d2ab173 100644 --- a/busybox/libbb/copy_file_chunk.c +++ b/libbb/copy_file_chunk.c @@ -2,27 +2,23 @@ /* * 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. + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public 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. - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ #include diff --git a/busybox/libbb/copyfd.c b/libbb/copyfd.c similarity index 100% rename from busybox/libbb/copyfd.c rename to libbb/copyfd.c diff --git a/busybox/libbb/create_icmp_socket.c b/libbb/create_icmp_socket.c similarity index 100% rename from busybox/libbb/create_icmp_socket.c rename to libbb/create_icmp_socket.c diff --git a/busybox/libbb/device_open.c b/libbb/device_open.c similarity index 79% rename from busybox/libbb/device_open.c rename to libbb/device_open.c index 8e97ce6c5..30b33d7f0 100644 --- a/busybox/libbb/device_open.c +++ b/libbb/device_open.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/dirname.c b/libbb/dirname.c similarity index 96% rename from busybox/libbb/dirname.c rename to libbb/dirname.c index df9a49daa..2aebd3815 100644 --- a/busybox/libbb/dirname.c +++ b/libbb/dirname.c @@ -22,7 +22,7 @@ #include #include "libbb.h" -#if defined __UCLIBC__ || __GNU_LIBRARY___ < 5 +#if defined __GNU_LIBRARY___ < 5 /* Return a string containing the path name of the parent * directory of PATH. */ diff --git a/busybox/libbb/error_msg.c b/libbb/error_msg.c similarity index 76% rename from busybox/libbb/error_msg.c rename to libbb/error_msg.c index c7d5fdb98..58308b6be 100644 --- a/busybox/libbb/error_msg.c +++ b/libbb/error_msg.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/error_msg_and_die.c b/libbb/error_msg_and_die.c similarity index 76% rename from busybox/libbb/error_msg_and_die.c rename to libbb/error_msg_and_die.c index b950ee00c..67a79c375 100644 --- a/busybox/libbb/error_msg_and_die.c +++ b/libbb/error_msg_and_die.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/libbb/fgets_str.c b/libbb/fgets_str.c new file mode 100644 index 000000000..6588f9482 --- /dev/null +++ b/libbb/fgets_str.c @@ -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 +#include +#include + +#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/busybox/libbb/find_mount_point.c b/libbb/find_mount_point.c similarity index 85% rename from busybox/libbb/find_mount_point.c rename to libbb/find_mount_point.c index 2d9481a69..1eb5dc942 100644 --- a/busybox/libbb/find_mount_point.c +++ b/libbb/find_mount_point.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c similarity index 75% rename from busybox/libbb/find_pid_by_name.c rename to libbb/find_pid_by_name.c index 7f39dd41c..fc3742ab2 100644 --- a/busybox/libbb/find_pid_by_name.c +++ b/libbb/find_pid_by_name.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 @@ -34,6 +28,8 @@ #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 @@ -46,13 +42,13 @@ * * Returns a list of all matching PIDs */ -extern pid_t* find_pid_by_name( char* pidName) +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; - pid_t* pidList=NULL; + long* pidList=NULL; /* open device */ fd = open(device, O_RDONLY); @@ -93,25 +89,19 @@ extern pid_t* find_pid_by_name( char* pidName) if ((strstr(info.command_line, pidName) != NULL) && (strlen(pidName) == strlen(info.command_line))) { - pidList=xrealloc( pidList, sizeof(pid_t) * (j+2)); + pidList=xrealloc( pidList, sizeof(long) * (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=xrealloc( pidList, sizeof(long)); pidList[0]=-1; } /* Free memory */ - free( pid_array); + free(pid_array); /* close device */ if (close (fd) != 0) @@ -130,11 +120,11 @@ extern pid_t* find_pid_by_name( char* pidName) * * Returns a list of all matching PIDs */ -extern pid_t* find_pid_by_name( char* pidName) +extern long* find_pid_by_name( char* pidName) { DIR *dir; struct dirent *next; - pid_t* pidList=NULL; + long* pidList=NULL; int i=0; dir = opendir("/proc"); @@ -167,22 +157,16 @@ extern pid_t* find_pid_by_name( char* pidName) /* 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)); + 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) + 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=xrealloc( pidList, sizeof(long)); pidList[0]=-1; } return pidList; diff --git a/busybox/libbb/find_root_device.c b/libbb/find_root_device.c similarity index 86% rename from busybox/libbb/find_root_device.c rename to libbb/find_root_device.c index f8f68464d..e5f698659 100644 --- a/busybox/libbb/find_root_device.c +++ b/libbb/find_root_device.c @@ -1,8 +1,9 @@ /* vi: set sw=4 ts=4: */ /* - * Copyright (C) 2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Utility routines. * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * Patched by a bunch of people. Feel free to acknowledge your work. * * This program is free software; you can redistribute it and/or modify @@ -18,7 +19,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include @@ -40,8 +40,11 @@ extern char *find_real_root_device_name(const char* name) if (stat("/", &rootStat) != 0) perror_msg("could not stat '/'"); else { - if ((dev = rootStat.st_rdev)==0) - dev=rootStat.st_dev; + /* 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) diff --git a/busybox/libbb/full_read.c b/libbb/full_read.c similarity index 73% rename from busybox/libbb/full_read.c rename to libbb/full_read.c index e9c4bbfc6..b91cdcbc9 100644 --- a/busybox/libbb/full_read.c +++ b/libbb/full_read.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999-2003 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,40 +17,35 @@ * You should have received a copy of the GNU General Public 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 #include #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) +ssize_t full_read(int fd, void *buf, size_t len) { - int cc; - int total; + ssize_t cc; + ssize_t total; total = 0; while (len > 0) { - cc = read(fd, buf, len); + cc = safe_read(fd, buf, len); if (cc < 0) - return -1; + return cc; /* read() returns -1 on failure. */ if (cc == 0) break; - buf += cc; + buf = ((char *)buf) + cc; total += cc; len -= cc; } diff --git a/busybox/libbb/full_write.c b/libbb/full_write.c similarity index 71% rename from busybox/libbb/full_write.c rename to libbb/full_write.c index dc9937fa3..c485a2402 100644 --- a/busybox/libbb/full_write.c +++ b/libbb/full_write.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999-2003 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 @@ -34,21 +28,21 @@ * 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) +ssize_t full_write(int fd, const void *buf, size_t len) { - int cc; - int total; + ssize_t cc; + ssize_t total; total = 0; while (len > 0) { - cc = write(fd, buf, len); + cc = safe_write(fd, buf, len); if (cc < 0) - return -1; + return cc; /* write() returns -1 on failure. */ - buf += cc; total += cc; + buf = ((const char *)buf) + cc; len -= cc; } diff --git a/busybox/libbb/get_console.c b/libbb/get_console.c similarity index 83% rename from busybox/libbb/get_console.c rename to libbb/get_console.c index 3b36a59e7..39c00e62e 100644 --- a/busybox/libbb/get_console.c +++ b/libbb/get_console.c @@ -2,9 +2,8 @@ /* * 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. + * 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 @@ -19,10 +18,6 @@ * You should have received a copy of the GNU General Public 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 @@ -87,16 +82,14 @@ static int open_a_console(char *fnam) * if tty_name is non-NULL, try this one instead. */ -int get_console_fd(char *tty_name) +int get_console_fd(void) { int fd; - if (tty_name) { - if (-1 == (fd = open_a_console(tty_name))) - return -1; - else - return fd; - } + if (-1 == (fd = open_a_console("/dev/console"))) + return -1; + else + return fd; fd = open_a_console(CURRENT_TTY); if (fd >= 0) diff --git a/busybox/watchdog.c b/libbb/get_last_path_component.c similarity index 52% rename from busybox/watchdog.c rename to libbb/get_last_path_component.c index f0b0ebd0e..6af726c83 100644 --- a/busybox/watchdog.c +++ b/libbb/get_last_path_component.c @@ -1,8 +1,8 @@ /* vi: set sw=4 ts=4: */ /* - * Mini watchdog implementation for busybox + * get_last_path_component implementation for busybox * - * Copyright (C) 2000 spoon . + * Copyright (C) 2001 Manuel Novoa III * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,30 +20,37 @@ * */ -/* getopt not needed */ +/* Set to 1 if you want basename() behavior for NULL or "". */ +/* WARNING!!! Doing so will break basename applet at least! */ +#define EMULATE_BASENAME 0 -#include -#include -#include -#include -#include "busybox.h" - -extern int watchdog_main(int argc, char **argv) +char *get_last_path_component(char *path) { - int fd; +#if EMULATE_BASENAME + static const char null_or_empty[] = "."; +#endif + char *first = path; + char *last; - if (argc != 2) { - show_usage(); +#if EMULATE_BASENAME + if (!path || !*path) { + return (char *) null_or_empty; } +#endif + + last = path - 1; - if ((fd=open(argv[1], O_WRONLY)) == -1) { - perror_msg_and_die(argv[1]); + while (*path) { + if ((*path != '/') && (path > ++last)) { + last = first = path; + } + ++path; } - while (1) { - sleep(30); - write(fd, "\0", 1); + if (*first == '/') { + last = first; } + last[1] = 0; - return EXIT_FAILURE; + return first; } diff --git a/busybox/libbb/get_line_from_file.c b/libbb/get_line_from_file.c similarity index 62% rename from busybox/libbb/get_line_from_file.c rename to libbb/get_line_from_file.c index 759481731..0d9720b17 100644 --- a/busybox/libbb/get_line_from_file.c +++ b/libbb/get_line_from_file.c @@ -2,9 +2,8 @@ /* * 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. + * 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 @@ -19,46 +18,57 @@ * You should have received a copy of the GNU General Public 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 +#include #include "libbb.h" - - -/* get_line_from_file() - This function reads an entire line from a text file +/* 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) + * 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) { - static const int GROWBY = 80; /* how large we will grow strings by */ +#define 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; + while ((ch = getc(file)) != EOF) { /* grow the line buffer as necessary */ - while (idx > linebufsz-2) + if (idx > linebufsz - 2) { linebuf = xrealloc(linebuf, linebufsz += GROWBY); + } linebuf[idx++] = (char)ch; - if ((char)ch == '\n') + if (ch == '\n' || ch == '\0') { + if (c) { + --idx; + } break; + } + } + if (linebuf) { + if (ferror(file)) { + free(linebuf); + return NULL; + } + linebuf[idx] = 0; } + return linebuf; +} - if (idx == 0) - return NULL; +extern char *get_line_from_file(FILE *file) +{ + return private_get_line_from_file(file, 0); +} - linebuf[idx] = 0; - return linebuf; +extern char *get_chomped_line_from_file(FILE *file) +{ + return private_get_line_from_file(file, 1); } diff --git a/libbb/gz_open.c b/libbb/gz_open.c new file mode 100644 index 000000000..a0187534d --- /dev/null +++ b/libbb/gz_open.c @@ -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 +#include +#include +#include +#include +#include +#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/busybox/libbb/herror_msg.c b/libbb/herror_msg.c similarity index 75% rename from busybox/libbb/herror_msg.c rename to libbb/herror_msg.c index f4210edad..1081a56b1 100644 --- a/busybox/libbb/herror_msg.c +++ b/libbb/herror_msg.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/herror_msg_and_die.c b/libbb/herror_msg_and_die.c similarity index 76% rename from busybox/libbb/herror_msg_and_die.c rename to libbb/herror_msg_and_die.c index 0df5ed016..a47c7ff95 100644 --- a/busybox/libbb/herror_msg_and_die.c +++ b/libbb/herror_msg_and_die.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/human_readable.c b/libbb/human_readable.c similarity index 100% rename from busybox/libbb/human_readable.c rename to libbb/human_readable.c diff --git a/busybox/libbb/inode_hash.c b/libbb/inode_hash.c similarity index 85% rename from busybox/libbb/inode_hash.c rename to libbb/inode_hash.c index 790af8f31..36484e6ae 100644 --- a/busybox/libbb/inode_hash.c +++ b/libbb/inode_hash.c @@ -2,27 +2,23 @@ /* * 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. + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public 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. - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ #include @@ -33,6 +29,13 @@ #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]; /* diff --git a/busybox/libbb/interface.c b/libbb/interface.c similarity index 99% rename from busybox/libbb/interface.c rename to libbb/interface.c index 484597c5f..5b1c418e9 100644 --- a/busybox/libbb/interface.c +++ b/libbb/interface.c @@ -3,7 +3,7 @@ * 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 $ + * Version: $Id: interface.c,v 1.8 2003/07/28 06:37:04 andersen Exp $ * * Author: Fred N. van Kempen, * and others. Copyright 1993 MicroWalt Corporation @@ -90,6 +90,10 @@ static int procnetdev_vsn = 1; +#ifdef DEBUG +#include +#endif + /* Ugh. But libc5 doesn't provide POSIX types. */ #include @@ -403,7 +407,7 @@ static int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, /* Grmpf. -FvK */ if (s_in->sin_family != AF_INET) { #ifdef DEBUG - fprintf(stderr, _("rresolve: unsupport address family %d !\n"), s_in->sin_family); + fprintf(stderr, "rresolve: unsupport address family %d !\n", s_in->sin_family); #endif errno = EAFNOSUPPORT; return (-1); @@ -1265,7 +1269,7 @@ static int if_readlist_proc(char *target) err = 0; while (fgets(buf, sizeof buf, fh)) { - char *s, name[IFNAMSIZ]; + char *s, name[128]; s = get_name(name, buf); ife = add_interface(name); get_dev_fields(s, ife); @@ -1867,7 +1871,7 @@ static void print_bytes_scaled(unsigned long long ull, const char *end) } } - printf("X bytes:%Lu (%Lu.%lu %sb)%s", ull, int_part, frac_part, ext, end); + printf("X bytes:%Lu (%Lu.%lu %siB)%s", ull, int_part, frac_part, ext, end); } static void ife_print(struct interface *ptr) @@ -2099,7 +2103,7 @@ static void ife_print(struct interface *ptr) 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); + 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); } diff --git a/busybox/libbb/isdirectory.c b/libbb/isdirectory.c similarity index 89% rename from busybox/libbb/isdirectory.c rename to libbb/isdirectory.c index 65f4fee00..3dfe10522 100644 --- a/busybox/libbb/isdirectory.c +++ b/libbb/isdirectory.c @@ -2,9 +2,8 @@ /* * 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. + * 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 @@ -19,10 +18,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/kernel_version.c b/libbb/kernel_version.c similarity index 81% rename from busybox/libbb/kernel_version.c rename to libbb/kernel_version.c index 09cd582c4..694af8e2c 100644 --- a/busybox/libbb/kernel_version.c +++ b/libbb/kernel_version.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/last_char_is.c b/libbb/last_char_is.c similarity index 100% rename from busybox/libbb/last_char_is.c rename to libbb/last_char_is.c diff --git a/busybox/libbb/libbb.h b/libbb/libbb.h similarity index 93% rename from busybox/libbb/libbb.h rename to libbb/libbb.h index 30f0bb9a7..c3b353f2c 100644 --- a/busybox/libbb/libbb.h +++ b/libbb/libbb.h @@ -2,7 +2,6 @@ /* * 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 @@ -16,11 +15,8 @@ * You should have received a copy of the GNU General Public 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 @@ -31,16 +27,16 @@ #include +#ifndef _BB_INTERNAL_H_ +#include "../busybox.h" +#endif + #ifdef DMALLOC #include "dmalloc.h" #endif #include -#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; @@ -103,8 +99,8 @@ 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); +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), @@ -114,15 +110,16 @@ 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 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 pid_t* find_pid_by_name( char* pidName); +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); @@ -306,6 +303,7 @@ extern const char * const can_not_create_raw_socket; # 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" @@ -317,10 +315,26 @@ extern const char * const can_not_create_raw_socket; # 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/busybox/libbb/libc5.c b/libbb/libc5.c similarity index 97% rename from busybox/libbb/libc5.c rename to libbb/libc5.c index 20295fd4b..67ab16176 100644 --- a/busybox/libbb/libc5.c +++ b/libbb/libc5.c @@ -9,7 +9,7 @@ #include -#if __GNU_LIBRARY__ < 5 +#if ! defined __dietlibc__ && __GNU_LIBRARY__ < 5 /* Copyright (C) 1991 Free Software Foundation, Inc. @@ -72,14 +72,14 @@ ssize_t getline(char **linebuf, size_t *n, FILE *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 - * , + * Modified for uClibc by Erik Andersen * * 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 @@ -127,6 +127,7 @@ int daemon( int nochdir, int noclose ) } return(0); } +#endif /* __uClinux__ */ /*- diff --git a/busybox/libbb/loop.c b/libbb/loop.c similarity index 88% rename from busybox/libbb/loop.c rename to libbb/loop.c index 4754b8da1..66e8921fa 100644 --- a/busybox/libbb/loop.c +++ b/libbb/loop.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 @@ -43,6 +37,7 @@ extern int del_loop(const char *device) return (FALSE); } if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { + close(fd); perror_msg("ioctl: LOOP_CLR_FD"); return (FALSE); } @@ -101,7 +96,7 @@ extern char *find_unused_loop_device(void) struct loop_info loopinfo; for (i = 0; i <= 7; i++) { - sprintf(dev, "/dev/loop%d", 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) { diff --git a/busybox/libbb/make_directory.c b/libbb/make_directory.c similarity index 100% rename from busybox/libbb/make_directory.c rename to libbb/make_directory.c diff --git a/busybox/libbb/messages.c b/libbb/messages.c similarity index 94% rename from busybox/libbb/messages.c rename to libbb/messages.c index 552c3ab5b..47b5526e3 100644 --- a/busybox/libbb/messages.c +++ b/libbb/messages.c @@ -1,7 +1,7 @@ /* vi: set sw=4 ts=4: */ /* - * Copyright (C) 2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/libbb/mode_string.c b/libbb/mode_string.c similarity index 81% rename from busybox/libbb/mode_string.c rename to libbb/mode_string.c index 0a3d6e6f0..12dc17966 100644 --- a/busybox/libbb/mode_string.c +++ b/libbb/mode_string.c @@ -2,27 +2,23 @@ /* * 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. + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public 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. - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ #include diff --git a/busybox/libbb/module_syscalls.c b/libbb/module_syscalls.c similarity index 69% rename from busybox/libbb/module_syscalls.c rename to libbb/module_syscalls.c index 8326f15ad..1320a6a25 100644 --- a/busybox/libbb/module_syscalls.c +++ b/libbb/module_syscalls.c @@ -2,8 +2,8 @@ /* * some system calls possibly missing from libc * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,13 +28,16 @@ _syscall* defined. */ #define __LIBRARY__ #include -#ifndef __UCLIBC__ +#if __GNU_LIBRARY__ < 5 +/* This is needed for libc5 */ #include #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); @@ -44,6 +47,24 @@ _syscall1(int, get_kernel_syms, __ptr_t, ks); * 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 @@ -56,10 +77,15 @@ int query_module(const char *name, int which, void *buf, size_t bufsize, size_t 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) @@ -73,6 +99,19 @@ unsigned long create_module(const char *name, size_t size) } 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 */ diff --git a/busybox/libbb/mtab.c b/libbb/mtab.c similarity index 73% rename from busybox/libbb/mtab.c rename to libbb/mtab.c index 28c9978ef..c521b1e05 100644 --- a/busybox/libbb/mtab.c +++ b/libbb/mtab.c @@ -1,4 +1,24 @@ /* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 by Erik Andersen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #include #include #include diff --git a/busybox/libbb/mtab_file.c b/libbb/mtab_file.c similarity index 78% rename from busybox/libbb/mtab_file.c rename to libbb/mtab_file.c index 56f8e06ab..e6ccd09eb 100644 --- a/busybox/libbb/mtab_file.c +++ b/libbb/mtab_file.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/my_getgrgid.c b/libbb/my_getgrgid.c similarity index 78% rename from busybox/libbb/my_getgrgid.c rename to libbb/my_getgrgid.c index fabd4776c..78f800158 100644 --- a/busybox/libbb/my_getgrgid.c +++ b/libbb/my_getgrgid.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/my_getgrnam.c b/libbb/my_getgrnam.c similarity index 78% rename from busybox/libbb/my_getgrnam.c rename to libbb/my_getgrnam.c index e3226a275..bea4ce062 100644 --- a/busybox/libbb/my_getgrnam.c +++ b/libbb/my_getgrnam.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/my_getpwnam.c b/libbb/my_getpwnam.c similarity index 78% rename from busybox/libbb/my_getpwnam.c rename to libbb/my_getpwnam.c index ae73ae7f1..2fc010137 100644 --- a/busybox/libbb/my_getpwnam.c +++ b/libbb/my_getpwnam.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/my_getpwnamegid.c b/libbb/my_getpwnamegid.c similarity index 80% rename from busybox/libbb/my_getpwnamegid.c rename to libbb/my_getpwnamegid.c index fb3d148ce..687c52c7e 100644 --- a/busybox/libbb/my_getpwnamegid.c +++ b/libbb/my_getpwnamegid.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/my_getpwuid.c b/libbb/my_getpwuid.c similarity index 78% rename from busybox/libbb/my_getpwuid.c rename to libbb/my_getpwuid.c index 46c7a884a..8dd828881 100644 --- a/busybox/libbb/my_getpwuid.c +++ b/libbb/my_getpwuid.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/parse_mode.c b/libbb/parse_mode.c similarity index 87% rename from busybox/libbb/parse_mode.c rename to libbb/parse_mode.c index 30d2f21cf..ba34ea929 100644 --- a/busybox/libbb/parse_mode.c +++ b/libbb/parse_mode.c @@ -2,27 +2,23 @@ /* * 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. + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public 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. - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ #include diff --git a/busybox/libbb/parse_number.c b/libbb/parse_number.c similarity index 78% rename from busybox/libbb/parse_number.c rename to libbb/parse_number.c index c90511dca..755a357ad 100644 --- a/busybox/libbb/parse_number.c +++ b/libbb/parse_number.c @@ -2,27 +2,23 @@ /* * 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. + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public 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. - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ #include diff --git a/busybox/libbb/perror_msg.c b/libbb/perror_msg.c similarity index 76% rename from busybox/libbb/perror_msg.c rename to libbb/perror_msg.c index 18c71ab1c..8c57b0d16 100644 --- a/busybox/libbb/perror_msg.c +++ b/libbb/perror_msg.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/perror_msg_and_die.c b/libbb/perror_msg_and_die.c similarity index 76% rename from busybox/libbb/perror_msg_and_die.c rename to libbb/perror_msg_and_die.c index 9d304a26b..9004925cc 100644 --- a/busybox/libbb/perror_msg_and_die.c +++ b/libbb/perror_msg_and_die.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/print_file.c b/libbb/print_file.c similarity index 100% rename from busybox/libbb/print_file.c rename to libbb/print_file.c diff --git a/busybox/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c similarity index 100% rename from busybox/libbb/process_escape_sequence.c rename to libbb/process_escape_sequence.c diff --git a/busybox/libbb/read_package_field.c b/libbb/read_package_field.c similarity index 72% rename from busybox/libbb/read_package_field.c rename to libbb/read_package_field.c index f561df831..ac5f80167 100644 --- a/busybox/libbb/read_package_field.c +++ b/libbb/read_package_field.c @@ -1,3 +1,26 @@ +/* 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 #include #include "libbb.h" diff --git a/busybox/libbb/real_loop.h b/libbb/real_loop.h similarity index 100% rename from busybox/libbb/real_loop.h rename to libbb/real_loop.h diff --git a/busybox/libbb/recursive_action.c b/libbb/recursive_action.c similarity index 91% rename from busybox/libbb/recursive_action.c rename to libbb/recursive_action.c index 6672db17f..e87ab9860 100644 --- a/busybox/libbb/recursive_action.c +++ b/libbb/recursive_action.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/remove_file.c b/libbb/remove_file.c similarity index 99% rename from busybox/libbb/remove_file.c rename to libbb/remove_file.c index 3b84680c4..988b09124 100644 --- a/busybox/libbb/remove_file.c +++ b/libbb/remove_file.c @@ -2,10 +2,8 @@ /* * Mini remove_file 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 @@ -19,7 +17,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include diff --git a/busybox/libbb/safe_read.c b/libbb/safe_read.c similarity index 76% rename from busybox/libbb/safe_read.c rename to libbb/safe_read.c index dbf4aa7e4..67f3268c5 100644 --- a/busybox/libbb/safe_read.c +++ b/libbb/safe_read.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999-2003 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/safe_strncpy.c b/libbb/safe_strncpy.c similarity index 76% rename from busybox/libbb/safe_strncpy.c rename to libbb/safe_strncpy.c index 55ec79802..0c5cf12ef 100644 --- a/busybox/libbb/safe_strncpy.c +++ b/libbb/safe_strncpy.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/coreutils/pwd.c b/libbb/safe_write.c similarity index 69% rename from busybox/coreutils/pwd.c rename to libbb/safe_write.c index f6a00bf1e..0ac6c2d96 100644 --- a/busybox/coreutils/pwd.c +++ b/libbb/safe_write.c @@ -1,9 +1,8 @@ /* vi: set sw=4 ts=4: */ /* - * Mini pwd implementation for busybox + * Utility routines. * - * - * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2003 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,27 +17,32 @@ * You should have received a copy of the GNU General Public 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 -#include #include #include -#include -#include "busybox.h" +#include "libbb.h" + + -extern int pwd_main(int argc, char **argv) +ssize_t safe_write(int fd, const void *buf, size_t count) { - static char *buf; - - buf = xgetcwd(buf); - - if (buf != NULL) { - puts(buf); - return EXIT_SUCCESS; - } - return EXIT_FAILURE; + 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/busybox/libbb/simplify_path.c b/libbb/simplify_path.c similarity index 99% rename from busybox/libbb/simplify_path.c rename to libbb/simplify_path.c index cf5b838a1..7b2a1ca51 100644 --- a/busybox/libbb/simplify_path.c +++ b/libbb/simplify_path.c @@ -2,10 +2,8 @@ /* * simplify_path implementation for busybox * - * * Copyright (C) 2001 Manuel Novoa III * - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/busybox/libbb/syscalls.c b/libbb/syscalls.c similarity index 63% rename from busybox/libbb/syscalls.c rename to libbb/syscalls.c index 426a14aa1..765868840 100644 --- a/busybox/libbb/syscalls.c +++ b/libbb/syscalls.c @@ -2,8 +2,8 @@ /* * some system calls possibly missing from libc * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,21 +27,20 @@ /* Kernel headers before 2.1.mumble need this on the Alpha to get _syscall* defined. */ #define __LIBRARY__ - - #include -#ifndef __UCLIBC__ +#if __GNU_LIBRARY__ < 5 +/* This is needed for libc5 */ #include #endif #include "libbb.h" -#if defined(__ia64__) +#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)); } -#else -_syscall3(int, sysfs, int, option, unsigned int, fs_index, char *, buf); #endif #ifndef __NR_pivot_root @@ -60,49 +59,70 @@ int pivot_root(const char * new_root,const char * put_old) return -1; } #else -# if defined(__ia64__) +# 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)); } -# else - _syscall2(int,pivot_root,const char *,new_root,const char *,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); +_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 + -#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); +#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 */ +#endif /* __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)) */ /* END CODE */ diff --git a/busybox/libbb/syslog_msg_with_name.c b/libbb/syslog_msg_with_name.c similarity index 78% rename from busybox/libbb/syslog_msg_with_name.c rename to libbb/syslog_msg_with_name.c index 5dadcc433..6474da459 100644 --- a/busybox/libbb/syslog_msg_with_name.c +++ b/libbb/syslog_msg_with_name.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/time_string.c b/libbb/time_string.c similarity index 80% rename from busybox/libbb/time_string.c rename to libbb/time_string.c index 076529006..d103a02f8 100644 --- a/busybox/libbb/time_string.c +++ b/libbb/time_string.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/trim.c b/libbb/trim.c similarity index 72% rename from busybox/libbb/trim.c rename to libbb/trim.c index 76b87ca1c..cb673cac3 100644 --- a/busybox/libbb/trim.c +++ b/libbb/trim.c @@ -2,27 +2,23 @@ /* * 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. + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public 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. - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ #include diff --git a/busybox/libbb/u_signal_names.c b/libbb/u_signal_names.c similarity index 84% rename from busybox/libbb/u_signal_names.c rename to libbb/u_signal_names.c index 623b10312..aee1db07c 100644 --- a/busybox/libbb/u_signal_names.c +++ b/libbb/u_signal_names.c @@ -1,3 +1,26 @@ +/* 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 #include #include diff --git a/busybox/libbb/unarchive.c b/libbb/unarchive.c similarity index 99% rename from busybox/libbb/unarchive.c rename to libbb/unarchive.c index 4d47eff0e..cb35bc4d3 100644 --- a/busybox/libbb/unarchive.c +++ b/libbb/unarchive.c @@ -410,7 +410,7 @@ file_header_t *get_header_cpio(FILE *src_stream) 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, + &nlink, &cpio_entry->mtime, (unsigned long*)&cpio_entry->size, dummy, &major, &minor, &namesize, dummy); cpio_entry->name = (char *) xcalloc(1, namesize); diff --git a/busybox/libbb/unzip.c b/libbb/unzip.c similarity index 88% rename from busybox/libbb/unzip.c rename to libbb/unzip.c index ee746216d..74624821d 100644 --- a/busybox/libbb/unzip.c +++ b/libbb/unzip.c @@ -7,13 +7,13 @@ * Originally adjusted for busybox by Sven Rudolph * based on gzip sources * - * Adjusted further by Erik Andersen , - * to support files as well as stdin/stdout, and to generally behave itself wrt + * Adjusted further by Erik Andersen 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 - * + * General cleanup to better adhere to the style guide and make use of + * standard busybox functions 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 @@ -73,7 +73,7 @@ static FILE *in_file, *out_file; static unsigned char *window; static unsigned long *crc_table; -static unsigned long crc = 0xffffffffL; /* shift register contents */ +static unsigned long crc; /* shift register contents */ /* Return codes from gzip */ static const int ERROR = 1; @@ -131,6 +131,8 @@ static void make_crc_table() /* 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) */ @@ -388,6 +390,7 @@ static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) 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 */ @@ -399,7 +402,9 @@ static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) md = mask_bits[bd]; for (;;) { /* do until end of block */ while (k < (unsigned) bl) { - b |= ((unsigned long)fgetc(in_file)) << k; + 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) @@ -411,7 +416,9 @@ static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) k -= t->b; e -= 16; while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; + 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); @@ -433,7 +440,9 @@ static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) /* get length of block to copy */ while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; + 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]); @@ -442,7 +451,9 @@ static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) /* decode distance of block to copy */ while (k < (unsigned) bd) { - b |= ((unsigned long)fgetc(in_file)) << k; + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; k += 8; } @@ -454,14 +465,18 @@ static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) k -= t->b; e -= 16; while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; + 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) { - b |= ((unsigned long)fgetc(in_file)) << k; + 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]); @@ -529,6 +544,7 @@ static int inflate_block(int *e) 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; + int input_char; /* make local bit buffer */ b = bb; @@ -536,7 +552,9 @@ static int inflate_block(int *e) /* read in last block bit */ while (k < 1) { - b |= ((unsigned long)fgetc(in_file)) << k; + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; k += 8; } *e = (int) b & 1; @@ -545,7 +563,9 @@ static int inflate_block(int *e) /* read in block type */ while (k < 2) { - b |= ((unsigned long)fgetc(in_file)) << k; + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; k += 8; } t = (unsigned) b & 3; @@ -577,14 +597,18 @@ static int inflate_block(int *e) /* get the length and its complement */ while (k_stored < 16) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + 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) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + 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)) { @@ -596,7 +620,9 @@ static int inflate_block(int *e) /* read and output the compressed data */ while (n--) { while (k_stored < 8) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + 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; @@ -697,21 +723,27 @@ static int inflate_block(int *e) /* read in table lengths */ while (k_dynamic < 5) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + 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) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + 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) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + 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 */ @@ -724,7 +756,9 @@ static int inflate_block(int *e) /* 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; + 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; @@ -750,7 +784,9 @@ static int inflate_block(int *e) i = l = 0; while ((unsigned) i < n) { while (k_dynamic < (unsigned) bl) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + 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; @@ -762,7 +798,9 @@ static int inflate_block(int *e) } else if (j == 16) { /* repeat last length 3 to 6 times */ while (k_dynamic < 2) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + 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); @@ -776,7 +814,9 @@ static int inflate_block(int *e) } } else if (j == 17) { /* 3 to 10 zero length codes */ while (k_dynamic < 3) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + 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); @@ -791,7 +831,9 @@ static int inflate_block(int *e) l = 0; } else { /* j == 18: 11 to 138 zero length codes */ while (k_dynamic < 7) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + 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); @@ -875,6 +917,13 @@ static int inflate() } } 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(); @@ -935,7 +984,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) } method = (int) fgetc(in_file); - if (method != 8) { + if (method != 8) { /* also catches EOF */ error_msg("unknown method %d -- get newer version of gzip", method); exit_code = 1; return -1; @@ -951,6 +1000,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) 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); @@ -958,12 +1008,12 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) /* Discard original name if any */ if ((flags & orig_name) != 0) { - while (fgetc(in_file) != 0); /* null */ + while (fgetc(in_file) != 0 && !feof(in_file)); /* null */ } /* Discard file comment if any */ if ((flags & comment) != 0) { - while (fgetc(in_file) != 0); /* null */ + while (fgetc(in_file) != 0 && !feof(in_file)); /* null */ } if (method < 0) { @@ -980,12 +1030,15 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) 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 @@ -995,18 +1048,20 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) 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)) { + 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 (((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) { + 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 0; + return exit_code; } /* diff --git a/busybox/libbb/vdprintf.c b/libbb/vdprintf.c similarity index 74% rename from busybox/libbb/vdprintf.c rename to libbb/vdprintf.c index 8c3e32a7a..f3c1ed7a9 100644 --- a/busybox/libbb/vdprintf.c +++ b/libbb/vdprintf.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 @@ -37,7 +31,7 @@ extern int vdprintf(int d, const char *format, va_list ap) char buf[BUF_SIZE]; int len; - len = vsprintf(buf, format, ap); + len = vsnprintf(buf, sizeof(buf), format, ap); return write(d, buf, len); } #endif diff --git a/busybox/libbb/verror_msg.c b/libbb/verror_msg.c similarity index 76% rename from busybox/libbb/verror_msg.c rename to libbb/verror_msg.c index b34821561..21cde2047 100644 --- a/busybox/libbb/verror_msg.c +++ b/libbb/verror_msg.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/vherror_msg.c b/libbb/vherror_msg.c similarity index 75% rename from busybox/libbb/vherror_msg.c rename to libbb/vherror_msg.c index ee0bb5009..8a7ada9ec 100644 --- a/busybox/libbb/vherror_msg.c +++ b/libbb/vherror_msg.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,20 +17,16 @@ * You should have received a copy of the GNU General Public 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 #include extern int h_errno; - #include #include "libbb.h" + extern void vherror_msg(const char *s, va_list p) { if(s == 0) diff --git a/busybox/libbb/vperror_msg.c b/libbb/vperror_msg.c similarity index 77% rename from busybox/libbb/vperror_msg.c rename to libbb/vperror_msg.c index ca9361e45..7da5bae0a 100644 --- a/busybox/libbb/vperror_msg.c +++ b/libbb/vperror_msg.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/wfopen.c b/libbb/wfopen.c similarity index 76% rename from busybox/libbb/wfopen.c rename to libbb/wfopen.c index 8b074d2f7..f58ec90c0 100644 --- a/busybox/libbb/wfopen.c +++ b/libbb/wfopen.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 diff --git a/busybox/libbb/xfuncs.c b/libbb/xfuncs.c similarity index 71% rename from busybox/libbb/xfuncs.c rename to libbb/xfuncs.c index eb93bf139..ee90e60a6 100644 --- a/busybox/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -2,9 +2,7 @@ /* * 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. + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +17,6 @@ * You should have received a copy of the GNU General Public 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 @@ -36,26 +30,15 @@ extern void *xmalloc(size_t size) { void *ptr = malloc(size); - - if (!ptr) + if (ptr == NULL && size != 0) error_msg_and_die(memory_exhausted); return ptr; } -extern void *xrealloc(void *old, size_t size) +extern void *xrealloc(void *ptr, 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) + ptr = realloc(ptr, size); + if (ptr == NULL && size != 0) error_msg_and_die(memory_exhausted); return ptr; } @@ -63,7 +46,7 @@ extern void *xrealloc(void *old, size_t size) extern void *xcalloc(size_t nmemb, size_t size) { void *ptr = calloc(nmemb, size); - if (!ptr) + if (ptr == NULL && nmemb != 0 && size != 0) error_msg_and_die(memory_exhausted); return ptr; } @@ -102,6 +85,13 @@ FILE *xfopen(const char *path, const char *mode) 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: diff --git a/busybox/libbb/xgetcwd.c b/libbb/xgetcwd.c similarity index 100% rename from busybox/libbb/xgetcwd.c rename to libbb/xgetcwd.c diff --git a/busybox/libbb/xgethostbyname.c b/libbb/xgethostbyname.c similarity index 99% rename from busybox/libbb/xgethostbyname.c rename to libbb/xgethostbyname.c index 258510332..f859a44af 100644 --- a/busybox/libbb/xgethostbyname.c +++ b/libbb/xgethostbyname.c @@ -2,7 +2,6 @@ /* * Mini xgethostbyname implementation. * - * * Copyright (C) 2001 Matt Kraai . * * This program is free software; you can redistribute it and/or modify @@ -23,9 +22,9 @@ #include extern int h_errno; - #include "libbb.h" + struct hostent *xgethostbyname(const char *name) { struct hostent *retval; diff --git a/busybox/libbb/xreadlink.c b/libbb/xreadlink.c similarity index 100% rename from busybox/libbb/xreadlink.c rename to libbb/xreadlink.c diff --git a/busybox/libbb/xregcomp.c b/libbb/xregcomp.c similarity index 73% rename from busybox/libbb/xregcomp.c rename to libbb/xregcomp.c index 6f5e2f0cb..07cf779d1 100644 --- a/busybox/libbb/xregcomp.c +++ b/libbb/xregcomp.c @@ -2,27 +2,23 @@ /* * 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. + * 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 + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public 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. - * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA */ #include diff --git a/busybox/coreutils/ln.c b/ln.c similarity index 95% rename from busybox/coreutils/ln.c rename to ln.c index 7412a86fd..213db9b72 100644 --- a/busybox/coreutils/ln.c +++ b/ln.c @@ -2,8 +2,8 @@ /* * Mini ln implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/console-tools/loadacm.c b/loadacm.c similarity index 100% rename from busybox/console-tools/loadacm.c rename to loadacm.c diff --git a/busybox/console-tools/loadfont.c b/loadfont.c similarity index 100% rename from busybox/console-tools/loadfont.c rename to loadfont.c diff --git a/busybox/console-tools/loadkmap.c b/loadkmap.c similarity index 100% rename from busybox/console-tools/loadkmap.c rename to loadkmap.c diff --git a/busybox/sysklogd/logger.c b/logger.c similarity index 97% rename from busybox/sysklogd/logger.c rename to logger.c index 9f730915f..37155c933 100644 --- a/busybox/sysklogd/logger.c +++ b/logger.c @@ -2,8 +2,8 @@ /* * Mini logger implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/coreutils/logname.c b/logname.c similarity index 100% rename from busybox/coreutils/logname.c rename to logname.c diff --git a/busybox/logread.c b/logread.c similarity index 100% rename from busybox/logread.c rename to logread.c diff --git a/busybox/basename.c b/losetup.c similarity index 52% rename from busybox/basename.c rename to losetup.c index c15afd533..bfeb6b274 100644 --- a/busybox/basename.c +++ b/losetup.c @@ -1,9 +1,7 @@ -/* vi: set sw=4 ts=4: */ /* - * Mini basename implementation for busybox + * Mini losetup implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * 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 @@ -21,32 +19,40 @@ * */ -/* getopt not needed */ - +#include #include + #include "busybox.h" -#include -extern int basename_main(int argc, char **argv) +int +losetup_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; + 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/busybox/ls.c b/ls.c similarity index 91% rename from busybox/ls.c rename to ls.c index 8d0282dfe..360b95c06 100644 --- a/busybox/ls.c +++ b/ls.c @@ -142,9 +142,17 @@ 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 +#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 @@ -222,7 +230,33 @@ static void newline(void) } /*----------------------------------------------------------------------*/ -#ifdef BB_FEATURE_LS_FILETYPES +#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)) @@ -443,7 +477,7 @@ static void showfiles(struct dnode **dn, int nfiles) if (column_width < len) column_width= len; } - if (column_width >= 6) + if (column_width >= 1) ncols = (int)(terminal_width / (column_width + COLUMN_GAP)); else { ncols = 1; @@ -581,15 +615,15 @@ static struct dnode **list_dir(char *path) 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) +#if defined (BB_FEATURE_LS_FILETYPES) || defined (BB_FEATURE_LS_COLOR) struct stat info; -#endif -#ifdef BB_FEATURE_LS_FILETYPES char append; #endif @@ -642,7 +676,7 @@ static int list_single(struct dnode *dn) break; #endif case LIST_ID_NUMERIC: - printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid); + printf("%-8ld %-8ld", (long)dn->dstat.st_uid, (long)dn->dstat.st_gid); column += 17; break; case LIST_SIZE: @@ -685,18 +719,43 @@ static int list_single(struct dnode *dn) 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(" -> %s", lpath); -#ifdef BB_FEATURE_LS_FILETYPES + 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); @@ -750,6 +809,11 @@ extern int ls_main(int argc, char **argv) #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 diff --git a/busybox/modutils/lsmod.c b/lsmod.c similarity index 77% rename from busybox/modutils/lsmod.c rename to lsmod.c index 76ed2fdd8..a7da1c938 100644 --- a/busybox/modutils/lsmod.c +++ b/lsmod.c @@ -2,8 +2,8 @@ /* * Mini lsmod implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * Modified by Alcove, Julien Gaulmin and * Nicolas Ferre to support pre 2.1 kernels @@ -40,6 +40,32 @@ #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 @@ -99,7 +125,9 @@ extern int lsmod_main(int argc, char **argv) } deps = xmalloc(depsize = 256); - printf("Module Size Used by\n"); + 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) { @@ -116,24 +144,24 @@ extern int lsmod_main(int argc, char **argv) } perror_msg_and_die("module %s: QM_REFS", mn); } - printf("%-20s%8lu%4ld ", mn, info.size, info.usecount); + printf("%-20s%8lu%4ld", mn, info.size, info.usecount); if (info.flags & NEW_MOD_DELETED) - printf("(deleted)"); + printf(" (deleted)"); else if (info.flags & NEW_MOD_INITIALIZING) - printf("(initializing)"); + printf(" (initializing)"); else if (!(info.flags & NEW_MOD_RUNNING)) - printf("(uninitialized)"); + printf(" (uninitialized)"); else { if (info.flags & NEW_MOD_AUTOCLEAN) - printf("(autoclean) "); + printf(" (autoclean) "); if (!(info.flags & NEW_MOD_USED_ONCE)) - printf("(unused)"); + printf(" (unused)"); } - if (count) printf("["); + 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("] "); + if (count) printf("]"); printf("\n"); } @@ -149,7 +177,8 @@ extern int lsmod_main(int argc, char **argv) int fd, i; char line[128]; - puts("Module Size Used by"); + printf("Module Size Used by"); + check_tainted(); fflush(stdout); if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) { diff --git a/busybox/miscutils/makedevs.c b/makedevs.c similarity index 57% rename from busybox/miscutils/makedevs.c rename to makedevs.c index b8c6dd1d8..67b28b534 100644 --- a/busybox/miscutils/makedevs.c +++ b/makedevs.c @@ -17,54 +17,51 @@ 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]; + 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; + mode |= S_IFCHR; break; case 'b': - mode = S_IFBLK; + mode |= S_IFBLK; break; case 'f': - mode = S_IFIFO; + mode |= S_IFIFO; break; default: show_usage(); } - mode |= 0660; while (S <= E) { + int sz; - if (type[0] != 'f') - dev = (major << 8) | Sminor; - strcpy(devname, basedev); + 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 (sbase == 0) { - sprintf(buf, "%d", S); - strcat(devname, buf); - } else { - sbase = 0; - } + /* if mode != S_IFCHR and != S_IFBLK third param in mknod() ignored */ - if (mknod(devname, mode, dev)) - printf("Failed to create: %s\n", devname); + 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++; } diff --git a/busybox/coreutils/md5sum.c b/md5sum.c similarity index 98% rename from busybox/coreutils/md5sum.c rename to md5sum.c index bb4d115ca..da79f83d8 100644 --- a/busybox/coreutils/md5sum.c +++ b/md5sum.c @@ -56,6 +56,12 @@ #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 @@ -401,7 +407,6 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct 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; @@ -434,7 +439,7 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct temp += FI(B,C,D); } temp += cwp[(int)(*pp++)] + *pc++; - temp = CYCLIC (temp, ps[i&3]); + CYCLIC (temp, ps[i&3]); temp += B; A = D; D = C; C = B; B = temp; } @@ -443,7 +448,7 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct for ( i = 0 ; i < 16 ; i++ ) { temp = A + FF(B,C,D) + cwp[(int)(*pp++)] + *pc++; - temp = CYCLIC (temp, ps[i&3]); + CYCLIC (temp, ps[i&3]); temp += B; A = D; D = C; C = B; B = temp; } @@ -451,21 +456,21 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct ps += 4; for ( i = 0 ; i < 16 ; i++ ) { temp = A + FG(B,C,D) + cwp[(int)(*pp++)] + *pc++; - temp = CYCLIC (temp, ps[i&3]); + 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]); + 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]); + CYCLIC (temp, ps[i&3]); temp += B; A = D; D = C; C = B; B = temp; } @@ -489,11 +494,6 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct } \ 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 @@ -699,12 +699,12 @@ static int split_3(char *s, s[i++] = '\0'; - if (s[i] != ' ' && s[i++] != '*') + 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]; + *w = &s[++i]; if (escaped_filename) { /* Translate each `\n' string in the file name to a NEWLINE, diff --git a/busybox/mk_loop_h.sh b/mk_loop_h.sh similarity index 90% rename from busybox/mk_loop_h.sh rename to mk_loop_h.sh index 71c987376..5adfbd55f 100755 --- a/busybox/mk_loop_h.sh +++ b/mk_loop_h.sh @@ -15,7 +15,7 @@ # 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 +if [ -f ${LINUXDIR:-/usr}/include/linux/posix_types.h ]; then echo '#include ' echo '#undef dev_t' echo '#define dev_t __kernel_dev_t' @@ -27,7 +27,7 @@ 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 +if [ -f ${LINUXDIR:-/usr}/include/linux/loop.h ]; then echo '#include ' else echo '#include "real_loop.h"' diff --git a/busybox/coreutils/mkdir.c b/mkdir.c similarity index 100% rename from busybox/coreutils/mkdir.c rename to mkdir.c diff --git a/busybox/coreutils/mkfifo.c b/mkfifo.c similarity index 100% rename from busybox/coreutils/mkfifo.c rename to mkfifo.c diff --git a/busybox/mkfs_minix.c b/mkfs_minix.c similarity index 100% rename from busybox/mkfs_minix.c rename to mkfs_minix.c diff --git a/busybox/coreutils/mknod.c b/mknod.c similarity index 96% rename from busybox/coreutils/mknod.c rename to mknod.c index b4d4b82a1..10d026ce3 100644 --- a/busybox/coreutils/mknod.c +++ b/mknod.c @@ -3,6 +3,7 @@ * Mini mknod implementation for busybox * * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/util-linux/mkswap.c b/mkswap.c similarity index 98% rename from busybox/util-linux/mkswap.c rename to mkswap.c index f72c7009a..bbf02095c 100644 --- a/busybox/util-linux/mkswap.c +++ b/mkswap.c @@ -81,7 +81,7 @@ static struct swap_header_v1 { unsigned int badpages[1]; } *p; -static void init_signature_page() +static inline void init_signature_page() { pagesize = getpagesize(); @@ -94,7 +94,7 @@ static void init_signature_page() p = (struct swap_header_v1 *) signature_page; } -static void write_signature(char *sig) +static inline void write_signature(char *sig) { char *sp = (char *) signature_page; @@ -147,7 +147,7 @@ It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips, #define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int)) -static void bit_set(unsigned int *addr, unsigned int nr) +static inline void bit_set(unsigned int *addr, unsigned int nr) { unsigned int r, m; @@ -179,7 +179,7 @@ static void page_ok(int page) bit_set(signature_page, page); } -static void page_bad(int page) +static inline void page_bad(int page) { if (version == 0) bit_test_and_clear(signature_page, page); diff --git a/busybox/miscutils/mktemp.c b/mktemp.c similarity index 100% rename from busybox/miscutils/mktemp.c rename to mktemp.c diff --git a/modprobe.c b/modprobe.c new file mode 100644 index 000000000..3cca57dee --- /dev/null +++ b/modprobe.c @@ -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 +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#define BB_FEATURE_MODPROBE_DEPEND + +#ifdef BB_FEATURE_MODPROBE_DEPEND + +#include + +/* 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/busybox/util-linux/more.c b/more.c similarity index 94% rename from busybox/util-linux/more.c rename to more.c index 780cddf66..f4958802b 100644 --- a/busybox/util-linux/more.c +++ b/more.c @@ -2,12 +2,11 @@ /* * Mini more implementation for busybox * - * * Copyright (C) 1995, 1996 by Bruce Perens . * - * Latest version blended together by Erik Andersen , - * based on the original more implementation by Bruce, and code from the - * Debian boot-floppies team. + * Latest version blended by Erik Andersen , 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 * @@ -88,11 +87,8 @@ extern int more_main(int argc, char **argv) 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); @@ -109,6 +105,7 @@ extern int more_main(int argc, char **argv) if(file==0) goto loop; + st.st_size = 0; fstat(fileno(file), &st); if(please_display_more_prompt>0) @@ -128,7 +125,7 @@ extern int more_main(int argc, char **argv) if (please_display_more_prompt>0) { len = printf("--More-- "); - if (file != stdin) { + if (file != stdin && st.st_size > 0) { #if _FILE_OFFSET_BITS == 64 len += printf("(%d%% of %lld bytes)", (int) (100 * ((double) ftell(file) / diff --git a/busybox/util-linux/mount.c b/mount.c similarity index 85% rename from busybox/util-linux/mount.c rename to mount.c index af57a7623..aa77f9818 100644 --- a/busybox/util-linux/mount.c +++ b/mount.c @@ -3,6 +3,7 @@ * Mini mount implementation for busybox * * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +25,7 @@ * * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab. * - * 1999-10-07 Erik Andersen , . + * 1999-10-07 Erik Andersen . * 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 @@ -100,6 +101,7 @@ 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}, @@ -127,7 +129,7 @@ do_mount(char *specialfile, char *dir, char *filesystemtype, char *lofile = NULL; #endif - if (fakeIt == FALSE) + if (! fakeIt) { #if defined BB_FEATURE_MOUNT_LOOP if (use_loop==TRUE) { @@ -163,7 +165,7 @@ do_mount(char *specialfile, char *dir, char *filesystemtype, if (status == 0 || fakeIt==TRUE) { #if defined BB_FEATURE_MTAB_SUPPORT - if (useMtab == TRUE) { + if (useMtab) { erase_mtab(specialfile); // Clean any stale entries write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts); } @@ -186,10 +188,15 @@ do_mount(char *specialfile, char *dir, char *filesystemtype, } +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) +parse_mount_options(char *options, int *flags, char **strflags) { while (options) { int gotone = FALSE; @@ -210,20 +217,16 @@ parse_mount_options(char *options, int *flags, char *strflags) f++; } #if defined BB_FEATURE_MOUNT_LOOP - if (gotone == FALSE && !strcasecmp("loop", options)) { /* loop device support */ + if (!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) { + if (**strflags) /* have previous parsed options */ + paste_str(strflags, ","); + paste_str(strflags, options); } - if (gotone == FALSE) - strcat(strflags, options); if (comma) { *comma = ','; options = ++comma; @@ -261,7 +264,7 @@ mount_one(char *blockDevice, char *directory, char *filesystemType, status = do_mount(blockDevice, directory, filesystemType, flags | MS_MGC_VAL, string_flags, useMtab, fakeIt, mtab_opts, mount_all); - if (status == TRUE) + if (status) break; } } @@ -286,7 +289,7 @@ mount_one(char *blockDevice, char *directory, char *filesystemType, status = do_mount(blockDevice, directory, filesystemType, flags | MS_MGC_VAL, string_flags, useMtab, fakeIt, mtab_opts, mount_all); - if (status == TRUE) + if (status) break; } } @@ -299,8 +302,8 @@ mount_one(char *blockDevice, char *directory, char *filesystemType, fakeIt, mtab_opts, mount_all); } - if (status == FALSE) { - if (whineOnErrors == TRUE) { + if (! status) { + if (whineOnErrors) { perror_msg("Mounting %s on %s failed", blockDevice, directory); } return (FALSE); @@ -308,7 +311,7 @@ mount_one(char *blockDevice, char *directory, char *filesystemType, return (TRUE); } -void show_mounts(void) +static void show_mounts(char *onlytype) { #if defined BB_FEATURE_USE_DEVPS_PATCH int fd, i, numfilesystems; @@ -332,10 +335,12 @@ void show_mounts(void) 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); + 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 @@ -355,8 +360,10 @@ void show_mounts(void) 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); + 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); @@ -373,31 +380,33 @@ void show_mounts(void) 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; + 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; - int fstabmount = FALSE; + 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); + 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; @@ -419,12 +428,13 @@ extern int mount_main(int argc, char **argv) } if (!all && optind == argc) - show_mounts(); + show_mounts(got_filesystemType ? filesystemType : 0); if (optind < argc) { /* if device is a filename get its real path */ if (stat(argv[optind], &statbuf) == 0) { - device = simplify_path(argv[optind]); + char *tmp = simplify_path(argv[optind]); + safe_strncpy(device, tmp, PATH_MAX); } else { safe_strncpy(device, argv[optind], PATH_MAX); } @@ -433,44 +443,41 @@ extern int mount_main(int argc, char **argv) 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 (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 == FALSE && optind + 1 == argc && ( + if (! all && optind + 1 == argc && ( (strcmp(device, m->mnt_fsname) != 0) && (strcmp(device, m->mnt_dir) != 0) ) ) { continue; } - if (all == TRUE && ( // If we're mounting 'all' + 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 == TRUE || flags == 0) { // Allow single mount to override fstab flags + if (all || flags == 0) { // Allow single mount to override fstab flags flags = 0; - *string_flags = '\0'; - parse_mount_options(m->mnt_opts, &flags, string_flags); + string_flags[0] = 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); + filesystemType = xstrdup(m->mnt_type); singlemount: - string_flags = strdup(string_flags); + extra_opts = string_flags; rc = EXIT_SUCCESS; #ifdef BB_NFSMOUNT - if (strchr(device, ':') != NULL) + 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"); @@ -482,13 +489,13 @@ extern int mount_main(int argc, char **argv) string_flags, useMtab, fakeIt, extra_opts, TRUE, all)) rc = EXIT_FAILURE; - if (all == FALSE) + if (! all) break; } - if (fstabmount == TRUE) + if (f) endmntent(f); - if (all == FALSE && fstabmount == TRUE && m == NULL) + if (! all && f && m == NULL) fprintf(stderr, "Can't find %s in /etc/fstab\n", device); return rc; diff --git a/busybox/msh.c b/msh.c similarity index 56% rename from busybox/msh.c rename to msh.c index e16d6f304..f3890d7c2 100644 --- a/busybox/msh.c +++ b/msh.c @@ -3,7 +3,8 @@ * Minix shell port for busybox * * This version of the Minix shell was adapted for use in busybox - * by Erik Andersen + * by Erik Andersen and + * Vladimir Oleynik * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,170 +19,192 @@ * You should have received a copy of the GNU General Public 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 -#include -#include +/* -------- sh.h -------- */ + +#include +#include +#include +#include #include -#include -#include +#include #include +#include +#include #include -#include -#include -#include #include -#include -#include #include -#include +#include #include +#include +#include + #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 -/* -------- sh.h -------- */ /* * shell */ -#define LINELIM 2100 -#define NPUSH 8 /* limit to input nesting */ +#define LINELIM 4096 +#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 */ +#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) +#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 */ +typedef void xint; /* base type of jmp_buf, for not broken compilers */ /* * shell components */ -#define QUOTE 0200 +#define QUOTE 0200 -#define NOBLOCK ((struct op *)NULL) -#define NOWORD ((char *)NULL) -#define NOWORDS ((char **)NULL) -#define NOPIPE ((int *)NULL) +#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, < > >>) */ + 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 */ + 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 & */ +#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 */ +#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; -} ; +#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 */ + 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 */ +#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 /* >&- */ -static struct wdblock *wdlist; -static struct wdblock *iolist; +#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; +static struct env { + char *linep; + struct io *iobase; + struct io *iop; + xint *errpt; + int iofd; + struct env *oenv; } e; /* @@ -194,511 +217,272 @@ static struct env { * -x: trace * -u: unset variables net diagnostic */ -static char *flag; +static char *flag; -static char *null; /* null value for variable */ -static int intr; /* interrupt pending */ +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 char *trap[_NSIG + 1]; +static char ourtrap[_NSIG + 1]; +static int trapset; /* trap pending */ -static int heedint; /* heed interrupt signals */ +static int heedint; /* heed interrupt signals */ -static int yynerrs; /* yacc */ +static int yynerrs; /* yacc */ -static char line[LINELIM]; -static char *elinep; +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 ); +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); /* 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 ); +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; +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 ); + +#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 */ + 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 */ + 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 +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 */ +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 */ +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) +#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)()); +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 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); +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; /* 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))) +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); -/* -------- word.h -------- */ +static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */ -#define NSTART 16 /* default number of words to allow for initially */ +#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen))) +#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen))) -struct wdblock { - short w_bsize; - short w_nword; - /* bounds are arbitrary */ - char *w_words[1]; -}; +/* -------- word.h -------- */ -static struct wdblock *addword (char *wd, struct wdblock *wb ); -static struct wdblock *newword (int nw ); -static char **getwords (struct wdblock *wb ); +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])) +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); -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}, -}; +static int areanum; /* current allocation area */ +#define NEW(type) (type *)getcell(sizeof(type)) +/* -------- sh.c -------- */ +/* + * shell + */ -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} +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 }; -/* 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; +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; -#ifdef BB_FEATURE_COMMAND_EDITING -static char * current_prompt; -#endif +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; +}; -/* -------- sh.c -------- */ -/* - * shell - */ +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 -extern int msh_main(int argc, char **argv) +#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)(); + int (*iof) (); initarea(); if ((ap = environ) != NULL) { @@ -719,7 +503,13 @@ extern int msh_main(int argc, char **argv) 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"); @@ -736,6 +526,7 @@ extern int msh_main(int argc, char **argv) if (prompt->value == null) #endif setval(prompt, "$ "); + if (geteuid() == 0) { setval(prompt, "# "); prompt->status &= ~EXPORT; @@ -750,8 +541,8 @@ extern int msh_main(int argc, char **argv) cflag = 0; name = *argv++; if (--argc >= 1) { - if(argv[0][0] == '-' && argv[0][1] != '\0') { - for (s = argv[0]+1; *s; s++) + if (argv[0][0] == '-' && argv[0][1] != '\0') { + for (s = argv[0] + 1; *s; s++) switch (*s) { case 'c': prompt->status &= ~EXPORT; @@ -762,7 +553,7 @@ extern int msh_main(int argc, char **argv) if (--argc > 0) PUSHIO(aword, *++argv, iof = nlchar); break; - + case 'q': qflag = SIG_DFL; break; @@ -776,12 +567,12 @@ extern int msh_main(int argc, char **argv) setval(prompt, ""); iof = linechar; break; - + case 'i': interactive++; default: - if (*s>='a' && *s<='z') - flag[(int)*s]++; + if (*s >= 'a' && *s <= 'z') + flag[(int) *s]++; } } else { argv--; @@ -820,67 +611,62 @@ extern int msh_main(int argc, char **argv) dolv = argv; dolc = argc; dolv[0] = name; - if (dolc > 1) { + if (dolc > 1) for (ap = ++argv; --argc > 0;) { - if (assign(*ap = *argv++, !COPYV)) { - dolc--; /* keyword */ - } else { + if (assign(*ap = *argv++, !COPYV)) + dolc--; /* keyword */ + else ap++; - } } - } setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); for (;;) { - if (interactive && e.iop <= iostack) { + if (interactive && e.iop <= iostack) #ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=prompt->value; + current_prompt = prompt->value; #else prs(prompt->value); #endif - } onecommand(); + /* Ensure that getenv("PATH") stays current */ + setenv("PATH", path->value, 1); } } -static void -setdash() +void setdash() { - register char *cp; - register int c; - char m['z'-'a'+1]; + register char *cp, c; + char m['z' - 'a' + 1]; cp = m; - for (c='a'; c<='z'; c++) - if (flag[c]) + for (c = 'a'; c <= 'z'; c++) + if (flag[(int) c]) *cp++ = c; *cp = 0; setval(lookup("-"), m); } -static int -newfile(s) +int newfile(s) register char *s; { - register int f; + int f; if (strcmp(s, "-") != 0) { f = open(s, 0); if (f < 0) { prs(s); err(": cannot open"); - return(1); + return (1); } } else f = 0; next(remap(f)); - return(0); + return (0); } -static void -onecommand() +void onecommand() { - register int i; + int i; jmp_buf m1; while (e.oenv) @@ -898,7 +684,7 @@ onecommand() inparse = 1; intr = 0; execflg = 0; - setjmp(failpt = m1); /* Bruce Evans' fix */ + setjmp(failpt = m1); /* Bruce Evans' fix */ if (setjmp(failpt = m1) || yyparse() || intr) { while (e.oenv) quitenv(); @@ -925,30 +711,27 @@ onecommand() } } -static void -fail() +void fail() { longjmp(failpt, 1); /* NOTREACHED */ } -static void -leave() +void leave() { if (execflg) fail(); scraphere(); freehere(1); runtrap(0); - exit(exstat); + _exit(exstat); /* NOTREACHED */ } -static void -warn(s) +void warn(s) register char *s; { - if(*s) { + if (*s) { prs(s); exstat = -1; } @@ -957,8 +740,7 @@ register char *s; leave(); } -static void -err(s) +void err(s) char *s; { warn(s); @@ -972,15 +754,14 @@ char *s; e.iop = e.iobase = iostack; } -static int -newenv(f) +int newenv(f) int f; { register struct env *ep; if (f) { quitenv(); - return(1); + return (1); } ep = (struct env *) space(sizeof(*ep)); if (ep == NULL) { @@ -991,20 +772,19 @@ int f; *ep = e; e.oenv = ep; e.errpt = errpt; - return(0); + return (0); } -static void -quitenv() +void quitenv() { register struct env *ep; - register int fd; + int fd; if ((ep = e.oenv) != NULL) { fd = e.iofd; e = *ep; /* should close `'d files */ - DELETE(ep); + freecell(ep); while (--fd >= e.iofd) close(fd); } @@ -1013,39 +793,35 @@ quitenv() /* * Is any character from s1 in s2? */ -static int -anys(s1, s2) +int anys(s1, s2) register char *s1, *s2; { while (*s1) if (any(*s1++, s2)) - return(1); - return(0); + return (1); + return (0); } /* * Is character c in s? */ -static int -any(c, s) +int any(c, s) register int c; register char *s; { while (*s) if (*s++ == c) - return(1); - return(0); + return (1); + return (0); } -static char * -putn(n) +char *putn(n) register int n; { - return(itoa(n, -1)); + return (itoa(n, -1)); } -static char * -itoa(u, n) +char *itoa(u, n) register unsigned u; int n; { @@ -1058,27 +834,25 @@ int n; m++; u = -u; } - cp = s+sizeof(s); + cp = s + sizeof(s); *--cp = 0; do { - *--cp = u%10 + '0'; + *--cp = u % 10 + '0'; u /= 10; } while (--n > 0 || u); if (m) *--cp = '-'; - return(cp); + return (cp); } -static void -next(f) +void next(f) int f; { PUSHIO(afile, f, filechar); } -static void -onintr(s) -int s; /* ANSI C requires a parameter */ +void onintr(s) +int s; /* ANSI C requires a parameter */ { signal(SIGINT, onintr); intr = 1; @@ -1087,52 +861,65 @@ int s; /* ANSI C requires a parameter */ prs("\n"); fail(); } - } - else if (heedint) { + } else if (heedint) { execflg = 0; leave(); } } -static char * -space(n) +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); + return (cp); } -static char * -strsave(s, a) +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); + if ((cp = space(strlen(s) + 1)) != NULL) { + setarea((char *) cp, a); + for (xp = cp; (*xp++ = *s++) != '\0';); + return (cp); } - return(""); + return (""); } /* * trap handling */ -static void -sig(i) +void sig(i) register int i; { trapset = i; signal(i, sig); } -static void runtrap(i) +void runtrap(i) int i; { char *trapstr; @@ -1152,8 +939,7 @@ int i; * not previously there, enter it now and * return a null value. */ -static struct var * -lookup(n) +struct var *lookup(n) register char *n; { register struct var *vp; @@ -1161,46 +947,44 @@ register char *n; register int c; static struct var dummy; - if (isdigit(*n)) { + if (digit(*n)) { dummy.name = n; - for (c = 0; isdigit(*n) && c < 1000; n++) - c = c*10 + *n-'0'; + 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); + dummy.value = c <= dolc ? dolv[c] : null; + return (&dummy); } for (vp = vlist; vp; vp = vp->next) if (eqname(vp->name, n)) - return(vp); + return (vp); cp = findeq(n); - vp = (struct var *)space(sizeof(*vp)); - if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) { + vp = (struct var *) space(sizeof(*vp)); + if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) { dummy.name = dummy.value = ""; - return(&dummy); + return (&dummy); } - for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++) - ; + for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++); if (*cp == 0) *cp = '='; *++cp = 0; - setarea((char *)vp, 0); - setarea((char *)vp->name, 0); + setarea((char *) vp, 0); + setarea((char *) vp->name, 0); vp->value = null; vp->next = vlist; vp->status = GETCELL; vlist = vp; - return(vp); + return (vp); } /* * give variable at `vp' the value `val'. */ -static void -setval(vp, val) +void setval(vp, val) struct var *vp; char *val; { - nameval(vp, val, (char *)NULL); + nameval(vp, val, (char *) NULL); } /* @@ -1210,8 +994,7 @@ char *val; * this is all so that exporting * values is reasonably painless. */ -static void -nameval(vp, val, name) +void nameval(vp, val, name) register struct var *vp; char *val, *name; { @@ -1221,128 +1004,118 @@ char *val, *name; if (vp->status & RONLY) { for (xp = vp->name; *xp && *xp != '=';) - putc(*xp++, stderr); + put1c(*xp++); err(" is read-only"); return; } fl = 0; if (name == NULL) { - xp = space(strlen(vp->name)+strlen(val)+2); + xp = space(strlen(vp->name) + strlen(val) + 2); if (xp == 0) return; /* make string: name=value */ - setarea((char *)xp, 0); + setarea((char *) xp, 0); name = xp; - for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++) - ; + for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++); if (*xp++ == 0) xp[-1] = '='; nv = xp; - for (cp = val; (*xp++ = *cp++) != '\0';) - ; + for (cp = val; (*xp++ = *cp++) != '\0';); val = nv; fl = GETCELL; } if (vp->status & GETCELL) - freecell(vp->name); /* form new string `name=value' */ + freecell(vp->name); /* form new string `name=value' */ vp->name = name; vp->value = val; vp->status |= fl; } -static void -export(vp) +void export(vp) struct var *vp; { vp->status |= EXPORT; } -static void -ronly(vp) +void ronly(vp) struct var *vp; { - if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */ + if (letter(vp->name[0])) /* not an internal symbol ($# etc) */ vp->status |= RONLY; } -static int -isassign(s) +int isassign(s) register char *s; { - if (!isalpha((int)*s) && *s != '_') - return(0); + if (!letter((int) *s)) + return (0); for (; *s != '='; s++) - if (*s == 0 || (!isalnum(*s) && *s != '_')) - return(0); - return(1); + if (*s == 0 || !letnum(*s)) + return (0); + return (1); } -static int -assign(s, cf) +int assign(s, cf) register char *s; int cf; { register char *cp; struct var *vp; - if (!isalpha(*s) && *s != '_') - return(0); + if (!letter(*s)) + return (0); for (cp = s; *cp != '='; cp++) - if (*cp == 0 || (!isalnum(*cp) && *cp != '_')) - return(0); + if (*cp == 0 || !letnum(*cp)) + return (0); vp = lookup(s); - nameval(vp, ++cp, cf == COPYV? (char *)NULL: s); + nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s); if (cf != COPYV) vp->status &= ~GETCELL; - return(1); + return (1); } -static int -checkname(cp) +int checkname(cp) register char *cp; { - if (!isalpha(*cp++) && *(cp-1) != '_') - return(0); + if (!letter(*cp++)) + return (0); while (*cp) - if (!isalnum(*cp++) && *(cp-1) != '_') - return(0); - return(1); + if (!letnum(*cp++)) + return (0); + return (1); } -static void -putvlist(f, out) +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 & 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, vp->name, (int) (findeq(vp->name) - vp->name)); write(out, "\n", 1); } } -static int -eqname(n1, n2) +int eqname(n1, n2) register char *n1, *n2; { for (; *n1 != '=' && *n1 != 0; n1++) if (*n2++ != *n1) - return(0); - return(*n2 == 0 || *n2 == '='); + return (0); + return (*n2 == 0 || *n2 == '='); } -static char * -findeq(cp) +static char *findeq(cp) register char *cp; { while (*cp != '\0' && *cp != '=') cp++; - return(cp); + return (cp); } /* -------- gmatch.c -------- */ @@ -1353,50 +1126,48 @@ register char *cp; * Match a pattern as in sh(1). */ -#define CMASK 0377 -#define QUOTE 0200 -#define QMASK (CMASK&~QUOTE) -#define NOT '!' /* might use ^ */ +#define CMASK 0377 +#define QUOTE 0200 +#define QMASK (CMASK&~QUOTE) +#define NOT '!' /* might use ^ */ -static int -gmatch(s, p) +int gmatch(s, p) register char *s, *p; { register int sc, pc; if (s == NULL || p == NULL) - return(0); + return (0); while ((pc = *p++ & CMASK) != '\0') { sc = *s++ & QMASK; switch (pc) { case '[': if ((p = cclass(p, sc)) == NULL) - return(0); + return (0); break; case '?': if (sc == 0) - return(0); + return (0); break; case '*': s--; do { if (*p == '\0' || gmatch(s, p)) - return(1); + return (1); } while (*s++ != '\0'); - return(0); + return (0); default: - if (sc != (pc&~QUOTE)) - return(0); + if (sc != (pc & ~QUOTE)) + return (0); } } - return(*s == 0); + return (*s == 0); } -static char * -cclass(p, sub) +static char *cclass(p, sub) register char *p; register int sub; { @@ -1407,7 +1178,7 @@ register int sub; found = not; do { if (*p == '\0') - return((char *)NULL); + return ((char *) NULL); c = *p & CMASK; if (p[1] == '-' && p[2] != ']') { d = p[2] & CMASK; @@ -1417,29 +1188,44 @@ register int sub; if (c == sub || (c <= sub && sub <= d)) found = !not; } while (*++p != ']'); - return(found? p+1: (char *)NULL); + 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. - * 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() +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) + while ((int) sbrk(0) & ALIGN) sbrk(1); - areabot = (struct region *)sbrk(REGSIZE); + areabot = (struct region *) sbrk(REGSIZE); areabot->next = areabot; areabot->area = BUSY; @@ -1447,22 +1233,20 @@ initarea() areanxt = areabot; } -char * -getcell(nbytes) +char *getcell(nbytes) unsigned nbytes; { - register int nregio; + int nregio; register struct region *p, *q; - register int i; + int i; + + if (nbytes == 0) /* silly and defeats the algorithm */ + Abort(); - if (nbytes == 0) { - puts("getcell(0)"); - abort(); - } /* silly and defeats the algorithm */ /* * round upwards and add administration area */ - nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1; + nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1; for (p = areanxt;;) { if (p->area > areanum) { /* @@ -1481,21 +1265,20 @@ unsigned nbytes; break; } i = nregio >= GROWBY ? nregio : GROWBY; - p = (struct region *)sbrk(i * REGSIZE); - if (p == (struct region *)-1) - return((char *)NULL); + 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 */ - } + 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: + found: /* * we found a FREE area big enough, pointed to by 'p', and up to 'q' */ @@ -1504,25 +1287,23 @@ unsigned nbytes; /* * split into requested area and rest */ - if (areanxt+1 > q) { - puts("OOM"); - abort(); /* insufficient space left for admin */ - } + 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)); + return ((char *) (p + 1)); } -static void -freecell(cp) -char *cp; + +void freecell(void *cp) { register struct region *p; - if ((p = (struct region *)cp) != NULL) { + if ((p = (struct region *) cp) != NULL) { p--; if (p < areanxt) areanxt = p; @@ -1530,8 +1311,7 @@ char *cp; } } -static void -freearea(a) +void freearea(a) register int a; { register struct region *p, *top; @@ -1542,26 +1322,23 @@ register int a; p->area = FREE; } -static void -setarea(cp,a) +void setarea(cp, a) char *cp; int a; { register struct region *p; - if ((p = (struct region *)cp) != NULL) - (p-1)->area = a; + if ((p = (struct region *) cp) != NULL) + (p - 1)->area = a; } -int -getarea(cp) +int getarea(cp) char *cp; { - return ((struct region*)cp-1)->area; + return ((struct region *) cp - 1)->area; } -static void -garbage() +void garbage() { register struct region *p, *q, *top; @@ -1573,14 +1350,6 @@ garbage() 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 -------- */ @@ -1588,20 +1357,85 @@ garbage() * 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() +int yyparse() { - startl = 1; + startl = 1; peeksym = 0; yynerrs = 0; outtree = c_list(); musthave('\n', 0); - return(yynerrs!=0); + return (yynerrs != 0); } -static struct op * -pipeline(cf) +static struct op *pipeline(cf) int cf; { register struct op *t, *p; @@ -1620,11 +1454,10 @@ int cf; } peeksym = c; } - return(t); + return (t); } -static struct op * -andor() +static struct op *andor() { register struct op *t, *p; register int c; @@ -1634,38 +1467,37 @@ andor() while ((c = yylex(0)) == LOGAND || c == LOGOR) { if ((p = pipeline(CONTIN)) == NULL) SYNTAXERR; - t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS); + t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS); } peeksym = c; } - return(t); + return (t); } -static struct op * -c_list() +static struct op *c_list() { register struct op *t, *p; register int c; t = andor(); if (t != NULL) { - if((peeksym = yylex(0)) == '&') + if ((peeksym = yylex(0)) == '&') t = block(TASYNC, t, NOBLOCK, NOWORDS); - while ((c = yylex(0)) == ';' || c == '&' || (multiline && c == '\n')) { + while ((c = yylex(0)) == ';' || c == '&' + || (multiline && c == '\n')) { if ((p = andor()) == NULL) - return(t); - if((peeksym = yylex(0)) == '&') + return (t); + if ((peeksym = yylex(0)) == '&') p = block(TASYNC, p, NOBLOCK, NOWORDS); t = list(t, p); } peeksym = c; } - return(t); + return (t); } -static int -synio(cf) +static int synio(cf) int cf; { register struct ioword *iop; @@ -1674,7 +1506,7 @@ int cf; if ((c = yylex(cf)) != '<' && c != '>') { peeksym = c; - return(0); + return (0); } i = yylval.i; musthave(WORD, 0); @@ -1682,11 +1514,10 @@ int cf; iounit = IODEFAULT; if (i & IOHERE) markhere(yylval.cp, iop); - return(1); + return (1); } -static void -musthave(c, cf) +static void musthave(c, cf) int c, cf; { if ((peeksym = yylex(cf)) != c) @@ -1694,8 +1525,7 @@ int c, cf; peeksym = 0; } -static struct op * -simple() +static struct op *simple() { register struct op *t; @@ -1717,13 +1547,12 @@ simple() break; default: - return(t); + return (t); } } } -static struct op * -nested(type, mark) +static struct op *nested(type, mark) int type, mark; { register struct op *t; @@ -1732,11 +1561,10 @@ int type, mark; t = c_list(); musthave(mark, 0); multiline--; - return(block(type, t, NOBLOCK, NOWORDS)); + return (block(type, t, NOBLOCK, NOWORDS)); } -static struct op * -command(cf) +static struct op *command(cf) int cf; { register struct op *t; @@ -1754,7 +1582,7 @@ int cf; peeksym = c; if ((t = simple()) == NULL) { if (iolist == NULL) - return((struct op *)NULL); + return ((struct op *) NULL); t = newtp(); t->type = TCOM; } @@ -1786,7 +1614,7 @@ int cf; case UNTIL: multiline++; t = newtp(); - t->type = c == WHILE? TWHILE: TUNTIL; + t->type = c == WHILE ? TWHILE : TUNTIL; t->left = c_list(); t->right = dogroup(1); t->words = NULL; @@ -1817,39 +1645,36 @@ int cf; multiline--; break; } - while (synio(0)) - ; + while (synio(0)); t = namelist(t); iolist = iosave; - return(t); + return (t); } -static struct op * -dogroup(onlydone) +static struct op *dogroup(onlydone) int onlydone; { register int c; - register struct op *mylist; + register struct op *oplist; c = yylex(CONTIN); if (c == DONE && onlydone) - return((struct op *)NULL); + return ((struct op *) NULL); if (c != DO) SYNTAXERR; - mylist = c_list(); + oplist = c_list(); musthave(DONE, 0); - return(mylist); + return (oplist); } -static struct op * -thenpart() +static struct op *thenpart() { register int c; register struct op *t; if ((c = yylex(0)) != THEN) { peeksym = c; - return((struct op *)NULL); + return ((struct op *) NULL); } t = newtp(); t->type = 0; @@ -1857,11 +1682,10 @@ thenpart() if (t->left == NULL) SYNTAXERR; t->right = elsepart(); - return(t); + return (t); } -static struct op * -elsepart() +static struct op *elsepart() { register int c; register struct op *t; @@ -1870,34 +1694,32 @@ elsepart() case ELSE: if ((t = c_list()) == NULL) SYNTAXERR; - return(t); + return (t); case ELIF: t = newtp(); t->type = TELIF; t->left = c_list(); t->right = thenpart(); - return(t); + return (t); default: peeksym = c; - return((struct op *)NULL); + return ((struct op *) NULL); } } -static struct op * -caselist() +static struct op *caselist() { register struct op *t; t = NULL; while ((peeksym = yylex(CONTIN)) != ESAC) t = list(t, casepart()); - return(t); + return (t); } -static struct op * -casepart() +static struct op *casepart() { register struct op *t; @@ -1908,11 +1730,10 @@ casepart() t->left = c_list(); if ((peeksym = yylex(CONTIN)) != ESAC) musthave(BREAK, CONTIN); - return(t); + return (t); } -static char ** -pattern() +static char **pattern() { register int c, cf; @@ -1924,42 +1745,39 @@ pattern() } while ((c = yylex(0)) == '|'); peeksym = c; word(NOWORD); - return(copyw()); + return (copyw()); } -static char ** -wordlist() +static char **wordlist() { register int c; if ((c = yylex(0)) != IN) { peeksym = c; - return((char **)NULL); + return ((char **) NULL); } startl = 0; while ((c = yylex(0)) == WORD) word(yylval.cp); word(NOWORD); peeksym = c; - return(copyw()); + return (copyw()); } /* * supporting functions */ -static struct op * -list(t1, t2) +static struct op *list(t1, t2) register struct op *t1, *t2; { if (t1 == NULL) - return(t2); + return (t2); if (t2 == NULL) - return(t1); - return(block(TLIST, t1, t2, NOWORDS)); + return (t1); + return (block(TLIST, t1, t2, NOWORDS)); } -static struct op * -block(type, t1, t2, wp) +static struct op *block(type, t1, t2, wp) int type; struct op *t1, *t2; char **wp; @@ -1971,42 +1789,65 @@ char **wp; t->left = t1; t->right = t2; t->words = wp; - return(t); + return (t); } -static int -rlookup(n) +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); + return (rp->r_val); + return (0); } -static struct op * -newtp() +static struct op *newtp() { register struct op *t; - t = (struct op *)tree(sizeof(*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); + return (t); } -static struct op * -namelist(t) +static struct op *namelist(t) register struct op *t; { if (iolist) { - iolist = addword((char *)NULL, iolist); + iolist = addword((char *) NULL, iolist); t->ioact = copyio(); } else t->ioact = NULL; @@ -2016,42 +1857,38 @@ register struct op *t; t->ioact = t->left->ioact; t->left->ioact = NULL; } - return(t); + return (t); } word(NOWORD); t->words = copyw(); - return(t); + return (t); } -static char ** -copyw() +static char **copyw() { register char **wd; wd = getwords(wdlist); wdlist = 0; - return(wd); + return (wd); } -static void -word(cp) +static void word(cp) char *cp; { wdlist = addword(cp, wdlist); } -static struct ioword ** -copyio() +static struct ioword **copyio() { register struct ioword **iop; iop = (struct ioword **) getwords(iolist); iolist = 0; - return(iop); + return (iop); } -static struct ioword * -io(u, f, cp) +static struct ioword *io(u, f, cp) int u; int f; char *cp; @@ -2062,32 +1899,28 @@ char *cp; iop->io_unit = u; iop->io_flag = f; iop->io_name = cp; - iolist = addword((char *)iop, iolist); - return(iop); + iolist = addword((char *) iop, iolist); + return (iop); } -static void -zzerr() +static void zzerr() { yyerror("syntax error"); } -static void -yyerror(s) +void yyerror(s) char *s; { yynerrs++; if (interactive && e.iop <= iostack) { multiline = 0; - while (eofc() == 0 && yylex(0) != '\n') - ; + while (eofc() == 0 && yylex(0) != '\n'); } err(s); fail(); } -static int -yylex(cf) +static int yylex(cf) int cf; { register int c, c1; @@ -2097,7 +1930,7 @@ int cf; peeksym = 0; if (c == '\n') startl = 1; - return(c); + return (c); } nlseen = 0; e.linep = line; @@ -2105,13 +1938,12 @@ int cf; startl = 0; yylval.i = 0; -loop: - while ((c = my_getc(0)) == ' ' || c == '\t') - ; + loop: + while ((c = getqc(0)) == ' ' || c == '\t'); switch (c) { default: if (any(c, "0123456789")) { - unget(c1 = my_getc(0)); + unget(c1 = getqc(0)); if (c1 == '<' || c1 == '>') { iounit = c - '0'; goto loop; @@ -2122,19 +1954,18 @@ int cf; break; case '#': - while ((c = my_getc(0)) != 0 && c != '\n') - ; + while ((c = getqc(0)) != 0 && c != '\n'); unget(c); goto loop; case 0: - return(c); + return (c); case '$': *e.linep++ = c; - if ((c = my_getc(0)) == '{') { + if ((c = getqc(0)) == '{') { if ((c = collect(c, '}')) != '\0') - return(c); + return (c); goto pack; } break; @@ -2143,7 +1974,7 @@ int cf; case '\'': case '"': if ((c = collect(c, c)) != '\0') - return(c); + return (c); goto pack; case '|': @@ -2151,126 +1982,121 @@ int cf; case ';': if ((c1 = dual(c)) != '\0') { startl = 1; - return(c1); + return (c1); } startl = 1; - return(c); + return (c); case '^': startl = 1; - return('|'); + return ('|'); case '>': case '<': diag(c); - return(c); + return (c); case '\n': nlseen++; gethere(); startl = 1; if (multiline || cf & CONTIN) { - if (interactive && e.iop <= iostack) { + if (interactive && e.iop <= iostack) #ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=cprompt->value; + current_prompt = cprompt->value; #else - prs(cprompt->value); + prs(cprompt->value); #endif - } if (cf & CONTIN) goto loop; } - return(c); + return (c); case '(': case ')': startl = 1; - return(c); + return (c); } unget(c); -pack: - while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) + 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, "\"'`$")) + if (any(c, "\"'`$")) goto loop; *e.linep++ = '\0'; - if (atstart && (c = rlookup(line))!=0) { + if (atstart && (c = rlookup(line)) != 0) { startl = 1; - return(c); + return (c); } yylval.cp = strsave(line, areanum); - return(WORD); + return (WORD); } -static int -collect(c, c1) -register int c, c1; +int collect(c, c1) +int c, c1; { char s[2]; *e.linep++ = c; - while ((c = my_getc(c1)) != c1) { + while ((c = getqc(c1)) != c1) { if (c == 0) { unget(c); s[0] = c1; s[1] = 0; - prs("no closing "); yyerror(s); - return(YYERRCODE); + prs("no closing "); + yyerror(s); + return (YYERRCODE); } - if (interactive && c == '\n' && e.iop <= iostack) { + if (interactive && c == '\n' && e.iop <= iostack) #ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=cprompt->value; + current_prompt = cprompt->value; #else - prs(cprompt->value); + prs(cprompt->value); #endif - } *e.linep++ = c; } *e.linep++ = c; - return(0); + return (0); } -static int -dual(c) -register int c; +int dual(c) +int c; { char s[3]; register char *cp = s; *cp++ = c; - *cp++ = my_getc(0); + *cp++ = getqc(0); *cp = 0; if ((c = rlookup(s)) == 0) unget(*--cp); - return(c); + return (c); } -static void -diag(ec) +static void diag(ec) register int ec; { register int c; - c = my_getc(0); + c = getqc(0); if (c == '>' || c == '<') { if (c != ec) zzerr(); - yylval.i = ec == '>'? IOWRITE|IOCAT: IOHERE; - c = my_getc(0); + yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE; + c = getqc(0); } else - yylval.i = ec == '>'? IOWRITE: IOREAD; + yylval.i = ec == '>' ? IOWRITE : IOREAD; if (c != '&' || yylval.i == IOHERE) unget(c); else yylval.i |= IODUP; } -static char * -tree(size) +static char *tree(size) unsigned size; { register char *t; @@ -2280,68 +2106,133 @@ unsigned size; fail(); /* NOTREACHED */ } - return(t); + return (t); } -/* VARARGS1 */ -/* ARGSUSED */ - /* -------- 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])) -static int -execute(t, pin, pout, act) +/* + * 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; - volatile int i, rv, a; + 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) ℘ -#endif - +#endif if (t == NULL) - return(0); + return (0); rv = 0; a = areanum++; wp = (wp2 = t->words) != NULL - ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY) - : NULL; + ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY) + : NULL; - switch(t->type) { + switch (t->type) { case TPAREN: case TCOM: - { - int child; - rv = forkexec(t, pin, pout, act, wp, &child); - if (child) { - exstat = rv; - leave(); - } + rv = forkexec(t, pin, pout, act, wp, &child); + if (child) { + exstat = rv; + leave(); } break; case TPIPE: - { - int pv[2]; - if ((rv = openpipe(pv)) < 0) + 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); - } + 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: @@ -2351,11 +2242,14 @@ int act; case TASYNC: { + /* save global vars altered by child */ int hinteractive = interactive; - i = vfork(); + i = parent(); if (i != 0) { + /* restore global vars */ interactive = hinteractive; + if (i != -1) { setval(lookup("!"), putn(i)); if (pin != NULL) @@ -2377,27 +2271,25 @@ int act; close(0); open("/dev/null", 0); } - exit(execute(t->left, pin, pout, FEXEC)); + _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)) + 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; + wp = dolv + 1; if ((i = dolc) < 0) i = 0; } else { i = -1; - while (*wp++ != NULL) - ; + while (*wp++ != NULL); } vp = lookup(t->str); while (setjmp(bc.brkpt)) @@ -2425,15 +2317,15 @@ int act; 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); + 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) + if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0) cp = ""; if ((t1 = findcase(t->left, cp)) != NULL) rv = execute(t1, pin, pout, 0); @@ -2453,7 +2345,7 @@ int act; break; } -broken: + broken: t->words = wp2; isbreak = 0; freehere(areanum); @@ -2467,14 +2359,17 @@ int act; trapset = 0; runtrap(i); } - return(rv); + return (rv); } -static int -forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *pforked) +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; - int (*shcom)() = NULL; + int i, rv, (*shcom) (); register int f; char *cp = NULL; struct ioword **iopp; @@ -2504,28 +2399,27 @@ forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *p owp = wp; resetsig = 0; *pforked = 0; - rv = -1; /* system-detected error */ + shcom = NULL; + rv = -1; /* system-detected error */ if (t->type == TCOM) { - while ((cp = *wp++) != NULL) - ; + while ((cp = *wp++) != NULL); cp = *wp; /* strip all initial assignments */ /* not correct wrt PATH=yyy command etc */ if (flag['x']) - echo (cp ? wp: owp); + echo(cp ? wp : owp); if (cp == NULL && t->ioact == NULL) { - while ((cp = *owp++) != NULL && assign(cp, COPYV)) - ; - return(setstatus(0)); - } - else if (cp != 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; @@ -2535,9 +2429,9 @@ forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *p hbrklist = brklist; hexecflg = execflg; - i = vfork(); + i = parent(); if (i != 0) { - /* who wrote this crappy non vfork safe shit? */ + /* restore vars altered by child (needed by vfork) */ pin = hpin; pout = hpout; *pforked = hforked; @@ -2549,12 +2443,11 @@ forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *p *pforked = 0; if (i == -1) - return(rv); + return (rv); if (pin != NULL) closepipe(pin); - return(pout==NULL? setstatus(waitfor(i,0)): 0); + return (pout == NULL ? setstatus(waitfor(i, 0)) : 0); } - if (interactive) { signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); @@ -2565,7 +2458,7 @@ forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *p (*pforked)++; brklist = 0; execflg = 0; - } + } if (owp != NULL) while ((cp = *owp++) != NULL && assign(cp, COPYV)) if (shcom == NULL) @@ -2573,7 +2466,7 @@ forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *p #ifdef COMPIPE if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) { err("piping to/from shell builtins not yet done"); - return(-1); + return (-1); } #endif if (pin != NULL) { @@ -2588,68 +2481,72 @@ forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *p if (shcom != NULL && shcom != doexec) { prs(cp); err(": cannot redirect shell command"); - return(-1); + return (-1); } while (*iopp) - if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) - return(rv); + if (iosetup(*iopp++, pin != NULL, pout != NULL)) + return (rv); } if (shcom) - return(setstatus((*shcom)(t))); + return (setstatus((*shcom) (t))); /* should use FIOCEXCL */ - for (i=FDBASE; itype == TPAREN) - exit(execute(t->left, NOPIPE, NOPIPE, FEXEC)); + _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); + _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 */ - exit(1); } /* * 0< 1> are ignored as required * within pipelines. */ -static int -iosetup(iop, pipein, pipeout) +int iosetup(iop, pipein, pipeout) register struct ioword *iop; int pipein, pipeout; { - register int u = -1; - char *cp=NULL, *msg; + int u; + char *msg; + char *cp = NULL; if (iop->io_unit == IODEFAULT) /* take default */ - iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1; + iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1; if (pipein && iop->io_unit == 0) - return(0); + return (0); if (pipeout && iop->io_unit == 1) - return(0); - msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create"; + 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 ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL) + return (1); } if (iop->io_flag & IODUP) { - if (cp[1] || (!isdigit(*cp) && *cp != '-')) { + if (cp[1] || (!digit(*cp) && *cp != '-')) { prs(cp); err(": illegal >& argument"); - return(1); + return (1); } if (*cp == '-') iop->io_flag = IOCLOSE; - iop->io_flag &= ~(IOREAD|IOWRITE); + iop->io_flag &= ~(IOREAD | IOWRITE); } switch (iop->io_flag) { case IOREAD: @@ -2657,14 +2554,14 @@ int pipein, pipeout; break; case IOHERE: - case IOHERE|IOXHERE: - u = herein(iop->io_name, iop->io_flag&IOXHERE); - cp = "here file"; + case IOHERE | IOXHERE: + u = herein(iop->io_name, iop->io_flag & IOXHERE); + cp = "here file "; break; - case IOWRITE|IOCAT: + case IOWRITE | IOCAT: if ((u = open(cp, 1)) >= 0) { - lseek(u, (long)0, 2); + lseek(u, (long) 0, 2); break; } case IOWRITE: @@ -2672,35 +2569,44 @@ int pipein, pipeout; break; case IODUP: - u = dup2(*cp-'0', iop->io_unit); + u = dup2(*cp - '0', iop->io_unit); break; case IOCLOSE: close(iop->io_unit); - return(0); + 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 "); - warn(msg); - return(1); + 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); + return (0); } -static void -echo(wp) +static void echo(wp) register char **wp; { - register int i; + int i; prs("+"); - for (i=0; wp[i]; i++) { + for (i = 0; wp[i]; i++) { if (i) prs(" "); prs(wp[i]); @@ -2708,8 +2614,7 @@ register char **wp; prs("\n"); } -static struct op ** -find1case(t, w) +static struct op **find1case(t, w) struct op *t; char *w; { @@ -2718,34 +2623,32 @@ char *w; register char **wp, *cp; if (t == NULL) - return((struct op **)NULL); + return ((struct op **) NULL); if (t->type == TLIST) { if ((tp = find1case(t->left, w)) != NULL) - return(tp); - t1 = t->right; /* TPAT */ + 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); + return (&t1->left); + return ((struct op **) NULL); } -static struct op * -findcase(t, w) +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); + return ((tp = find1case(t, w)) != NULL ? *tp : (struct op *) NULL); } /* * Enter a new loop level (marked for break/continue). */ -static void -brkset(bc) +static void brkset(bc) struct brkcon *bc; { bc->nextlev = brklist; @@ -2759,8 +2662,7 @@ struct brkcon *bc; * Ignore interrupt signals while waiting * unless `canintr' is true. */ -static int -waitfor(lastpid, canintr) +int waitfor(lastpid, canintr) register int lastpid; int canintr; { @@ -2790,7 +2692,9 @@ int canintr; prn(pid); prs(": "); } - prs("Signal "); prn(rv); prs(" "); + prs("Signal "); + prn(rv); + prs(" "); } if (WAITCORE(s)) prs(" - core dumped"); @@ -2807,20 +2711,20 @@ int canintr; if (canintr) intr = 0; } else { - if (exstat == 0) exstat = rv; + if (exstat == 0) + exstat = rv; onintr(0); } } - return(rv); + return (rv); } -static int -setstatus(s) +int setstatus(s) register int s; { exstat = s; setval(lookup("?"), putn(s)); - return(s); + return (s); } /* @@ -2828,8 +2732,7 @@ register int s; * If getenv("PATH") were kept up-to-date, * execvp might be used. */ -static char * -rexecve(c, v, envp) +char *rexecve(c, v, envp) char *c, **v, **envp; { register int i; @@ -2863,9 +2766,7 @@ char *c, **v, **envp; } if (tp != e.linep) *tp++ = '/'; - for (i = 0; (*tp++ = c[i++]) != '\0';) - ; - + for (i = 0; (*tp++ = c[i++]) != '\0';); execve(e.linep, v, envp); switch (errno) { case ENOEXEC: @@ -2874,30 +2775,29 @@ char *c, **v, **envp; *v = e.linep; execve("/bin/sh", v, envp); *v = tp; - return("no Shell"); + return ("no Shell"); case ENOMEM: - return("program too big"); + return ("program too big"); case E2BIG: - return("argument list too long"); + return ("argument list too long"); case EACCES: eacces++; break; } } - return(errno==ENOENT ? "not found" : "cannot execute"); + return (errno == ENOENT ? "not found" : "cannot execute"); } /* * Run the command produced by generator `f' * applied to stream `arg'. */ -static int -run(argp, f) +int run(argp, f) struct ioarg *argp; -int (*f)(); +int (*f) (); { struct op *otree; struct wdblock *swdlist; @@ -2910,7 +2810,6 @@ int (*f)(); /* Avoid longjmp clobbering */ (void) &rv; #endif - areanum++; swdlist = wdlist; siolist = iolist; @@ -2932,7 +2831,7 @@ int (*f)(); failpt = ofail; outtree = otree; freearea(areanum--); - return(rv); + return (rv); } /* -------- do.c -------- */ @@ -2941,53 +2840,10 @@ int (*f)(); * 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); + return (0); } static int @@ -2998,38 +2854,49 @@ register struct op *t; if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL) er = ": no home directory"; - else if(chdir(cp) < 0) + else if (chdir(cp) < 0) er = ": bad directory"; - else - return(0); - prs(cp != NULL? cp: "cd"); + 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); + return (1); } -static int -doshift(t) +int doshift(t) register struct op *t; { - register int n; + int n; - n = t->words[1]? getn(t->words[1]): 1; - if(dolc < n) { + n = t->words[1] ? getn(t->words[1]) : 1; + if (dolc < n) { err("nothing to shift"); - return(1); + return (1); } dolv[n] = dolv[0]; dolv += n; dolc -= n; setval(lookup("#"), putn(dolc)); - return(0); + return (0); } /* * execute login and newgrp directly */ -static int -dologin(t) +int dologin(t) struct op *t; { register char *cp; @@ -3038,13 +2905,14 @@ struct op *t; 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); + cp = rexecve(t->words[0], t->words, makenv(0)); + prs(t->words[0]); + prs(": "); + err(cp); + return (1); } -static int -doumask(t) +int doumask(t) register struct op *t; { register int i, n; @@ -3053,137 +2921,128 @@ register struct op *t; 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); + 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'); + for (n = 0; *cp >= '0' && *cp <= '9'; cp++) + n = n * 8 + (*cp - '0'); umask(n); } - return(0); + return (0); } -static int -doexec(t) +int doexec(t) register struct op *t; { - register int i; + int i; jmp_buf ex; xint *ofail; t->ioact = NULL; - for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++) - ; + for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++); if (i == 0) - return(1); + return (1); execflg = 1; ofail = failpt; if (setjmp(failpt = ex) == 0) execute(t, NOPIPE, NOPIPE, FEXEC); failpt = ofail; execflg = 0; - return(1); + return (1); } -static int -dodot(t) +int dodot(t) struct op *t; { - register int i; + int i; register char *sp, *tp; char *cp; if ((cp = t->words[1]) == NULL) - return(0); - sp = any('/', cp)? ":": path->value; + 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';) - ; + for (i = 0; (*tp++ = cp[i++]) != '\0';); if ((i = open(e.linep, 0)) >= 0) { exstat = 0; next(remap(i)); - return(exstat); + return (exstat); } } prs(cp); err(": not found"); - return(-1); + return (-1); } -static int -dowait(t) +int dowait(t) struct op *t; { - register int i; + int i; register char *cp; if ((cp = t->words[1]) != NULL) { i = getn(cp); if (i == 0) - return(0); + return (0); } else i = -1; setstatus(waitfor(i, 1)); - return(0); + return (0); } -static int -doread(t) +int doread(t) struct op *t; { register char *cp, **wp; - register int nb = 0; - register int nl = 0; + int nb = 0; + register int nl = 0; if (t->words[1] == NULL) { err("Usage: read name ..."); - return(1); + return (1); } - for (wp = t->words+1; *wp; wp++) { - for (cp = e.linep; !nl && cp < elinep-1; cp++) + 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))) + (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value))) break; *cp = 0; if (nb <= 0) break; setval(lookup(*wp), e.linep); } - return(nb <= 0); + return (nb <= 0); } -static int -doeval(t) +int doeval(t) register struct op *t; { - return(RUN(awordlist, t->words+1, wdchar)); + return (RUN(awordlist, t->words + 1, wdchar)); } -static int -dotrap(t) +int dotrap(t) register struct op *t; { - register int n, i; - register int resetsig; + register int n, i; + register int resetsig; if (t->words[1] == NULL) { - for (i=0; i<=_NSIG; i++) + for (i = 0; i <= _NSIG; i++) if (trap[i]) { prn(i); prs(": "); prs(trap[i]); prs("\n"); } - return(0); + return (0); } - resetsig = isdigit(*t->words[1]); + resetsig = digit(*t->words[1]); for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) { n = getsig(t->words[i]); freecell(trap[n]); @@ -3199,17 +3058,15 @@ register struct op *t; if (n == SIGINT) setsig(n, onintr); else - setsig(n, n == SIGQUIT ? SIG_IGN - : SIG_DFL); + setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL); else setsig(n, SIG_DFL); } } - return(0); + return (0); } -static int -getsig(s) +int getsig(s) char *s; { register int n; @@ -3218,11 +3075,12 @@ char *s; err("trap: bad signal number"); n = 0; } - return(n); + return (n); } -static void -setsig( register int n, void (*f)(int)) +void setsig(n, f) +int n; +void (*f) (int); { if (n == 0) return; @@ -3232,12 +3090,11 @@ setsig( register int n, void (*f)(int)) } } -static int -getn(as) +int getn(as) char *as; { register char *s; - register int n, m; + int n, m; s = as; m = 1; @@ -3245,38 +3102,35 @@ char *as; m = -1; s++; } - for (n = 0; isdigit(*s); s++) - n = (n*10) + (*s-'0'); + for (n = 0; digit(*s); s++) + n = (n * 10) + (*s - '0'); if (*s) { prs(as); err(": bad number"); } - return(n*m); + return (n * m); } -static int -dobreak(t) +int dobreak(t) struct op *t; { - return(brkcontin(t->words[1], 1)); + return (brkcontin(t->words[1], 1)); } -static int -docontinue(t) +int docontinue(t) struct op *t; { - return(brkcontin(t->words[1], 0)); + return (brkcontin(t->words[1], 0)); } -static int -brkcontin(cp, val) +static int brkcontin(cp, val) register char *cp; int val; { register struct brkcon *bc; - register int nl; + int nl; - nl = cp == NULL? 1: getn(cp); + nl = cp == NULL ? 1 : getn(cp); if (nl <= 0) nl = 999; do { @@ -3286,15 +3140,14 @@ int val; } while (--nl); if (nl) { err("bad break/continue level"); - return(1); + return (1); } isbreak = val; longjmp(bc->brkpt, 1); /* NOTREACHED */ } -static int -doexit(t) +int doexit(t) struct op *t; { register char *cp; @@ -3304,74 +3157,59 @@ struct op *t; setstatus(getn(cp)); leave(); /* NOTREACHED */ - return(0); } -static int -doexport(t) +int doexport(t) struct op *t; { - rdexp(t->words+1, export, EXPORT); - return(0); + rdexp(t->words + 1, export, EXPORT); + return (0); } -static int -doreadonly(t) +int doreadonly(t) struct op *t; { - rdexp(t->words+1, ronly, RONLY); - return(0); + rdexp(t->words + 1, ronly, RONLY); + return (0); } -static void -rdexp(wp, f, key) +static void rdexp(wp, f, key) register char **wp; -void (*f)(); +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'; - } + for (; *wp != NULL; wp++) if (checkname(*wp)) - (*f)(lookup(*wp)); + (*f) (lookup(*wp)); else badid(*wp); - } } else putvlist(key, 1); } -static void -badid(s) +static void badid(s) register char *s; { prs(s); err(": bad identifier"); } -static int -doset(t) +int doset(t) register struct op *t; { register struct var *vp; register char *cp; - register int n; + int n; if ((cp = t->words[1]) == NULL) { for (vp = vlist; vp; vp = vp->next) varput(vp->name, 1); - return(0); + return (0); } if (*cp == '-') { /* bad: t->words++; */ - for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++) - ; + for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++); if (*++cp == 0) flag['x'] = flag['v'] = 0; else @@ -3383,70 +3221,94 @@ register struct op *t; break; default: - if (*cp>='a' && *cp<='z') - flag[(int)*cp]++; + 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; + 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); + setarea((char *) (dolv - 1), 0); } - return(0); + return (0); } -static void -varput(s, out) +void varput(s, out) register char *s; int out; { - if (isalnum(*s) || *s == '_') { + if (letnum(*s)) { write(out, s, strlen(s)); write(out, "\n", 1); } } -/* - * Copyright (c) 1999 Herbert Xu - * This file contains code for the times builtin. - */ -static int dotimes () +#define SECS 60L +#define MINS 3600L + +int dotimes() { - struct tms buf; - long int clk_tck = sysconf(_SC_CLK_TCK); + struct tms tbuf; + + times(&tbuf); - 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; + 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} +}; -static int (*inbuilt(char *s))() +int (*inbuilt(s)) () +register char *s; { - const struct builtincmd *bp; - - for (bp = builtincmds; bp->name != NULL; bp++) - if (strcmp(bp->name, s) == 0) - return(bp->builtinfunc); + register struct builtin *bp; - return((int(*)())NULL); + for (bp = builtin; bp->command != NULL; bp++) + if (strcmp(bp->command, s) == 0) + return (bp->fn); + return ((int (*)()) NULL); } + /* -------- eval.c -------- */ /* @@ -3457,7 +3319,24 @@ static int (*inbuilt(char *s))() * glob */ -static char ** eval( char **ap, int f) +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; @@ -3469,6 +3348,7 @@ static char ** eval( char **ap, int f) (void) ℘ (void) ≈ #endif + wp = NULL; wb = NULL; wf = NULL; @@ -3481,16 +3361,16 @@ static char ** eval( char **ap, int f) expand(*wf, &wb, f & ~DOGLOB); } } - for (wb = addword((char *)0, wb); *ap; ap++) { + for (wb = addword((char *) 0, wb); *ap; ap++) { if (!flag['k'] || !isassign(*ap)) expand(*ap, &wb, f & ~DOKEY); } - wb = addword((char *)0, wb); + wb = addword((char *) 0, wb); wp = getwords(wb); quitenv(); } else gflg = 1; - return(gflg? (char **)NULL: wp); + return (gflg ? (char **) NULL : wp); } /* @@ -3498,40 +3378,45 @@ static char ** eval( char **ap, int f) * names in the dictionary. Keyword assignments * will already have been done. */ -static char ** -makenv() - +char **makenv(int all) { register struct wdblock *wb; register struct var *vp; wb = NULL; for (vp = vlist; vp; vp = vp->next) - if (vp->status & EXPORT) + if (all || vp->status & EXPORT) wb = addword(vp->name, wb); - wb = addword((char *)0, wb); - return(getwords(wb)); + wb = addword((char *) 0, wb); + return (getwords(wb)); } -static char * -evalstr(cp, f) -register char *cp; +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) + if (wb == NULL || wb->w_nword == 0 + || (cp = wb->w_words[0]) == NULL) cp = ""; - DELETE(wb); + freecell(wb); } else cp = NULL; - return(cp); + return (cp); } -static int -expand( char *cp, register struct wdblock **wbp, int f) +static int expand(cp, wbp, f) +char *cp; +register struct wdblock **wbp; +int f; { jmp_buf ev; @@ -3539,17 +3424,17 @@ expand( char *cp, register struct wdblock **wbp, int f) /* Avoid longjmp clobbering */ (void) &cp; #endif + gflg = 0; if (cp == NULL) - return(0); + return (0); if (!anys("$`'\"", cp) && - !anys(ifs->value, cp) && - ((f&DOGLOB)==0 || !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); + return (1); } if (newenv(setjmp(errpt = ev)) == 0) { PUSHIO(aword, cp, strchar); @@ -3557,7 +3442,7 @@ expand( char *cp, register struct wdblock **wbp, int f) while ((cp = blank(f)) && gflg == 0) { e.linep = cp; cp = strsave(cp, areanum); - if ((f&DOGLOB) == 0) { + if ((f & DOGLOB) == 0) { if (f & DOTRIM) unquote(cp); *wbp = addword(cp, *wbp); @@ -3567,17 +3452,16 @@ expand( char *cp, register struct wdblock **wbp, int f) quitenv(); } else gflg = 1; - return(gflg == 0); + return (gflg == 0); } /* * Blank interpretation and quoting */ -static char * -blank(f) +static char *blank(f) int f; { - register int c, c1; + int c, c1; register char *sp; int scanequals, foundequals; @@ -3585,13 +3469,13 @@ int f; scanequals = f & DOKEY; foundequals = 0; -loop: + loop: switch (c = subgetc('"', foundequals)) { case 0: if (sp == e.linep) - return(0); + return (0); *e.linep++ = 0; - return(sp); + return (sp); default: if (f & DOBLANK && any(c, ifs->value)) @@ -3613,14 +3497,14 @@ int f; c = 0; } unget(c); - if (!isalpha(c) && c != '_') + if (!letter(c)) scanequals = 0; for (;;) { c = subgetc('"', foundequals); if (c == 0 || - f & (DOBLANK && any(c, ifs->value)) || - (!INSUB() && any(c, "\"'"))) { - scanequals = 0; + (f & DOBLANK && any(c, ifs->value)) || + (!INSUB() && any(c, "\"'"))) { + scanequals = 0; unget(c); if (any(c, "\"'")) goto loop; @@ -3629,33 +3513,31 @@ int f; if (scanequals) { if (c == '=') { foundequals = 1; - scanequals = 0; - } - else if (!isalnum(c) && c != '_') + scanequals = 0; + } else if (!letnum(c)) scanequals = 0; } *e.linep++ = c; } *e.linep++ = 0; - return(sp); + return (sp); } /* * Get characters, substituting for ` and $ */ -static int -subgetc(ec, quoted) -register int ec; +int subgetc(ec, quoted) +register char ec; int quoted; { register char c; -again: - c = my_getc(ec); + again: + c = getqc(ec); if (!INSUB() && ec != '\'') { if (c == '`') { if (grave(quoted) == 0) - return(0); + return (0); e.iop->task = XGRAVE; goto again; } @@ -3664,28 +3546,27 @@ int quoted; goto again; } } - return(c); + return (c); } /* * Prepare to generate the string returned by ${} substitution. */ -static int -dollar(quoted) +static int dollar(quoted) int quoted; { int otask; struct io *oiop; char *dolp; - register char *s, c, *cp=NULL; + register char *s, c, *cp; 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 (letter(c)) { + while ((c = readc()) != 0 && letnum(c)) if (e.linep < elinep) *e.linep++ = c; unget(c); @@ -3695,7 +3576,7 @@ int quoted; oiop = e.iop; otask = e.iop->task; e.iop->task = XOTHER; - while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n') + while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n') if (e.linep < elinep) *e.linep++ = c; if (oiop == e.iop) @@ -3703,7 +3584,7 @@ int quoted; if (c != '}') { err("unclosed ${"); gflg++; - return(c); + return (c); } } if (e.linep >= elinep) { @@ -3712,40 +3593,45 @@ int quoted; e.linep -= 10; } *e.linep = 0; - if (*s) - for (cp = s+1; *cp; cp++) + 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 ${=} */ + 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 (isdigit(*s)) { + 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 = strsave(cp, areanum); + dolp = evalstr(strsave(cp, areanum), DOSUB); break; case '?': @@ -3753,69 +3639,84 @@ int quoted; prs("missing value for "); err(s); } else - err(cp); + err(evalstr(strsave(cp, areanum), DOSUB)); gflg++; break; } - } else if (c == '+') - dolp = strsave(cp, areanum); + } else if (c == '+') { + dolp = evalstr(strsave(cp, areanum), DOSUB); + } if (flag['u'] && dolp == null) { prs("unset variable: "); err(s); gflg++; } - e.linep = s; PUSHIO(aword, dolp, quoted ? qstrchar : strchar); - return(0); + return (0); } /* * Run the command in `...` and read its output. */ -static int -grave(quoted) +static int grave(quoted) int quoted; { - register int i; - char *cp; + int otask; + struct io *oiop; + register char *cp, *s; + register int i, c; int pf[2]; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &cp; +#ifndef USE_FORK + char *av[4]; + char **env; #endif - for (cp = e.iop->argp->aword; *cp != '`'; cp++) - if (*cp == 0) { - err("no closing `"); - return(0); - } + + 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); - if ((i = vfork()) == -1) { + return (0); +#ifndef USE_FORK + env = makenv(1); +#endif + if ((i = XFORK()) == -1) { closepipe(pf); err("try again"); - return(0); + return (0); } if (i != 0) { - e.iop->argp->aword = ++cp; + e.linep = s; close(pf[1]); - PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar); - return(1); + PUSHIO(afile, remap(pf[0]), quoted ? qgravechar : gravechar); + return (1); } - *cp = 0; + *e.linep = 0; /* allow trapped signals */ - for (i=0; i<=_NSIG; i++) + 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; - cp = strsave(e.iop->argp->aword, 0); areanum = 1; - freehere(areanum); - freearea(areanum); /* free old space */ + inhere = acthere = (struct here *) 0; + freearea(areanum); /* free old space */ e.oenv = NULL; e.iop = (e.iobase = iostack) - 1; unquote(cp); @@ -3823,10 +3724,21 @@ int quoted; 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 } -static char * -unquote(as) +char *unquote(as) register char *as; { register char *s; @@ -3834,7 +3746,7 @@ register char *as; if ((s = as) != NULL) while (*s) *s++ &= ~QUOTE; - return(as); + return (as); } /* -------- glob.c -------- */ @@ -3843,23 +3755,22 @@ register char *as; * glob */ -#define scopy(x) strsave((x), areanum) -#define BLKSIZ 512 -#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent)) +#define scopy(x) strsave((x), areanum) +#define BLKSIZ 512 + -static struct wdblock *cl, *nl; -static char spcl[] = "[?*"; +static struct wdblock *cl, *nl; +static char spcl[] = "[?*"; -static struct wdblock * -glob(cp, wb) +struct wdblock *glob(cp, wb) char *cp; struct wdblock *wb; { - register int i; + int i; register char *pp; if (cp == 0) - return(wb); + return (wb); i = 0; for (pp = cp; *pp; pp++) if (any(*pp, spcl)) @@ -3867,9 +3778,10 @@ struct wdblock *wb; 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; iw_nword; i++) { /* for each argument */ + 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); @@ -3878,26 +3790,25 @@ struct wdblock *wb; if (*pp == '\0') nl = addword(scopy(cl->w_words[i]), nl); } - for(i=0; iw_nword; i++) - DELETE(cl->w_words[i]); - DELETE(cl); + for (i = 0; i < cl->w_nword; i++) + freecell(cl->w_words[i]); + freecell(cl); } - for(i=0; iw_nword; i++) + for (i = 0; i < cl->w_nword; i++) unquote(cl->w_words[i]); - glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp); + glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp); if (cl->w_nword) { - for (i=0; iw_nword; i++) + for (i = 0; i < cl->w_nword; i++) wb = addword(cl->w_words[i], wb); - DELETE(cl); - return(wb); + freecell(cl); + return (wb); } } wb = addword(unquote(cp), wb); - return(wb); + return (wb); } -static void -globname(we, pp) +void globname(we, pp) char *we; register char *pp; { @@ -3906,53 +3817,48 @@ register char *pp; int k; DIR *dirp; struct dirent *de; - char dname[NAME_MAX+1]; + 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;) + for (dp = cp = space((int) (pp - np) + 3); np < pp;) *cp++ = *np++; *cp++ = '.'; *cp = '\0'; - for (gp = cp = space(strlen(pp)+1); *np && *np != '/';) + for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';) *cp++ = *np++; *cp = '\0'; dirp = opendir(dp); if (dirp == 0) { - DELETE(dp); - DELETE(gp); + freecell(dp); + freecell(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; - */ + while ((de = readdir(dirp)) != NULL) { strncpy(dname, de->d_name, NAME_MAX); - if (dname[0] == '.') - if (*gp != '.') + 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; - for(k=0; kw_words; - for (i=0; iw_nword; i++) + for (i = 0; i < wb->w_nword; i++) if (anys(spcl, *wd++)) - return(1); - return(0); + return (1); + return (0); } -static int -xstrcmp(p1, p2) +static int xstrcmp(p1, p2) char *p1, *p2; { - return(strcmp(*(char **)p1, *(char **)p2)); + return (strcmp(*(char **) p1, *(char **) p2)); } /* -------- word.c -------- */ -static struct wdblock * -newword(nw) +#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 = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *)); wb->w_bsize = nw; wb->w_nword = 0; - return(wb); + return (wb); } -static struct wdblock * -addword(wd, wb) +struct wdblock *addword(wd, wb) char *wd; register struct wdblock *wb; { register struct wdblock *wb2; - register int nw; + 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 *)); + memcpy(wb2->w_words, wb->w_words, nw * sizeof(char *)); wb2->w_nword = nw; - DELETE(wb); + freecell(wb); wb = wb2; } wb->w_words[wb->w_nword++] = wd; - return(wb); + return (wb); } -static -char ** -getwords(wb) + +char **getwords(wb) register struct wdblock *wb; { register char **wd; - register int nb; + int nb; if (wb == NULL) - return((char **)NULL); + return ((char **) NULL); if (wb->w_nword == 0) { - DELETE(wb); - return((char **)NULL); + freecell(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); + memcpy(wd, wb->w_words, nb); + freecell(wb); /* perhaps should done by caller */ + return (wd); } -int (*func)(char *, char *); -int globv; +static int (*func) (char *, char *); +static int globv; -static void -glob0(a0, a1, a2, a3) +void glob0(a0, a1, a2, a3) char *a0; unsigned a1; int a2; @@ -4070,8 +3970,7 @@ int (*a3) (char *, char *); glob1(a0, a0 + a1 * a2); } -static void -glob1(base, lim) +void glob1(base, lim) char *base, *lim; { register char *i, *j; @@ -4083,16 +3982,16 @@ char *base, *lim; v2 = globv; -top: - if ((n=(int)(lim-base)) <= v2) + top: + if ((n = (int) (lim - base)) <= v2) return; - n = v2 * (n / (2*v2)); - hptr = lptr = base+n; + n = v2 * (n / (2 * v2)); + hptr = lptr = base + n; i = base; - j = lim-v2; - for(;;) { + j = lim - v2; + for (;;) { if (i < lptr) { - if ((c = (*func)(i, lptr)) == 0) { + if ((c = (*func) (i, lptr)) == 0) { glob2(i, lptr -= v2); continue; } @@ -4102,9 +4001,9 @@ char *base, *lim; } } -begin: + begin: if (j > hptr) { - if ((c = (*func)(hptr, j)) == 0) { + if ((c = (*func) (hptr, j)) == 0) { glob2(hptr += v2, j); goto begin; } @@ -4125,12 +4024,12 @@ char *base, *lim; if (i == lptr) { - if (lptr-base >= lim-hptr) { - glob1(hptr+v2, lim); + if (lptr - base >= lim - hptr) { + glob1(hptr + v2, lim); lim = lptr; } else { glob1(base, lptr); - base = hptr+v2; + base = hptr + v2; } goto top; } @@ -4141,8 +4040,7 @@ char *base, *lim; } } -static void -glob2(i, j) +void glob2(i, j) char *i, *j; { register char *index1, *index2, c; @@ -4155,11 +4053,10 @@ char *i, *j; c = *index1; *index1++ = *index2; *index2++ = c; - } while(--m); + } while (--m); } -static void -glob3(i, j, k) +void glob3(i, j, k) char *i, *j, *k; { register char *index1, *index2, *index3; @@ -4175,7 +4072,7 @@ char *i, *j, *k; *index1++ = *index3; *index3++ = *index2; *index2++ = c; - } while(--m); + } while (--m); } /* -------- io.c -------- */ @@ -4184,103 +4081,103 @@ char *i, *j, *k; * shell IO */ -static int my_getc( int ec) +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) - ; + if (e.linep > elinep) { + while ((c = readc()) != '\n' && c); err("input line too long"); gflg++; - return(c); + return (c); } c = readc(); - if (ec != '\'' && e.iop->task != XGRAVE) { - if(c == '\\') { + if (ec != '\'' && e.iop->task != XGRAVE) { + if (c == '\\') { c = readc(); if (c == '\n' && ec != '\"') - return(my_getc(ec)); + return (getqc(ec)); c |= QUOTE; } } - return(c); + return (c); } -static void -unget(c) +void unget(c) int c; { if (e.iop >= e.iobase) e.iop->peekc = c; } -static int -eofc() - +int eofc() { - return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0); + return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0); } -static int -readc() +int readc() { - register int c; + 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) { + 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; + current_prompt = prompt->value; #else - prs(prompt->value); + prs(prompt->value); #endif } - } } if (e.iop >= iostack) - return(0); + return (0); leave(); /* NOTREACHED */ - return(0); } -static void -ioecho(c) +void ioecho(c) char c; { if (flag['v']) write(2, &c, sizeof c); } -static void -pushio(argp, fn) +void pushio(argp, fn) struct ioarg *argp; -int (*fn)(); +int (*fn) (); { if (++e.iop >= &iostack[NPUSH]) { e.iop--; @@ -4291,21 +4188,21 @@ int (*fn)(); e.iop->iofn = fn; if (argp->afid != AFID_NOBUF) - e.iop->argp = argp; + 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->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->prev = ~'\n'; e.iop->peekc = 0; e.iop->xchar = 0; e.iop->nlcount = 0; @@ -4317,15 +4214,14 @@ int (*fn)(); e.iop->task = XOTHER; } -static struct io * -setbase(ip) +struct io *setbase(ip) struct io *ip; { register struct io *xp; xp = e.iobase; e.iobase = ip; - return(xp); + return (xp); } /* @@ -4335,109 +4231,102 @@ struct io *ip; /* * Produce the characters of a string, then a newline, then EOF. */ -static int -nlchar(ap) +int nlchar(ap) register struct ioarg *ap; { register int c; if (ap->aword == NULL) - return(0); + return (0); if ((c = *ap->aword++) == 0) { ap->aword = NULL; - return('\n'); + return ('\n'); } - return(c); + return (c); } /* * Given a list of words, produce the characters * in them, with a space after each word. */ -static int -wdchar(ap) +int wdchar(ap) register struct ioarg *ap; { register char c; register char **wl; if ((wl = ap->awordlist) == NULL) - return(0); + return (0); if (*wl != NULL) { if ((c = *(*wl)++) != 0) - return(c & 0177); + return (c & 0177); ap->awordlist++; - return(' '); + return (' '); } ap->awordlist = NULL; - return('\n'); + return ('\n'); } /* * Return the characters of a list of words, * producing a space between them. */ -static int -dolchar(ap) +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); + PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar); + return (-1); } - return(0); + return (0); } -static int -xxchar(ap) +static int xxchar(ap) register struct ioarg *ap; { register int c; if (ap->aword == NULL) - return(0); + return (0); if ((c = *ap->aword++) == '\0') { ap->aword = NULL; - return(' '); + return (' '); } - return(c); + return (c); } /* * Produce the characters from a single word (string). */ -static int -strchar(ap) +int strchar(ap) register struct ioarg *ap; { register int c; if (ap->aword == NULL || (c = *ap->aword++) == 0) - return(0); - return(c); + return (0); + return (c); } /* * Produce quoted characters from a single word (string). */ -static int -qstrchar(ap) +int qstrchar(ap) register struct ioarg *ap; { register int c; if (ap->aword == NULL || (c = *ap->aword++) == 0) - return(0); - return(c|QUOTE); + return (0); + return (c | QUOTE); } /* * Return the characters from a file. */ -static int -filechar(ap) +int filechar(ap) register struct ioarg *ap; { register int i; @@ -4445,47 +4334,44 @@ register struct ioarg *ap; 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; + 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 + 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 (i == sizeof(c) ? c & 0177 : (closef(ap->afile), 0)); } } /* * Return the characters from a here temp file. */ -static int -herechar(ap) +int herechar(ap) register struct ioarg *ap; { char c; @@ -4503,20 +4389,18 @@ register struct ioarg *ap; * Return the characters produced by a process (`...`). * Quote them if required, and remove any trailing newline characters. */ -static int -gravechar(ap, iop) +int gravechar(ap, iop) struct ioarg *ap; struct io *iop; { register int c; - if ((c = qgravechar(ap, iop)&~QUOTE) == '\n') + if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n') c = ' '; - return(c); + return (c); } -static int -qgravechar(ap, iop) +int qgravechar(ap, iop) register struct ioarg *ap; struct io *iop; { @@ -4525,7 +4409,7 @@ struct io *iop; if (iop->xchar) { if (iop->nlcount) { iop->nlcount--; - return('\n'|QUOTE); + return ('\n' | QUOTE); } c = iop->xchar; iop->xchar = 0; @@ -4535,18 +4419,17 @@ struct io *iop; iop->nlcount++; iop->xchar = c; if (c == 0) - return(c); + return (c); iop->nlcount--; c = '\n'; } - return(c!=0? c|QUOTE: 0); + return (c != 0 ? c | QUOTE : 0); } /* * Return a single command (usually the first line) from a file. */ -static int -linechar(ap) +int linechar(ap) register struct ioarg *ap; { register int c; @@ -4554,83 +4437,81 @@ register struct ioarg *ap; if ((c = filechar(ap)) == '\n') { if (!multiline) { closef(ap->afile); - ap->afile = -1; /* illegal value */ + ap->afile = -1; /* illegal value */ } } - return(c); + return (c); } -static void -prs(s) +void prs(s) register char *s; { - if (*s) - write(2, s, strlen(s)); + fputs(s, stderr); +} + +void put1c(c) +char c; +{ + putc(c, stderr); } -static void -prn(u) +void prn(u) unsigned u; { prs(itoa(u, 0)); } -static void -closef(i) +void closef(i) register int i; { if (i > 2) close(i); } -static void -closeall() +void closeall() { - register int u; + int u; - for (u=NUFILE; u= 0 && fd < e.iofd); - for (i=0; ih_next) + for (lh = inhere; lh != NULL; lh = lh->h_next) if (lh->h_next == 0) { lh->h_next = h; break; } - iop->io_flag |= IOHERE|IOXHERE; + iop->io_flag |= IOHERE | IOXHERE; for (s = h->h_tag; *s; s++) if (*s & QUOTE) { - iop->io_flag &= ~ IOXHERE; - *s &= ~ QUOTE; + iop->io_flag &= ~IOXHERE; + *s &= ~QUOTE; } h->h_dosub = iop->io_flag & IOXHERE; } -static void -gethere() +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: '\''); + 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; + hp->h_next = acthere; + acthere = inhere; + inhere = NULL; } } -static void -readhere(name, s, ec) +static void readhere(name, s, ec) char **name; register char *s; int ec; { int tf; - char tname[30] = ".msh_XXXXXX"; - register int c; + char tname[30]; + int c; jmp_buf ev; - char myline [LINELIM+1]; - char *thenext; + char read_line[LINELIM + 1]; + char *next_read_line; - tf = mkstemp(tname); +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &tf; +#endif + + tempname(tname); + *name = strsave(tname, areanum); + tf = creat(tname, 0600); 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) { + if (interactive && e.iop <= iostack) #ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=cprompt->value; + current_prompt = cprompt->value; #else - prs(cprompt->value); + prs(cprompt->value); #endif - } - thenext = myline; - while ((c = my_getc(ec)) != '\n' && c) { - if (ec == '\'') - c &= ~ QUOTE; - if (thenext >= &myline[LINELIM]) { + next_read_line = read_line; + while ((c = readc()) != '\n' && c) { + if (next_read_line >= &read_line[LINELIM]) { c = 0; break; } - *thenext++ = c; + *next_read_line++ = c; } - *thenext = 0; - if (strcmp(s, myline) == 0 || c == 0) + *next_read_line = 0; + if (strcmp(s, read_line) == 0 || c == 0) break; - *thenext++ = '\n'; - write (tf, myline, (int)(thenext-myline)); + *next_read_line++ = '\n'; + write(tf, read_line, (int) (next_read_line - read_line)); } if (c == 0) { - prs("here document `"); prs(s); err("' unclosed"); + prs("here document `"); + prs(s); + err("' unclosed"); } quitenv(); } @@ -4753,37 +4636,39 @@ int ec; * open here temp file. * if unquoted here, expand here temp file into second temp file. */ -static int -herein(hname, xdoll) +int herein(hname, xdoll) char *hname; int xdoll; { - register int hf; - int tf; + int hf, tf; #if __GNUC__ /* Avoid longjmp clobbering */ (void) &tf; #endif + if (hname == 0) - return(-1); + return (-1); hf = open(hname, 0); if (hf < 0) return (-1); if (xdoll) { char c; - char tname[30] = ".msh_XXXXXX"; + char tname[30]; jmp_buf ev; - - tf = mkstemp(tname); - if (tf < 0) + + 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) { - c &= ~ QUOTE; - write(tf, &c, sizeof c); + char c1 = c & ~QUOTE; + + if (c & QUOTE && !any(c1, "`$\\")) + write(tf, "\\", 1); + write(tf, &c1, 1); } quitenv(); } else @@ -4796,21 +4681,19 @@ int xdoll; return (hf); } -static void -scraphere() +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); + unlink(h->h_iop->io_name); } inhere = NULL; } /* unlink here temp files before a freearea(area) */ -static void -freehere(area) +void freehere(area) int area; { register struct here *h, *hl; @@ -4828,29 +4711,38 @@ int area; 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 @@ -4865,4 +4757,3 @@ int area; * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ - diff --git a/busybox/miscutils/mt.c b/mt.c similarity index 100% rename from busybox/miscutils/mt.c rename to mt.c diff --git a/busybox/coreutils/mv.c b/mv.c similarity index 100% rename from busybox/coreutils/mv.c rename to mv.c diff --git a/busybox/networking/nc.c b/nc.c similarity index 81% rename from busybox/networking/nc.c rename to nc.c index 5335872e5..87e67e4cb 100644 --- a/busybox/networking/nc.c +++ b/nc.c @@ -40,10 +40,15 @@ #include #include "busybox.h" +#define GAPING_SECURITY_HOLE + int nc_main(int argc, char **argv) { - int do_listen = 0, lport = 0, tmpfd, opt, sfd; + 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; @@ -58,17 +63,32 @@ int nc_main(int argc, char **argv) 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) { @@ -100,6 +120,20 @@ int nc_main(int argc, char **argv) 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); diff --git a/busybox/nfsmount.c b/nfsmount.c similarity index 100% rename from busybox/nfsmount.c rename to nfsmount.c diff --git a/busybox/nfsmount.h b/nfsmount.h similarity index 100% rename from busybox/nfsmount.h rename to nfsmount.h diff --git a/busybox/nslookup.c b/nslookup.c similarity index 87% rename from busybox/nslookup.c rename to nslookup.c index 9b7cb645c..2139afd7e 100644 --- a/busybox/nslookup.c +++ b/nslookup.c @@ -2,8 +2,8 @@ /* * Mini nslookup implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu + * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -90,10 +90,16 @@ static int addr_list_fprint(char **h_addr_list) } /* print the results as nslookup would */ -static struct hostent *hostent_fprint(struct hostent *host) +static struct hostent *hostent_fprint(struct hostent *host, int is_server) { + char *format; + if (is_server) { + format = "Server: "; + } else { + format = "Name: "; + } if (host) { - printf("Name: %s\n", host->h_name); + printf("%s%s\n", format, host->h_name); addr_list_fprint(host->h_addr_list); } else { printf("*** Unknown host\n"); @@ -128,24 +134,15 @@ static struct hostent *gethostbyaddr_wrapper(const char *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)); + hostent_fprint(gethostbyaddr_wrapper(ip), 1); printf("\n"); } -#endif /* naive function to check whether char *s is an ip address */ static int is_ip_address(const char *s) @@ -176,8 +173,8 @@ int nslookup_main(int argc, char **argv) } else { host = gethostbyname(argv[1]); } - hostent_fprint(host); + hostent_fprint(host, 0); return EXIT_SUCCESS; } -/* $Id: nslookup.c,v 1.24 2001/07/06 17:51:29 andersen Exp $ */ +/* $Id: nslookup.c,v 1.28 2002/04/27 04:03:59 andersen Exp $ */ diff --git a/busybox/procps/pidof.c b/pidof.c similarity index 89% rename from busybox/procps/pidof.c rename to pidof.c index 50dffd387..c75571a01 100644 --- a/busybox/procps/pidof.c +++ b/pidof.c @@ -2,8 +2,8 @@ /* * pidof implementation for busybox * - * Copyright (C) 2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999-2002 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ extern int pidof_main(int argc, char **argv) { - int opt; + int opt, n = 0; /* do normal option parsing */ @@ -58,7 +58,7 @@ extern int pidof_main(int argc, char **argv) /* Looks like everything is set to go. */ while(optind < argc) { - pid_t* pidList; + long* pidList; pidList = find_pid_by_name( argv[optind]); if (!pidList || *pidList<=0) { @@ -66,7 +66,7 @@ extern int pidof_main(int argc, char **argv) } for(; pidList && *pidList!=0; pidList++) { - printf("%ld ", (long)*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 diff --git a/busybox/networking/ping.c b/ping.c similarity index 99% rename from busybox/networking/ping.c rename to ping.c index 5ca5dd9e0..74ff614df 100644 --- a/busybox/networking/ping.c +++ b/ping.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * $Id: ping.c,v 1.46 2001/07/17 01:12:36 andersen Exp $ + * $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 @@ -216,7 +216,7 @@ static void ping(const char *host) /* listen for replies */ while (1) { struct sockaddr_in from; - size_t fromlen = sizeof(from); + socklen_t fromlen = sizeof(from); if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, (struct sockaddr *) &from, &fromlen)) < 0) { diff --git a/busybox/pivot_root.c b/pivot_root.c similarity index 100% rename from busybox/pivot_root.c rename to pivot_root.c diff --git a/busybox/init/poweroff.c b/poweroff.c similarity index 92% rename from busybox/init/poweroff.c rename to poweroff.c index db20a4572..443b70fd1 100644 --- a/busybox/init/poweroff.c +++ b/poweroff.c @@ -2,8 +2,8 @@ /* * Mini poweroff implementation for busybox * - * * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ 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"); + long *pid = find_pid_by_name("init"); if (!pid || *pid<=0) { pid = find_pid_by_name("linuxrc"); if (!pid || *pid<=0) diff --git a/busybox/coreutils/printf.c b/printf.c similarity index 100% rename from busybox/coreutils/printf.c rename to printf.c diff --git a/busybox/pristine_setup.sh b/pristine_setup.sh similarity index 87% rename from busybox/pristine_setup.sh rename to pristine_setup.sh index 9e638f96e..62f3f3075 100755 --- a/busybox/pristine_setup.sh +++ b/pristine_setup.sh @@ -34,11 +34,6 @@ 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" diff --git a/busybox/procps/ps.c b/ps.c similarity index 65% rename from busybox/procps/ps.c rename to ps.c index 9e96a5402..d16d55b18 100644 --- a/busybox/procps/ps.c +++ b/ps.c @@ -2,8 +2,8 @@ /* * Mini ps implementation(s) for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * * This contains _two_ implementations of ps for Linux. One uses the @@ -38,6 +38,7 @@ #include #include #include +#include #include "busybox.h" static const int TERMINAL_WIDTH = 79; /* not 80 in case terminal has linefold bug */ @@ -51,14 +52,13 @@ static const int TERMINAL_WIDTH = 79; /* not 80 in case terminal has linefo */ 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) */ + 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; @@ -77,6 +77,24 @@ static int file2str(char *filename, char *ret, int cap) } +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; @@ -89,6 +107,7 @@ static void parse_proc_status(char *S, proc_t * P) 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); @@ -102,9 +121,101 @@ static void parse_proc_status(char *S, proc_t * P) 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; @@ -133,7 +244,8 @@ extern int ps_main(int argc, char **argv) terminal_width = win.ws_col - 1; #endif - printf(" PID Uid Stat Command\n"); + 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; @@ -142,6 +254,11 @@ extern int ps_main(int argc, char **argv) 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') @@ -152,7 +269,8 @@ extern int ps_main(int argc, char **argv) if (file == NULL) continue; i = 0; - len = printf("%5d %-8s %c ", p.pid, uidName, p.state); + 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') diff --git a/busybox/pwd.c b/pwd.c similarity index 99% rename from busybox/pwd.c rename to pwd.c index f6a00bf1e..9c5d70cef 100644 --- a/busybox/pwd.c +++ b/pwd.c @@ -2,7 +2,6 @@ /* * Mini pwd implementation for busybox * - * * Copyright (C) 1995, 1996 by Bruce Perens . * * This program is free software; you can redistribute it and/or modify diff --git a/pwd_grp/.indent.pro b/pwd_grp/.indent.pro new file mode 100644 index 000000000..492ecf1c7 --- /dev/null +++ b/pwd_grp/.indent.pro @@ -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 index 000000000..ffdfb7535 --- /dev/null +++ b/pwd_grp/__getgrent.c @@ -0,0 +1,162 @@ +/* + * __getgrent.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#include +#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 index 000000000..f60bfec7c --- /dev/null +++ b/pwd_grp/__getpwent.c @@ -0,0 +1,113 @@ +/* + * __getpwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#include +#include +#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 */ + +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 index 000000000..eb029a31a --- /dev/null +++ b/pwd_grp/config.h @@ -0,0 +1,65 @@ +/* + * config.h - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 index 000000000..cefe6e7a1 --- /dev/null +++ b/pwd_grp/fgetgrent.c @@ -0,0 +1,33 @@ +/* + * fgetgrent.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#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 index 000000000..294d334a0 --- /dev/null +++ b/pwd_grp/fgetpwent.c @@ -0,0 +1,33 @@ +/* + * fgetpwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#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 index 000000000..620a853cb --- /dev/null +++ b/pwd_grp/getgrgid.c @@ -0,0 +1,42 @@ +/* + * getgrgid.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#include +#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 index 000000000..55825b1a8 --- /dev/null +++ b/pwd_grp/getgrnam.c @@ -0,0 +1,48 @@ +/* + * getgrnam.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#include +#include +#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 index 000000000..dc33da235 --- /dev/null +++ b/pwd_grp/getpw.c @@ -0,0 +1,45 @@ +/* + * getpw.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#include +#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 index 000000000..cdd165535 --- /dev/null +++ b/pwd_grp/getpwnam.c @@ -0,0 +1,49 @@ +/* + * getpwnam.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#include +#include +#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 index 000000000..7182119a5 --- /dev/null +++ b/pwd_grp/getpwuid.c @@ -0,0 +1,42 @@ +/* + * getpwuid.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#include +#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 index 000000000..7e162366c --- /dev/null +++ b/pwd_grp/grent.c @@ -0,0 +1,52 @@ +/* + * grent.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#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/busybox/include/grp.h b/pwd_grp/grp.h similarity index 100% rename from busybox/include/grp.h rename to pwd_grp/grp.h diff --git a/pwd_grp/initgroups.c b/pwd_grp/initgroups.c new file mode 100644 index 000000000..d45baddae --- /dev/null +++ b/pwd_grp/initgroups.c @@ -0,0 +1,74 @@ +/* + * initgroups.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#include +#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 index 000000000..a54fde685 --- /dev/null +++ b/pwd_grp/putpwent.c @@ -0,0 +1,37 @@ +/* + * putpwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#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/busybox/include/pwd.h b/pwd_grp/pwd.h similarity index 100% rename from busybox/include/pwd.h rename to pwd_grp/pwd.h diff --git a/pwd_grp/pwent.c b/pwd_grp/pwent.c new file mode 100644 index 000000000..e72e41d1e --- /dev/null +++ b/pwd_grp/pwent.c @@ -0,0 +1,56 @@ +/* + * pwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * 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 +#include +#include +#include "pwd.h" +#include + +/* + * 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 index 000000000..e371cb892 --- /dev/null +++ b/pwd_grp/setgroups.c @@ -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 + * + * 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 +#include +#include +#include +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ +#include +#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/busybox/rdate.c b/rdate.c similarity index 100% rename from busybox/rdate.c rename to rdate.c diff --git a/busybox/miscutils/readlink.c b/readlink.c similarity index 91% rename from busybox/miscutils/readlink.c rename to readlink.c index c46ebd108..fc5b7c2e3 100644 --- a/busybox/miscutils/readlink.c +++ b/readlink.c @@ -2,9 +2,7 @@ /* * Mini readlink implementation for busybox * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Matt Kraai + * Copyright (C) 1999,2000,2001 by 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 diff --git a/reboot.c b/reboot.c new file mode 100644 index 000000000..456865eb6 --- /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 . + * Copyright (C) 1999-2002 by Erik Andersen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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 +#include +#include +#include + +#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) + #include + #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/busybox/procps/renice.c b/renice.c similarity index 100% rename from busybox/procps/renice.c rename to renice.c diff --git a/busybox/reset.c b/reset.c similarity index 85% rename from busybox/reset.c rename to reset.c index 755c4c335..76244ca13 100644 --- a/busybox/reset.c +++ b/reset.c @@ -3,8 +3,8 @@ * Mini reset implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * and Kent Robotti * * This program is free software; you can redistribute it and/or modify @@ -29,7 +29,7 @@ extern int reset_main(int argc, char **argv) { - printf("\033c"); + printf("\033[?25h\033c\033[J"); return EXIT_SUCCESS; } diff --git a/busybox/coreutils/rm.c b/rm.c similarity index 100% rename from busybox/coreutils/rm.c rename to rm.c diff --git a/busybox/coreutils/rmdir.c b/rmdir.c similarity index 93% rename from busybox/coreutils/rmdir.c rename to rmdir.c index cac27cac9..4508ad48d 100644 --- a/busybox/coreutils/rmdir.c +++ b/rmdir.c @@ -3,8 +3,8 @@ * Mini rmdir implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/rmmod.c b/rmmod.c similarity index 92% rename from busybox/rmmod.c rename to rmmod.c index 7596d0232..affe975fa 100644 --- a/busybox/rmmod.c +++ b/rmmod.c @@ -2,8 +2,8 @@ /* * Mini rmmod implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/route.c b/route.c similarity index 97% rename from busybox/route.c rename to route.c index 9d210af64..d18d4ae29 100644 --- a/busybox/route.c +++ b/route.c @@ -360,7 +360,7 @@ INET_setroute(int action, int options, char **args) #define RTF_REJECT 0x0200 /* Reject route */ #endif -static void displayroutes(void) +static void displayroutes(int numeric) { char buff[256]; int nl = 0 ; @@ -410,9 +410,9 @@ static void displayroutes(void) dest.s_addr = d; gw.s_addr = g; mask.s_addr = m; - strcpy(sdest, (dest.s_addr==0 ? "default" : + strcpy(sdest, (numeric == 0 && dest.s_addr==0 ? "default" : inet_ntoa(dest))); - strcpy(sgw, (gw.s_addr==0 ? "*" : + strcpy(sgw, (numeric == 0 && gw.s_addr==0 ? "*" : inet_ntoa(gw))); printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n", sdest, sgw, @@ -427,12 +427,19 @@ static void displayroutes(void) 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(); + displayroutes(numeric); return EXIT_SUCCESS; } else { /* check verb */ diff --git a/busybox/archival/rpm2cpio.c b/rpm2cpio.c similarity index 100% rename from busybox/archival/rpm2cpio.c rename to rpm2cpio.c diff --git a/busybox/examples/depmod.pl b/scripts/depmod.pl similarity index 96% rename from busybox/examples/depmod.pl rename to scripts/depmod.pl index e65f07b68..bd7767f19 100755 --- a/busybox/examples/depmod.pl +++ b/scripts/depmod.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl -w # vi: set ts=4: # Copyright (c) 2001 David Schleef -# Copyright (c) 2001 Erik Andersen +# Copyright (c) 2001 Erik Andersen # Copyright (c) 2001 Stuart Hughes # This program is free software; you can redistribute it and/or modify it # under the same terms as Perl itself. @@ -212,7 +212,7 @@ =head1 OPTIONS =head1 COPYRIGHT Copyright (c) 2001 David Schleef -Copyright (c) 2001 Erik Andersen +Copyright (c) 2001 Erik Andersen Copyright (c) 2001 Stuart Hughes This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -223,5 +223,5 @@ =head1 AUTHOR =cut -# $Id: depmod.pl,v 1.1 2001/07/30 19:32:03 andersen Exp $ +# $Id: depmod.pl,v 1.2 2001/11/19 23:57:54 andersen Exp $ diff --git a/busybox/scripts/inittab b/scripts/inittab similarity index 91% rename from busybox/scripts/inittab rename to scripts/inittab index 8e7e945b3..5716045b8 100644 --- a/busybox/scripts/inittab +++ b/scripts/inittab @@ -1,7 +1,7 @@ # /etc/inittab init(8) configuration for BusyBox # -# Copyright (C) 1999 by Lineo, inc. Written by Erik Andersen -# , +# Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen +# Copyright (C) 1999,2000,2001 by Erik Andersen # # # Note, BusyBox init doesn't support runlevels. The runlevels field is @@ -24,7 +24,7 @@ # : The runlevels field is completely ignored. # # : Valid actions include: sysinit, respawn, askfirst, wait, once, -# ctrlaltdel, and shutdown. +# 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 @@ -43,6 +43,8 @@ # ::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 @@ -79,6 +81,9 @@ tty5::respawn:/sbin/getty 38400 tty6 # 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 diff --git a/busybox/examples/mk2knr.pl b/scripts/mk2knr.pl similarity index 100% rename from busybox/examples/mk2knr.pl rename to scripts/mk2knr.pl diff --git a/busybox/examples/undeb b/scripts/undeb similarity index 100% rename from busybox/examples/undeb rename to scripts/undeb diff --git a/busybox/examples/unrpm b/scripts/unrpm similarity index 100% rename from busybox/examples/unrpm rename to scripts/unrpm diff --git a/sed.c b/sed.c new file mode 100644 index 000000000..df6ccb228 --- /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 + * Copyright (C) 2002 Matt Kraai + * Copyright (C) 2003 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 + * + */ + +/* 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 +#include /* for getopt() */ +#include +#include /* for strdup() */ +#include +#include /* for isspace() */ +#include +#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(istring); + + /* 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;istring); + + /* 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/busybox/setkeycodes.c b/setkeycodes.c similarity index 98% rename from busybox/setkeycodes.c rename to setkeycodes.c index c3c7e09aa..85612c8b1 100644 --- a/busybox/setkeycodes.c +++ b/setkeycodes.c @@ -46,7 +46,7 @@ setkeycodes_main(int argc, char** argv) show_usage(); } - fd = get_console_fd("/dev/console"); + fd = get_console_fd(); while (argc > 2) { a.keycode = atoi(argv[2]); diff --git a/busybox/coreutils/sleep.c b/sleep.c similarity index 99% rename from busybox/coreutils/sleep.c rename to sleep.c index 3bcab88ee..7bc98d8e8 100644 --- a/busybox/coreutils/sleep.c +++ b/sleep.c @@ -2,7 +2,6 @@ /* * Mini sleep implementation for busybox * - * * Copyright (C) 1995, 1996 by Bruce Perens . * * This program is free software; you can redistribute it and/or modify diff --git a/busybox/coreutils/sort.c b/sort.c similarity index 100% rename from busybox/coreutils/sort.c rename to sort.c diff --git a/busybox/coreutils/stty.c b/stty.c similarity index 97% rename from busybox/coreutils/stty.c rename to stty.c index 2e00a496d..a67a17c0f 100644 --- a/busybox/coreutils/stty.c +++ b/stty.c @@ -572,14 +572,34 @@ extern int main(int argc, char **argv) speed_was_set = 0; require_set_attr = 0; - k = optind; - while (k < argc) { + 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) @@ -661,7 +681,6 @@ extern int main(int argc, char **argv) } else error_msg_and_die("invalid argument `%s'", argv[k]); } - k++; } if (require_set_attr) { diff --git a/busybox/swaponoff.c b/swaponoff.c similarity index 77% rename from busybox/swaponoff.c rename to swaponoff.c index ce0e2c6cc..a57dfe472 100644 --- a/busybox/swaponoff.c +++ b/swaponoff.c @@ -2,9 +2,8 @@ /* * Mini swapon/swapoff implementation for busybox * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,13 +39,13 @@ extern int swapoff (__const char *__path); #include "busybox.h" -static int whichApp; +static int whichApp; /* default SWAPON_APP */ -static const int SWAPON_APP = 1; -static const int SWAPOFF_APP = 2; +static const int SWAPON_APP = 0; +static const int SWAPOFF_APP = 1; -static void swap_enable_disable(char *device) +static int swap_enable_disable(const char *device) { int status; @@ -55,32 +54,35 @@ static void swap_enable_disable(char *device) else status = swapoff(device); - if (status != 0) - perror_msg_and_die(applet_name); + if (status != 0) { + perror_msg("%s", device); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } -static void do_em_all() +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) { - swap_enable_disable(m->mnt_fsname); + if(swap_enable_disable(m->mnt_fsname) == EXIT_FAILURE) + err++; } } endmntent(f); - exit(EXIT_SUCCESS); + return err; } extern int swap_on_off_main(int argc, char **argv) { - if (strcmp(applet_name, "swapon") == 0) { - whichApp = SWAPON_APP; - } else { + if (applet_name[5] == 'f') { /* "swapoff" */ whichApp = SWAPOFF_APP; } @@ -101,14 +103,13 @@ extern int swap_on_off_main(int argc, char **argv) if (stat("/etc/fstab", &statBuf) < 0) error_msg_and_die("/etc/fstab file missing"); } - do_em_all(); + return do_em_all(); break; default: goto usage_and_exit; } } - swap_enable_disable(*argv); - return EXIT_SUCCESS; + return swap_enable_disable(*argv); usage_and_exit: show_usage(); diff --git a/busybox/coreutils/sync.c b/sync.c similarity index 100% rename from busybox/coreutils/sync.c rename to sync.c diff --git a/busybox/sysklogd/syslogd.c b/syslogd.c similarity index 78% rename from busybox/sysklogd/syslogd.c rename to syslogd.c index 25bc68f20..784337b0b 100644 --- a/busybox/sysklogd/syslogd.c +++ b/syslogd.c @@ -2,8 +2,8 @@ /* * Mini syslogd implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * Copyright (C) 2000 by Karl M. Hegbloom * @@ -55,7 +55,7 @@ #define __LOG_FILE "/var/log/messages" /* Path to the unix socket */ -static char lfile[BUFSIZ]; +static char lfile[MAXPATHLEN]; static char *logFilePath = __LOG_FILE; @@ -63,7 +63,7 @@ static char *logFilePath = __LOG_FILE; static int MarkInterval = 20 * 60; /* localhost's name */ -static char LocalHostName[32]; +static char LocalHostName[64]; #ifdef BB_FEATURE_REMOTE_LOG #include @@ -78,8 +78,17 @@ 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 #include @@ -90,19 +99,19 @@ 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 + 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 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; /* @@ -138,11 +147,11 @@ void ipcsyslog_cleanup(void){ void ipcsyslog_init(void){ if (buf == NULL){ if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) - perror_msg_and_die("shmget"); + perror_msg_and_die("shmget"); if ((buf = shmat(shmid, NULL, 0)) == NULL) - perror_msg_and_die("shmat"); + perror_msg_and_die("shmat"); buf->size=data_size; @@ -150,11 +159,11 @@ void ipcsyslog_init(void){ // 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 (errno == EEXIST){ if ((s_semid = semget(KEY_ID, 2, 0)) == -1) perror_msg_and_die("semget"); }else - perror_msg_and_die("semget"); + perror_msg_and_die("semget"); } }else{ printf("Buffer already allocated just grab the semaphore?"); @@ -179,16 +188,16 @@ void circ_message(const char *msg){ * 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. + * 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. + * 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 @@ -202,19 +211,19 @@ void circ_message(const char *msg){ * to worry about overflows here! */ int k= buf->tail + l - buf->head; /* we need to know how many bytes - we are overwriting to make + 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 + 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; + 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! */ @@ -226,22 +235,22 @@ void circ_message(const char *msg){ /* 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 */ + 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'; - + 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]); @@ -251,11 +260,12 @@ void circ_message(const char *msg){ 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 +#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))); @@ -273,7 +283,7 @@ static void message (char *fmt, ...) if ((circular_logging == TRUE) && (buf != NULL)){ char b[1024]; va_start (arguments, fmt); - vsprintf (b, fmt, arguments); + vsnprintf (b, sizeof(b)-1, fmt, arguments); va_end (arguments); circ_message(b); @@ -349,14 +359,15 @@ static const int IOV_COUNT = 2; memset(&res, 0, sizeof(res)); snprintf(res, sizeof(res), "<%d>", pri); v->iov_base = res ; - v->iov_len = strlen(res); + v->iov_len = strlen(res); v++; v->iov_base = msg; - v->iov_len = strlen(msg); - + v->iov_len = strlen(msg); +writev_retry: if ( -1 == writev(remotefd,iov, IOV_COUNT)){ - error_msg_and_die("syslogd: cannot write to remote file handle on" + if (errno == EINTR) goto writev_retry; + error_msg_and_die("cannot write to remote file handle on" "%s:%d",RemoteHost,RemotePort); } } @@ -389,28 +400,23 @@ static void domark(int sig) /* 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) +static int serveConnection (char* tmpbuf, int n_read) { - 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 ]; + int num_lt = 0; + char line[ MAXLINE + 1 ]; unsigned char c; char *q = line; - tmpbuf[ n_read - 1 ] = '\0'; - - while (p && (c = *p) && q < &line[ sizeof (line) - 1 ]) { - if (c == '<') { + 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'); @@ -433,13 +439,13 @@ static int serveConnection (int conn) /* Now log it */ logMessage (pri, line); } - RELEASE_BB_BUFFER (tmpbuf); return n_read; } #ifdef BB_FEATURE_REMOTE_LOG -static void init_RemoteLog (void){ +static void init_RemoteLog (void) +{ struct sockaddr_in remoteaddr; struct hostent *hostinfo; @@ -450,7 +456,7 @@ static void init_RemoteLog (void){ remotefd = socket(AF_INET, SOCK_DGRAM, 0); if (remotefd < 0) { - error_msg_and_die("syslogd: cannot create socket"); + error_msg_and_die("cannot create socket"); } hostinfo = xgethostbyname(RemoteHost); @@ -459,12 +465,12 @@ static void init_RemoteLog (void){ 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 + /* + 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); + error_msg_and_die("cannot connect to remote host %s:%d", RemoteHost, RemotePort); } } @@ -476,7 +482,6 @@ static void doSyslogd (void) struct sockaddr_un sunx; socklen_t addrLength; - int sock_fd; fd_set fds; @@ -499,18 +504,16 @@ static void doSyslogd (void) 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) + 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)) || (listen (sock_fd, 5))) + 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); - FD_ZERO (&fds); - FD_SET (sock_fd, &fds); #ifdef BB_FEATURE_IPC_SYSLOG if (circular_logging == TRUE ){ @@ -518,58 +521,48 @@ static void doSyslogd (void) } #endif - #ifdef BB_FEATURE_REMOTE_LOG - if (doRemoteLog == TRUE){ - init_RemoteLog(); - } - #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)); + FD_ZERO (&fds); + FD_SET (sock_fd, &fds); - if ((n_ready = select (FD_SETSIZE, &readfds, NULL, NULL, NULL)) < 0) { - if (errno == EINTR) continue; /* alarm may have happened. */ + if (select (sock_fd+1, &fds, NULL, NULL, NULL) < 0) { + if (errno == EINTR) { + /* alarm may have happened. */ + continue; + } 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 */ + 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; @@ -579,15 +572,17 @@ extern int syslogd_main(int argc, char **argv) case 'm': MarkInterval = atoi(optarg) * 60; break; +#if ! defined(__uClinux__) case 'n': doFork = FALSE; break; +#endif case 'O': - logFilePath = strdup(optarg); + logFilePath = xstrdup(optarg); break; #ifdef BB_FEATURE_REMOTE_LOG case 'R': - RemoteHost = strdup(optarg); + RemoteHost = xstrdup(optarg); if ( (p = strchr(RemoteHost, ':'))){ RemotePort = atoi(p+1); *p = '\0'; @@ -623,10 +618,12 @@ extern int syslogd_main(int argc, char **argv) umask(0); +#if ! defined(__uClinux__) if (doFork == TRUE) { if (daemon(0, 1) < 0) perror_msg_and_die("daemon"); } +#endif doSyslogd(); return EXIT_SUCCESS; diff --git a/busybox/coreutils/tail.c b/tail.c similarity index 97% rename from busybox/coreutils/tail.c rename to tail.c index 90cc2a6ef..5e572c582 100644 --- a/busybox/coreutils/tail.c +++ b/tail.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,7 @@ static void tailbuf_append(char *buf, int len) taillen += len; } -static void tailbuf_trunc() +static void tailbuf_trunc(void) { char *s; s = memchr(tailbuf, '\n', taillen); @@ -68,6 +69,11 @@ int tail_main(int argc, char **argv) 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': diff --git a/busybox/archival/tar.c b/tar.c similarity index 99% rename from busybox/archival/tar.c rename to tar.c index 389d7f02e..60d9cf9f4 100644 --- a/busybox/archival/tar.c +++ b/tar.c @@ -6,8 +6,8 @@ * 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 , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999-2002 by Erik Andersen * * Based in part in the tar implementation in sash * Copyright (c) 1999 by David I. Bell @@ -168,7 +168,9 @@ extern int tar_main(int argc, char **argv) int tostdoutFlag = FALSE; int status = FALSE; int opt; +#if defined BB_FEATURE_TAR_GZIP pid_t pid; +#endif if (argc <= 1) show_usage(); @@ -531,6 +533,7 @@ readTarHeader(struct TarHeader *rawHeader, struct TarInfo *header) return( FALSE); } +#if defined BB_FEATURE_TAR_EXCLUDE static int exclude_file(char **excluded_files, const char *file) { int i; @@ -557,6 +560,7 @@ static int exclude_file(char **excluded_files, const char *file) return 0; } +#endif static int extract_file(char **extract_files, const char *file) { diff --git a/busybox/coreutils/tee.c b/tee.c similarity index 93% rename from busybox/coreutils/tee.c rename to tee.c index 439cf7dc5..0533dbd65 100644 --- a/busybox/coreutils/tee.c +++ b/tee.c @@ -2,8 +2,7 @@ /* * Mini tee implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Matt Kraai + * Copyright (C) 1999,2000,2001 by 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 diff --git a/busybox/telnet.c b/telnet.c similarity index 86% rename from busybox/telnet.c rename to telnet.c index ce82a0ee8..cacb91fcb 100644 --- a/busybox/telnet.c +++ b/telnet.c @@ -25,8 +25,7 @@ * HISTORY * Revision 3.1 1994/04/17 11:31:54 too * initial revision - * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen - * + * Modified 2000/06/13 for inclusion in BusyBox by Erik Andersen * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan * * @@ -46,6 +45,10 @@ #include #include "busybox.h" +#ifdef BB_FEATURE_AUTOWIDTH +# include +#endif + #if 0 static const int DOTRACE = 1; #endif @@ -141,6 +144,10 @@ static int one = 1; static char *ttype; #endif +#ifdef BB_FEATURE_AUTOWIDTH +static int win_width, win_height; +#endif + static void doexit(int ev) { cookmode(); @@ -203,22 +210,38 @@ static void handlenetoutput(int len) * 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; + * 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; i > 0; i--, p++) + for (i = len, j = 0; i > 0; i--, p++) { if (*p == 0x1d) { conescape(); return; } + outbuf[j++] = *p; if (*p == 0xff) - *p = 0x7f; + outbuf[j++] = 0xff; + else if (*p == 0x0d) + outbuf[j++] = 0x00; } - write(G.netfd, G.buf, len); + if (j > 0 ) + write(G.netfd, outbuf, j); } @@ -347,6 +370,26 @@ static void putiac_subopt(byte c, char *str) } #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) */ /* ******************************* */ @@ -405,7 +448,7 @@ static inline void to_notsup(char c) else if (G.telwish == DO) putiac2(WONT, c); } -static inline void to_echo() +static inline void to_echo(void) { /* if server requests ECHO, don't agree */ if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; } @@ -432,7 +475,7 @@ static inline void to_echo() WriteCS(1, "\r\n"); /* sudden modec */ } -static inline void to_sga() +static inline void to_sga(void) { /* daemon always sends will/wont, client do/dont */ @@ -454,7 +497,7 @@ static inline void to_sga() } #ifdef BB_FEATURE_TELNET_TTYPE -static inline void to_ttype() +static inline void to_ttype(void) { /* Tell server we will (or won't) do TTYPE */ @@ -467,23 +510,38 @@ static inline void to_ttype() } #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(c); break; - case TELOPT_SGA: to_sga(c); break; + case TELOPT_ECHO: to_echo(); break; + case TELOPT_SGA: to_sga(); break; #ifdef BB_FEATURE_TELNET_TTYPE - case TELOPT_TTYPE: to_ttype(c); break; + 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; + default: to_notsup(c); + break; } } /* ******************************* */ -/* subnegotiation -- ignore all (except TTYPE) */ +/* subnegotiation -- ignore all (except TTYPE,NAWS) */ static int subneg(byte c) { @@ -537,6 +595,14 @@ extern int telnet_main(int argc, char** argv) 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 @@ -662,28 +728,6 @@ static void setup_sockaddr_in(struct sockaddr_in * addr, int port) 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; diff --git a/busybox/coreutils/test.c b/test.c similarity index 100% rename from busybox/coreutils/test.c rename to test.c diff --git a/busybox/tests/.cvsignore b/tests/.cvsignore similarity index 100% rename from busybox/tests/.cvsignore rename to tests/.cvsignore diff --git a/busybox/tests/Makefile b/tests/Makefile similarity index 100% rename from busybox/tests/Makefile rename to tests/Makefile diff --git a/busybox/tests/cp_tests.mk b/tests/cp_tests.mk similarity index 100% rename from busybox/tests/cp_tests.mk rename to tests/cp_tests.mk diff --git a/busybox/tests/ln_tests.mk b/tests/ln_tests.mk similarity index 100% rename from busybox/tests/ln_tests.mk rename to tests/ln_tests.mk diff --git a/busybox/tests/multibuild.pl b/tests/multibuild.pl similarity index 100% rename from busybox/tests/multibuild.pl rename to tests/multibuild.pl diff --git a/busybox/tests/multifeat.pl b/tests/multifeat.pl similarity index 100% rename from busybox/tests/multifeat.pl rename to tests/multifeat.pl diff --git a/busybox/tests/mv_tests.mk b/tests/mv_tests.mk similarity index 100% rename from busybox/tests/mv_tests.mk rename to tests/mv_tests.mk diff --git a/busybox/tests/sh.testcases b/tests/sh.testcases similarity index 93% rename from busybox/tests/sh.testcases rename to tests/sh.testcases index e2a75873e..aa834d4a2 100644 --- a/busybox/tests/sh.testcases +++ b/tests/sh.testcases @@ -69,12 +69,12 @@ rm -f fish TMP=fish && >$TMP ls fish -# ash, lash, and hush do not create fish; bash and ksh do. +# ash, lash, and hush do not create wish; bash and ksh do. # Thanks to Tapani Tarvainen for this stress test. unset TMP -rm -f fish -TMP=fish >$TMP -ls fish +rm -f wish +TMP=wish >$TMP +ls wish # The following example shows that hush's parser is # not _really_ Bourne compatible @@ -86,4 +86,4 @@ PATH=$PATH:. echo $a # assuming the shell wasn't too buggy, clean up the mess -rm -f a=b fish foo +rm -f a=b wish fish foo diff --git a/busybox/tests/syslog_test.c b/tests/syslog_test.c similarity index 100% rename from busybox/tests/syslog_test.c rename to tests/syslog_test.c diff --git a/busybox/tests/testcases b/tests/testcases similarity index 100% rename from busybox/tests/testcases rename to tests/testcases diff --git a/busybox/tests/tester.sh b/tests/tester.sh similarity index 100% rename from busybox/tests/tester.sh rename to tests/tester.sh diff --git a/busybox/tests/tst-syslogd.c b/tests/tst-syslogd.c similarity index 100% rename from busybox/tests/tst-syslogd.c rename to tests/tst-syslogd.c diff --git a/busybox/tftp.c b/tftp.c similarity index 58% rename from busybox/tftp.c rename to tftp.c index 999b5d706..08535a95c 100644 --- a/busybox/tftp.c +++ b/tftp.c @@ -3,7 +3,8 @@ /* */ /* A simple tftp client for busybox. */ /* Tries to follow RFC1350. */ -/* Only "octet" mode and 512-byte data blocks are supported. */ +/* Only "octet" mode supported. */ +/* Optional blocksize negotiation (RFC2347 + RFC2348) */ /* */ /* Copyright (C) 2001 Magnus Damm */ /* */ @@ -45,8 +46,23 @@ #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", @@ -61,8 +77,71 @@ static const char *tftp_error_msg[] = { 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 *serverfile, int localfd, const int port, int tftp_bufsize) + 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; @@ -81,7 +160,14 @@ static inline int tftp(const int cmd, const struct hostent *host, int finished = 0; int timeout = bb_tftp_num_retries; int block_nr = 1; - RESERVE_BB_BUFFER(buf, tftp_bufsize + 4); // Why 4 ? + +#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; @@ -103,50 +189,79 @@ static inline int tftp(const int cmd, const struct hostent *host, /* build opcode */ if (cmd_get) { - opcode = 1; // read request = 1 + opcode = TFTP_RRQ; } if (cmd_put) { - opcode = 2; // write request = 2 + opcode = TFTP_WRQ; } while (1) { - - /* build packet of type "opcode" */ - - cp = buf; + /* first create the opcode part */ + *((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 + if ((cmd_get && (opcode == TFTP_RRQ)) || + (cmd_put && (opcode == TFTP_WRQ))) { + int too_long = 0; - /* what is this trying to do ? */ - while (cp != &buf[tftp_bufsize - 1]) { - if ((*cp = *serverfile++) == '\0') - break; - cp++; + /* 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; } - /* and this ? */ - if ((*cp != '\0') || (&buf[tftp_bufsize - 1] - cp) < 7) { - error_msg("too long server-filename"); + + if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) { + error_msg("too long remote-filename"); break; } - memcpy(cp + 1, "octet", 6); - cp += 7; + /* 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 == 4)) || // acknowledgement = 4 - (cmd_put && (opcode == 3))) { // data packet == 3 + if ((cmd_get && (opcode == TFTP_ACK)) || + (cmd_put && (opcode == TFTP_DATA))) { *((unsigned short *) cp) = htons(block_nr); @@ -154,7 +269,7 @@ static inline int tftp(const int cmd, const struct hostent *host, block_nr++; - if (cmd_put && (opcode == 3)) { // data packet == 3 + if (cmd_put && (opcode == TFTP_DATA)) { len = read(localfd, cp, tftp_bufsize - 4); if (len < 0) { @@ -200,7 +315,7 @@ static inline int tftp(const int cmd, const struct hostent *host, memset(&from, 0, sizeof(from)); fromlen = sizeof(from); - tv.tv_sec = 5; // BB_TFPT_TIMEOUT = 5 + tv.tv_sec = TFTP_TIMEOUT; tv.tv_usec = 0; FD_ZERO(&rfds); @@ -261,9 +376,76 @@ static inline int tftp(const int cmd, const struct hostent *host, printf("received %d bytes: %04x %04x\n", len, opcode, tmp); #endif - if (cmd_get && (opcode == 3)) { // data packet == 3 + 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) { @@ -275,43 +457,30 @@ static inline int tftp(const int cmd, const struct hostent *host, finished++; } - opcode = 4; // acknowledgement = 4 + opcode = TFTP_ACK; continue; } } - if (cmd_put && (opcode == 4)) { // acknowledgement = 4 + if (cmd_put && (opcode == TFTP_ACK)) { if (tmp == (block_nr - 1)) { if (finished) { break; } - opcode = 3; // data packet == 3 + opcode = TFTP_DATA; 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; - } } +#ifdef BB_FEATURE_CLEAN_UP close(socketfd); + free(buf); +#endif + return finished ? EXIT_SUCCESS : EXIT_FAILURE; } @@ -326,13 +495,38 @@ int tftp_main(int argc, char **argv) int flags = 0; int opt; int result; - int blocksize = 512; + int blocksize = TFTP_BLOCKSIZE_DEFAULT; + + /* figure out what to pass to getopt */ + +#ifdef BB_FEATURE_TFTP_BLOCKSIZE +#define BS "b:" +#else +#define BS +#endif - while ((opt = getopt(argc, argv, "b:gpl:r:")) != -1) { +#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; @@ -357,8 +551,16 @@ int tftp_main(int argc, char **argv) if ((cmd == 0) || (optind == argc)) { show_usage(); } - - fd = open(localfile, flags, 0644); + 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"); } @@ -370,14 +572,18 @@ int tftp_main(int argc, char **argv) } #ifdef BB_FEATURE_TFTP_DEBUG - printf("using server \"%s\", serverfile \"%s\"," + 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); - close(fd); +#ifdef BB_FEATURE_CLEAN_UP + if (!(fd == fileno(stdout) || fd == fileno(stdin))) { + close(fd); + } +#endif return(result); -} \ No newline at end of file +} diff --git a/time.c b/time.c new file mode 100644 index 000000000..fa352a899 --- /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 . + Heavily modified by David MacKenzie . + Heavily modified for busybox by Erik Andersen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For pid_t. */ +#include +#include /* For getpagesize, maybe. */ + +#define TV_MSEC tv_usec / 1000 +#include +#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 index 000000000..e992d23fa --- /dev/null +++ b/top.c @@ -0,0 +1,739 @@ +/* + * A tiny 'top' utility. + * + * This is written specifically for the linux /proc//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 + * + * Rewroted by Vladimir Oleynik (C) 2002 + */ + +/* 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 +#include +#include +#include +#include +#include +#include +#include +/* get page info */ +#include +#include "busybox.h" + +#define FEATURE_CPU_USAGE_PERCENTAGE /* + 2k */ + +#ifdef FEATURE_CPU_USAGE_PERCENTAGE +#include +#include +#include +#include /* 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 "" */ + 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 +#include +#include + + +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/busybox/coreutils/touch.c b/touch.c similarity index 92% rename from busybox/coreutils/touch.c rename to touch.c index 1718da71e..036b5c3ee 100644 --- a/busybox/coreutils/touch.c +++ b/touch.c @@ -3,8 +3,8 @@ * Mini touch implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/coreutils/tr.c b/tr.c similarity index 100% rename from busybox/coreutils/tr.c rename to tr.c diff --git a/busybox/traceroute.c b/traceroute.c similarity index 98% rename from busybox/traceroute.c rename to traceroute.c index a3abd0a00..c0c216528 100644 --- a/busybox/traceroute.c +++ b/traceroute.c @@ -235,18 +235,14 @@ inetname(struct sockaddr_in *from) if (first && !nflag) { first = 0; - if (gethostname(domain, MAXHOSTNAMELEN) == 0 && - (cp = strchr(domain, '.'))) - (void) strcpy(domain, cp + 1); - else - domain[0] = 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)) + if ((cp = strchr(hp->h_name, '.')) && !strcmp(cp + 1, domain)) *cp = 0; cp = (char *)hp->h_name; } @@ -324,8 +320,7 @@ wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer) * Convert an ICMP "type" field to a printable string. */ static inline const char * -pr_type(t) - u_char t; +pr_type(u_char t) { static const char * const ttab[] = { "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", @@ -549,12 +544,12 @@ traceroute_main(argc, argv) if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, sizeof(datalen)) < 0) perror_msg_and_die("SO_SNDBUF"); -#endif 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 +#endif /* IP_HDRINCL */ #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG if (options & SO_DEBUG) (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, @@ -574,7 +569,7 @@ traceroute_main(argc, argv) #ifndef IP_HDRINCL if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) perror_msg_and_die("bind"); -#endif IP_HDRINCL +#endif /* IP_HDRINCL */ } fprintf(stderr, "traceroute to %s (%s)", hostname, diff --git a/busybox/true_false.c b/true_false.c similarity index 88% rename from busybox/true_false.c rename to true_false.c index 76183431c..b00e29820 100644 --- a/busybox/true_false.c +++ b/true_false.c @@ -3,8 +3,8 @@ * Mini true/false implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/coreutils/tty.c b/tty.c similarity index 100% rename from busybox/coreutils/tty.c rename to tty.c diff --git a/busybox/umount.c b/umount.c similarity index 98% rename from busybox/umount.c rename to umount.c index 74638d21c..2a06a3b45 100644 --- a/busybox/umount.c +++ b/umount.c @@ -3,8 +3,8 @@ * Mini umount implementation for busybox * * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/coreutils/uname.c b/uname.c similarity index 100% rename from busybox/coreutils/uname.c rename to uname.c diff --git a/busybox/uniq.c b/uniq.c similarity index 92% rename from busybox/uniq.c rename to uniq.c index 53e3c64f2..e46fc4488 100644 --- a/busybox/uniq.c +++ b/uniq.c @@ -2,9 +2,9 @@ /* * Mini uniq implementation for busybox * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu + * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * Written by John Beppu * Rewritten by Matt Kraai * * This program is free software; you can redistribute it and/or modify diff --git a/busybox/miscutils/update.c b/update.c similarity index 100% rename from busybox/miscutils/update.c rename to update.c diff --git a/busybox/uptime.c b/uptime.c similarity index 94% rename from busybox/uptime.c rename to uptime.c index 6758d959e..5460ac8a5 100644 --- a/busybox/uptime.c +++ b/uptime.c @@ -2,8 +2,8 @@ /* * Mini uptime implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/busybox/applets/usage.c b/usage.c similarity index 100% rename from busybox/applets/usage.c rename to usage.c diff --git a/busybox/applets/usage.h b/usage.h similarity index 91% rename from busybox/applets/usage.h rename to usage.h index 4d38c43bb..2cf591905 100644 --- a/busybox/applets/usage.h +++ b/usage.h @@ -191,7 +191,7 @@ #define dd_trivial_usage \ "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \ - "\t [seek=N] [conv=notrunc|sync]" + "\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" \ @@ -201,6 +201,7 @@ "\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" \ @@ -272,7 +273,7 @@ "\t-d\toutput will be in DOS format" #define dpkg_trivial_usage \ - "-i package_file\n" + "-i package_file\n" \ "[-CPru] package_name" #define dpkg_full_usage \ "\t-i\tInstall the package\n" \ @@ -297,7 +298,7 @@ "$ 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]..." + "[-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" \ @@ -307,6 +308,7 @@ 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 \ @@ -448,6 +450,11 @@ #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]" @@ -463,7 +470,9 @@ ) 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") + "\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" @@ -686,6 +695,7 @@ " ::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" \ @@ -717,7 +727,7 @@ " : \n" \ "\n" \ " Valid actions include: sysinit, respawn, askfirst, wait, \n" \ -" once, ctrlaltdel, and shutdown.\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" \ @@ -730,7 +740,10 @@ " 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" \ +" 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" \ @@ -751,7 +764,7 @@ "\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" \ +" run in the order they appear in /etc/inittab.\n" \ "\n" \ " : \n" \ "\n" \ @@ -774,8 +787,8 @@ " \n" \ " # /sbin/getty invocations for selected ttys\n" \ " #\n" \ -" tty4::respawn:/sbin/getty 38400 tty5\n" \ -" tty5::respawn:/sbin/getty 38400 tty6\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" \ @@ -786,6 +799,9 @@ " # 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" \ @@ -903,6 +919,14 @@ #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 @@ -1085,11 +1109,82 @@ "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" #define modprobe_trivial_usage \ - "[FILE ...]" + "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 for hight level module loading and unloading." + "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 cdrom\n" + "$ modprobe pcnet_cs\n" \ + "$ modprobe -r pcnet_cs\n" #define more_trivial_usage \ "[FILE ...]" @@ -1164,9 +1259,13 @@ "$ mv /tmp/foo /bin/bar\n" #define nc_trivial_usage \ - "[IP] [port]" + "[OPTIONS] [IP] [port]" #define nc_full_usage \ - "Netcat opens a pipe to IP:port" + "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" \ @@ -1411,6 +1510,15 @@ "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 \ @@ -1569,6 +1677,14 @@ #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 \ @@ -1584,6 +1700,15 @@ ) \ "\t-r FILE\tTransfer remote FILE.\n" +#define top_trivial_usage \ + "[-d ]" +#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 \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 \ diff --git a/busybox/coreutils/usleep.c b/usleep.c similarity index 100% rename from busybox/coreutils/usleep.c rename to usleep.c diff --git a/busybox/coreutils/uudecode.c b/uudecode.c similarity index 99% rename from busybox/coreutils/uudecode.c rename to uudecode.c index a4059ddfe..21dc4b23a 100644 --- a/busybox/coreutils/uudecode.c +++ b/uudecode.c @@ -204,7 +204,7 @@ static int decode (const char *inname, register char *p; int mode; char buf[2 * BUFSIZ]; - char *outname; + char *outname = NULL; int do_base64 = 0; int res; int dofre; diff --git a/busybox/coreutils/uuencode.c b/uuencode.c similarity index 100% rename from busybox/coreutils/uuencode.c rename to uuencode.c diff --git a/busybox/editors/vi.c b/vi.c similarity index 99% rename from busybox/editors/vi.c rename to vi.c index 8d7506d0f..fba5f445a 100644 --- a/busybox/editors/vi.c +++ b/vi.c @@ -19,7 +19,7 @@ */ static const char vi_Version[] = - "$Id: vi.c,v 1.15 2001/08/02 05:26:41 andersen Exp $"; + "$Id: vi.c,v 1.20 2003/12/23 21:26:05 andersen Exp $"; /* * To compile for standalone use: @@ -324,7 +324,7 @@ extern int vi_main(int argc, char **argv) #ifdef BB_FEATURE_VI_CRASHME (void) srand((long) getpid()); #endif /* BB_FEATURE_VI_CRASHME */ - status_buffer = (Byte *) malloc(200); // hold messages to user + 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) { @@ -342,7 +342,7 @@ extern int vi_main(int argc, char **argv) reg[i] = 0; } // init the yank regs #endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_DOT_CMD +#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 */ @@ -789,6 +789,20 @@ static void do_cmd(Byte c) 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') { @@ -813,6 +827,7 @@ static void do_cmd(Byte c) goto dc1; } +key_cmd_mode: switch (c) { //case 0x01: // soh //case 0x09: // ht @@ -2492,7 +2507,7 @@ static Byte *new_screen(int ro, int co) if (screen != 0) free(screen); screensize = ro * co + 8; - screen = (Byte *) malloc(screensize); + 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 (~). @@ -2510,7 +2525,7 @@ static Byte *new_text(int size) //text -= 4; free(text); } - text = (Byte *) malloc(size + 8); + text = (Byte *) xmalloc(size + 8); memset(text, '\0', size); // clear new text[] //text += 4; // leave some room for "oops" textend = text + size - 1; @@ -3028,7 +3043,7 @@ static void start_new_cmd_q(Byte c) if (last_modifying_cmd != 0) free(last_modifying_cmd); // get buffer for new cmd - last_modifying_cmd = (Byte *) malloc(BUFSIZ); + 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) @@ -3084,7 +3099,7 @@ static Byte *text_yank(Byte * p, Byte * q, int dest) // copy text into a registe if (t != 0) { // if already a yank register free(t); // free it } - t = (Byte *) malloc(cnt + 1); // get a new register + 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; @@ -3157,10 +3172,8 @@ static void rawmode(void) 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); } @@ -3420,8 +3433,14 @@ static Byte get_one_char() // 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; + 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 */ diff --git a/busybox/miscutils/watchdog.c b/watchdog.c similarity index 100% rename from busybox/miscutils/watchdog.c rename to watchdog.c diff --git a/busybox/coreutils/wc.c b/wc.c similarity index 56% rename from busybox/coreutils/wc.c rename to wc.c index 695e7e7d4..fb81c0a8f 100644 --- a/busybox/coreutils/wc.c +++ b/wc.c @@ -26,40 +26,50 @@ #include #include "busybox.h" -static int total_lines, total_words, total_chars, max_length; -static int print_lines, print_words, print_chars, print_length; +enum print_e { + print_lines = 1, + print_words = 2, + print_chars = 4, + print_length = 8 +}; -static void print_counts(int lines, int words, int chars, int length, - const char *name) -{ - char const *space = ""; +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; - if (print_lines) { - printf("%7d", lines); - space = " "; +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_words) { - printf("%s%7d", space, words); - space = " "; + if (print_type & print_length) { + printf("%7d ", length); } - if (print_chars) { - printf("%s%7d", space, chars); - space = " "; + if (*name) { + printf("%s", name); } - 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; + 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; - lines = words = chars = length = 0; while ((c = getc(file)) != EOF) { chars++; switch (c) { @@ -77,7 +87,7 @@ static void wc_file(FILE * file, const char *name) case ' ': linepos++; case '\v': - word_separator: +word_separator: if (in_word) { in_word = 0; words++; @@ -89,68 +99,71 @@ static void wc_file(FILE * file, const char *name) break; } } - if (linepos > length) + if (linepos > length) { length = linepos; - if (in_word) + } + if (in_word) { words++; + } print_counts(lines, words, chars, length, name); total_lines += lines; total_words += words; total_chars += chars; - if (length > max_length) + 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; + int opt; while ((opt = getopt(argc, argv, "clLw")) > 0) { - switch (opt) { + switch (opt) { case 'c': - print_chars = 1; + print_type |= print_chars; break; case 'l': - print_lines = 1; + print_type |= print_lines; break; case 'L': - print_length = 1; + print_type |= print_length; break; case 'w': - print_words = 1; + print_type |= print_words; break; default: show_usage(); - } + } } - if (!print_lines && !print_words && !print_chars && !print_length) - print_lines = print_words = print_chars = 1; + if (print_type == 0) { + print_type = print_lines | print_words | print_chars; + } if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) { wc_file(stdin, ""); - return EXIT_SUCCESS; } else { + unsigned short num_files_counted = 0; while (optind < argc) { - if ((file = wfopen(argv[optind], "r")) != NULL) + 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]); - else - status = EXIT_FAILURE; - num_files_counted++; + fclose(file); + } optind++; + num_files_counted++; + } + if (num_files_counted > 1) { + print_counts(total_lines, total_words, total_chars, max_length, "total"); } } - if (num_files_counted > 1) - print_counts(total_lines, total_words, total_chars, - max_length, "total"); - - return status; + return(EXIT_SUCCESS); } diff --git a/busybox/networking/wget.c b/wget.c similarity index 96% rename from busybox/networking/wget.c rename to wget.c index 59373d1d9..ef85b62fb 100644 --- a/busybox/networking/wget.c +++ b/wget.c @@ -53,7 +53,8 @@ struct host_info { }; static void parse_url(char *url, struct host_info *h); -static FILE *open_socket(char *host, int port); +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); @@ -168,6 +169,7 @@ int wget_main(int argc, char **argv) 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) */ @@ -289,6 +291,8 @@ int wget_main(int argc, char **argv) do_continue = 0; } + s_in = lookup_host (server.host); + if (proxy || !target.is_ftp) { /* * HTTP session @@ -301,7 +305,7 @@ int wget_main(int argc, char **argv) * Open socket to http server */ if (sfp) fclose(sfp); - sfp = open_socket(server.host, server.port); + sfp = open_socket(s_in, server.port); /* * Send HTTP request. @@ -407,7 +411,7 @@ read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) if (! target.user) target.user = xstrdup("anonymous:busybox@"); - sfp = open_socket(server.host, server.port); + sfp = open_socket(s_in, server.port); if (ftpcmd(NULL, NULL, sfp, buf) != 220) close_delete_and_die("%s", buf+4); @@ -450,7 +454,7 @@ read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) port = atoi(s+1); s = strrchr(buf, ','); port += atoi(s+1) * 256; - dfp = open_socket(server.host, port); + dfp = open_socket(s_in, port); if (do_continue) { sprintf(buf, "REST %ld", beg_range); @@ -481,7 +485,8 @@ read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) #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); + if (safe_fwrite(buf, 1, n, output) != n) + perror_msg_and_die("fwrite"); #ifdef BB_FEATURE_WGET_STATUSBAR statbytes+=n; #endif @@ -533,7 +538,7 @@ void parse_url(char *url, struct host_info *h) *sp++ = '\0'; h->path = sp; } else - h->path = ""; + h->path = xstrdup(""); up = strrchr(h->host, '@'); if (up != NULL) { @@ -552,26 +557,34 @@ void parse_url(char *url, struct host_info *h) } -FILE *open_socket(char *host, int port) +static struct sockaddr_in *lookup_host(char *host) { - struct sockaddr_in s_in; + static 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); + + 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(%s)", host); + 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()"); @@ -817,7 +830,7 @@ progressmeter(int flag) * 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 $ + * $Id: wget.c,v 1.48 2002/04/27 07:40:00 andersen Exp $ */ diff --git a/busybox/findutils/which.c b/which.c similarity index 61% rename from busybox/findutils/which.c rename to which.c index c460ffdd1..365c83bcd 100644 --- a/busybox/findutils/which.c +++ b/which.c @@ -2,8 +2,7 @@ /* * Which implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , + * Copyright (C) 1999-2003 by Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,10 +26,19 @@ #include #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; - struct stat filestat; int i, count=1, found, status = EXIT_SUCCESS; if (argc <= 1 || **(argv + 1) == '-') @@ -38,32 +46,42 @@ extern int which_main(int argc, char **argv) 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++; - } + 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; - 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; + + /* + * 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); } - free(buf); - path_n += (strlen(path_n) + 1); } if (!found) status = EXIT_FAILURE; diff --git a/busybox/coreutils/whoami.c b/whoami.c similarity index 100% rename from busybox/coreutils/whoami.c rename to whoami.c diff --git a/busybox/findutils/xargs.c b/xargs.c similarity index 76% rename from busybox/findutils/xargs.c rename to xargs.c index 48adae90a..a89a799a2 100644 --- a/busybox/findutils/xargs.c +++ b/xargs.c @@ -1,9 +1,9 @@ /* * Mini xargs implementation for busybox * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * Remixed by Mark Whitley , + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen + * Remixed by Mark Whitley * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,8 +28,10 @@ int xargs_main(int argc, char **argv) { - char *cmd_to_be_executed = NULL; - char *file_to_act_on = NULL; + 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. @@ -45,33 +47,35 @@ int xargs_main(int argc, char **argv) /* 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 "); + argv[0] = "/bin/echo"; + len++; /* space for trailing ' ' */ + len++; /* space for trailing '\0' */ } 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, " "); + 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 = NULL; - char *output_line = NULL; - char *execstr = NULL; + FILE *cmd_output; + char *output_line; + char *execstr; /* eat the newline off the filename. */ chomp(file_to_act_on); /* eat blank lines */ - if (strlen(file_to_act_on) == 0) + if (file_to_act_on[0] == 0) continue; /* assemble the command and execute it */ @@ -79,6 +83,7 @@ int xargs_main(int argc, char **argv) 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"); diff --git a/busybox/coreutils/yes.c b/yes.c similarity index 100% rename from busybox/coreutils/yes.c rename to yes.c