summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-10-24 05:00:29 +0000
committerEric Andersen <andersen@codepoet.org>2001-10-24 05:00:29 +0000
commitbdfd0d78bc44e73d693510e70087857785b3b521 (patch)
tree153a573095afac8d8d0ea857759ecabd77fb28b7
parent9260fc5552a3ee52eb95823aa6689d52a1ffd33c (diff)
downloadbusybox-w32-bdfd0d78bc44e73d693510e70087857785b3b521.tar.gz
busybox-w32-bdfd0d78bc44e73d693510e70087857785b3b521.tar.bz2
busybox-w32-bdfd0d78bc44e73d693510e70087857785b3b521.zip
Major rework of the directory structure and the entire build system.
-Erik
-rw-r--r--.cvsignore1
-rw-r--r--AUTHORS2
-rw-r--r--Changelog66
-rw-r--r--Config.h494
-rw-r--r--LICENSE9
-rw-r--r--Makefile311
-rw-r--r--README15
-rw-r--r--addgroup.c178
-rw-r--r--adduser.c366
-rw-r--r--adjtimex.c176
-rw-r--r--applets.c116
-rw-r--r--applets.h500
-rw-r--r--applets/busybox.c14
-rwxr-xr-xapplets/busybox.sh4
-rw-r--r--applets/usage.h54
-rw-r--r--ar.c89
-rw-r--r--archival/Makefile43
-rw-r--r--archival/config.in19
-rw-r--r--archival/gzip.c2
-rw-r--r--archival/tar.c32
-rw-r--r--ash.c12825
-rw-r--r--basename.c52
-rw-r--r--bunzip2.c2340
-rw-r--r--busybox.c181
-rw-r--r--busybox.h106
-rwxr-xr-xbusybox.mkll24
-rwxr-xr-xbusybox.sh16
-rw-r--r--busybox.spec44
-rw-r--r--cat.c53
-rw-r--r--chgrp.c91
-rw-r--r--chmod.c85
-rw-r--r--chown.c113
-rw-r--r--chroot.c75
-rw-r--r--chvt.c43
-rw-r--r--clear.c34
-rw-r--r--cmdedit.c1521
-rw-r--r--cmdedit.h6
-rw-r--r--cmp.c80
-rw-r--r--console-tools/Makefile43
-rw-r--r--console-tools/clear.c5
-rw-r--r--console-tools/config.in18
-rw-r--r--console-tools/reset.c7
-rw-r--r--coreutils/basename.c4
-rw-r--r--coreutils/cat.c4
-rw-r--r--coreutils/chgrp.c7
-rw-r--r--coreutils/chmod.c7
-rw-r--r--coreutils/chown.c7
-rw-r--r--coreutils/chroot.c7
-rw-r--r--coreutils/cmp.c4
-rw-r--r--coreutils/df.c12
-rw-r--r--coreutils/dirname.c4
-rw-r--r--coreutils/du.c15
-rw-r--r--coreutils/head.c5
-rw-r--r--coreutils/ln.c4
-rw-r--r--coreutils/ls.c116
-rw-r--r--coreutils/rmdir.c5
-rw-r--r--coreutils/sort.c14
-rw-r--r--coreutils/tail.c12
-rw-r--r--coreutils/tee.c3
-rw-r--r--coreutils/touch.c5
-rw-r--r--coreutils/tr.c10
-rw-r--r--coreutils/uniq.c5
-rw-r--r--coreutils/uuencode.c4
-rw-r--r--cp.c114
-rw-r--r--cpio.c95
-rw-r--r--cut.c356
-rw-r--r--date.c247
-rw-r--r--dc.c182
-rw-r--r--dd.c154
-rw-r--r--deallocvt.c43
-rw-r--r--debian/Config.h-deb498
-rw-r--r--debian/Config.h-static498
-rw-r--r--debian/Config.h-udeb498
-rwxr-xr-xdebian/rules14
-rw-r--r--deluser.c175
-rw-r--r--df.c158
-rw-r--r--dirname.c40
-rw-r--r--dmesg.c95
-rwxr-xr-xdocs/autodocifier.pl4
-rw-r--r--docs/busybox.net/index.html3
-rw-r--r--docs/busybox.net/oldnews.html23
-rw-r--r--docs/new-applet-HOWTO.txt4
-rw-r--r--docs/style-guide.txt10
-rw-r--r--dos2unix.c194
-rw-r--r--dpkg.c1509
-rw-r--r--dpkg_deb.c130
-rw-r--r--du.c257
-rw-r--r--dumpkmap.c95
-rw-r--r--dutmp.c64
-rw-r--r--echo.c152
-rw-r--r--editors/Makefile36
-rw-r--r--editors/config.in12
-rw-r--r--editors/sed.c8
-rw-r--r--editors/vi.c450
-rw-r--r--env.c106
-rw-r--r--examples/inittab4
-rw-r--r--examples/kernel-patches/devps.patch.9_25_200012
-rwxr-xr-xexamples/mk2knr.pl2
-rw-r--r--expr.c535
-rw-r--r--fbset.c424
-rw-r--r--fdflush.c47
-rw-r--r--find.c200
-rw-r--r--findutils/Makefile39
-rw-r--r--findutils/config.in14
-rw-r--r--findutils/find.c24
-rw-r--r--findutils/grep.c36
-rw-r--r--findutils/which.c4
-rw-r--r--findutils/xargs.c8
-rw-r--r--free.c69
-rw-r--r--freeramdisk.c64
-rw-r--r--fsck_minix.c1478
-rw-r--r--getopt.c402
-rw-r--r--getty.c1232
-rw-r--r--grep.c358
-rw-r--r--gunzip.c183
-rw-r--r--gzip.c2568
-rw-r--r--halt.c41
-rw-r--r--head.c97
-rw-r--r--hostid.c32
-rw-r--r--hostname.c128
-rw-r--r--hush.c2695
-rw-r--r--id.c97
-rw-r--r--ifconfig.c492
-rw-r--r--include/applets.h302
-rw-r--r--include/busybox.h28
-rw-r--r--include/grp.h6
-rw-r--r--include/libbb.h14
-rw-r--r--include/pwd.h6
-rw-r--r--include/usage.h54
-rw-r--r--init.c1045
-rw-r--r--init/Makefile39
-rw-r--r--init/config.in25
-rw-r--r--init/halt.c2
-rw-r--r--init/init.c32
-rw-r--r--init/poweroff.c2
-rw-r--r--init/reboot.c2
-rw-r--r--insmod.c3485
-rwxr-xr-xinstall.sh52
-rw-r--r--kill.c142
-rw-r--r--klogd.c153
-rw-r--r--lash.c1640
-rw-r--r--length.c13
-rw-r--r--libbb/Makefile78
-rw-r--r--libbb/ask_confirmation.c16
-rw-r--r--libbb/chomp.c16
-rw-r--r--libbb/concat_path_file.c25
-rw-r--r--libbb/copy_file.c1
-rw-r--r--libbb/copy_file_chunk.c16
-rw-r--r--libbb/copyfd.c2
-rw-r--r--libbb/device_open.c8
-rw-r--r--libbb/error_msg.c8
-rw-r--r--libbb/error_msg_and_die.c8
-rw-r--r--libbb/fgets_str.c28
-rw-r--r--libbb/find_mount_point.c8
-rw-r--r--libbb/find_pid_by_name.c14
-rw-r--r--libbb/find_root_device.c6
-rw-r--r--libbb/full_read.c8
-rw-r--r--libbb/full_write.c8
-rw-r--r--libbb/get_console.c9
-rw-r--r--libbb/get_last_path_component.c8
-rw-r--r--libbb/get_line_from_file.c9
-rw-r--r--libbb/gz_open.c23
-rw-r--r--libbb/herror_msg.c8
-rw-r--r--libbb/herror_msg_and_die.c9
-rw-r--r--libbb/inode_hash.c16
-rw-r--r--libbb/interface.c25
-rw-r--r--libbb/isdirectory.c9
-rw-r--r--libbb/kernel_version.c8
-rw-r--r--libbb/libbb.h326
-rw-r--r--libbb/loop.c8
-rw-r--r--libbb/messages.c5
-rw-r--r--libbb/mode_string.c16
-rw-r--r--libbb/module_syscalls.c4
-rw-r--r--libbb/mtab.c20
-rw-r--r--libbb/mtab_file.c12
-rw-r--r--libbb/my_getgrgid.c12
-rw-r--r--libbb/my_getgrnam.c13
-rw-r--r--libbb/my_getpwnam.c13
-rw-r--r--libbb/my_getpwnamegid.c12
-rw-r--r--libbb/my_getpwuid.c12
-rw-r--r--libbb/parse_mode.c16
-rw-r--r--libbb/parse_number.c16
-rw-r--r--libbb/perror_msg.c8
-rw-r--r--libbb/perror_msg_and_die.c8
-rw-r--r--libbb/print_file.c2
-rw-r--r--libbb/read_package_field.c23
-rw-r--r--libbb/recursive_action.c8
-rw-r--r--libbb/remove_file.c3
-rw-r--r--libbb/safe_read.c8
-rw-r--r--libbb/safe_strncpy.c8
-rw-r--r--libbb/syscalls.c4
-rw-r--r--libbb/syslog_msg_with_name.c8
-rw-r--r--libbb/time_string.c8
-rw-r--r--libbb/trim.c16
-rw-r--r--libbb/u_signal_names.c23
-rw-r--r--libbb/vdprintf.c8
-rw-r--r--libbb/verror_msg.c8
-rw-r--r--libbb/vherror_msg.c8
-rw-r--r--libbb/vperror_msg.c8
-rw-r--r--libbb/wfopen.c8
-rw-r--r--libbb/xfuncs.c8
-rw-r--r--libbb/xgethostbyname.c1
-rw-r--r--libbb/xregcomp.c16
-rw-r--r--ln.c131
-rw-r--r--loadacm.c357
-rw-r--r--loadfont.c209
-rw-r--r--loadkmap.c89
-rw-r--r--logger.c200
-rw-r--r--logname.c41
-rw-r--r--logread.c144
-rw-r--r--ls.c937
-rw-r--r--lsmod.c166
-rw-r--r--makedevs.c95
-rw-r--r--md5sum.c1074
-rw-r--r--miscutils/Makefile44
-rw-r--r--miscutils/config.in20
-rw-r--r--miscutils/readlink.c6
-rwxr-xr-xmk_loop_h.sh37
-rw-r--r--mkdir.c64
-rw-r--r--mkfifo.c60
-rw-r--r--mkfs_minix.c847
-rw-r--r--mknod.c92
-rw-r--r--mkswap.c422
-rw-r--r--mktemp.c40
-rw-r--r--modprobe.c121
-rw-r--r--modutils/Makefile39
-rw-r--r--modutils/config.in22
-rw-r--r--modutils/insmod.c131
-rw-r--r--modutils/lsmod.c10
-rw-r--r--modutils/rmmod.c4
-rw-r--r--more.c217
-rw-r--r--mount.c498
-rw-r--r--msh.c4870
-rw-r--r--mt.c121
-rw-r--r--mv.c168
-rw-r--r--nc.c137
-rw-r--r--networking/Makefile45
-rw-r--r--networking/config.in21
-rw-r--r--networking/hostname.c4
-rw-r--r--networking/ifconfig.c30
-rw-r--r--networking/nslookup.c6
-rw-r--r--networking/ping.c8
-rw-r--r--networking/telnet.c12
-rw-r--r--networking/tftp.c38
-rw-r--r--networking/traceroute.c26
-rw-r--r--networking/wget.c24
-rw-r--r--nfsmount.c977
-rw-r--r--nfsmount.h242
-rw-r--r--nslookup.c183
-rw-r--r--pidof.c79
-rw-r--r--ping.c555
-rw-r--r--pivot_root.c35
-rw-r--r--poweroff.c41
-rw-r--r--printf.c455
-rwxr-xr-xpristine_setup.sh46
-rw-r--r--procps/Makefile40
-rw-r--r--procps/config.in17
-rw-r--r--procps/free.c4
-rw-r--r--procps/kill.c4
-rw-r--r--procps/pidof.c4
-rw-r--r--procps/ps.c32
-rw-r--r--procps/uptime.c6
-rw-r--r--ps.c266
-rw-r--r--pwd.c44
-rw-r--r--rdate.c116
-rw-r--r--readlink.c48
-rw-r--r--reboot.c49
-rw-r--r--renice.c54
-rw-r--r--reset.c35
-rw-r--r--rm.c77
-rw-r--r--rmdir.c97
-rw-r--r--rmmod.c62
-rw-r--r--route.c452
-rw-r--r--rpm2cpio.c91
-rw-r--r--scripts/Configure705
-rw-r--r--scripts/Menuconfig1285
-rwxr-xr-xscripts/depmod.pl227
-rw-r--r--scripts/inittab86
-rw-r--r--scripts/lxdialog/BIG.FAT.WARNING4
-rw-r--r--scripts/lxdialog/Makefile46
-rw-r--r--scripts/lxdialog/Makefile-2.571
-rw-r--r--scripts/lxdialog/checklist.c369
-rw-r--r--scripts/lxdialog/colors.h161
-rw-r--r--scripts/lxdialog/dialog.h184
-rw-r--r--scripts/lxdialog/inputbox.c240
-rw-r--r--scripts/lxdialog/lxdialog.c226
-rw-r--r--scripts/lxdialog/menubox.c443
-rw-r--r--scripts/lxdialog/msgbox.c85
-rw-r--r--scripts/lxdialog/textbox.c556
-rw-r--r--scripts/lxdialog/util.c359
-rw-r--r--scripts/lxdialog/yesno.c118
-rwxr-xr-xscripts/mk2knr.pl84
-rw-r--r--scripts/mkdep.c628
-rw-r--r--scripts/split-include.c226
-rw-r--r--scripts/undeb53
-rw-r--r--scripts/unrpm48
-rw-r--r--sed.c850
-rw-r--r--setkeycodes.c72
-rw-r--r--shell/Makefile40
-rw-r--r--shell/ash.c34
-rw-r--r--shell/cmdedit.c94
-rw-r--r--shell/config.in51
-rw-r--r--shell/hush.c21
-rw-r--r--shell/lash.c38
-rw-r--r--shell/msh.c26
-rw-r--r--sleep.c38
-rw-r--r--sort.c106
-rw-r--r--start_stop_daemon.c271
-rw-r--r--stty.c1376
-rw-r--r--swaponoff.c115
-rw-r--r--sync.c35
-rw-r--r--sysdeps/linux/config.in23
-rw-r--r--sysdeps/linux/defconfig0
-rw-r--r--sysklogd/Makefile38
-rw-r--r--sysklogd/config.in16
-rw-r--r--sysklogd/klogd.c4
-rw-r--r--sysklogd/logger.c6
-rw-r--r--sysklogd/logread.c2
-rw-r--r--sysklogd/syslogd.c30
-rw-r--r--syslogd.c641
-rw-r--r--tail.c251
-rw-r--r--tar.c745
-rw-r--r--tee.c67
-rw-r--r--telnet.c711
-rw-r--r--test.c579
-rwxr-xr-xtests/multibuild.pl8
-rwxr-xr-xtests/multifeat.pl8
-rw-r--r--tests/testcases2
-rwxr-xr-xtests/tester.sh14
-rw-r--r--tftp.c574
-rw-r--r--touch.c75
-rw-r--r--tr.c248
-rw-r--r--traceroute.c652
-rw-r--r--true_false.c39
-rw-r--r--tty.c44
-rw-r--r--umount.c298
-rw-r--r--uname.c156
-rw-r--r--uniq.c89
-rw-r--r--update.c112
-rw-r--r--uptime.c77
-rw-r--r--usage.c10
-rw-r--r--usage.h1894
-rw-r--r--usleep.c38
-rw-r--r--util-linux/Makefile48
-rw-r--r--util-linux/config.in27
-rw-r--r--util-linux/fbset.c12
-rw-r--r--util-linux/fsck_minix.c42
-rw-r--r--util-linux/mkfs_minix.c20
-rw-r--r--util-linux/more.c12
-rw-r--r--util-linux/mount.c26
-rw-r--r--util-linux/swaponoff.c5
-rw-r--r--util-linux/umount.c29
-rw-r--r--uudecode.c353
-rw-r--r--uuencode.c180
-rw-r--r--vi.c3947
-rw-r--r--watchdog.c49
-rw-r--r--wc.c156
-rw-r--r--wget.c834
-rw-r--r--which.c80
-rw-r--r--whoami.c44
-rw-r--r--xargs.c105
-rw-r--r--yes.c53
362 files changed, 8827 insertions, 75864 deletions
diff --git a/.cvsignore b/.cvsignore
index 71269c542..618c9fd84 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -2,3 +2,4 @@ busybox
2busybox.links 2busybox.links
3_install 3_install
4applet_source_list 4applet_source_list
5.config
diff --git a/AUTHORS b/AUTHORS
index 09b0b5095..4df213aa0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,7 +8,7 @@ incorect, _please_ let me know.
8 8
9----------- 9-----------
10 10
11Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 11Erik Andersen <andersen@codepoet.org>, <andersee@debian.org>
12 Tons of new stuff, major rewrite of most of the 12 Tons of new stuff, major rewrite of most of the
13 core apps, tons of new apps as noted in header files. 13 core apps, tons of new apps as noted in header files.
14 14
diff --git a/Changelog b/Changelog
index 9ed6d58ce..2a778d65d 100644
--- a/Changelog
+++ b/Changelog
@@ -52,8 +52,8 @@
52 -- Fixed msh to support underscores in variable names. 52 -- Fixed msh to support underscores in variable names.
53 -- Fixed a sed problem with unsatisfied backrefs (the problem was 53 -- Fixed a sed problem with unsatisfied backrefs (the problem was
54 noted by Martin Bene). 54 noted by Martin Bene).
55 -- Removed BB_SH define entirely. Now one simply picks the shell 55 -- Removed CONFIG_SH define entirely. Now one simply picks the shell
56 or shells they want as BB_<foo> in Config.h 56 or shells they want as CONFIG_<foo> in Config.h
57 -- Fixed head to use ferror(3) to check for errors, not errno. 57 -- Fixed head to use ferror(3) to check for errors, not errno.
58 * Shu-Hao Chang <shuhao_chang@trend.com.tw> 58 * Shu-Hao Chang <shuhao_chang@trend.com.tw>
59 -- Fixed sed handling of multiple -e commands 59 -- Fixed sed handling of multiple -e commands
@@ -62,10 +62,10 @@
62 * Jaspreet Singh <jsingh@somanetworks.com> 62 * Jaspreet Singh <jsingh@somanetworks.com>
63 -- Fixed both a segfault and cosmetic bug in route 63 -- Fixed both a segfault and cosmetic bug in route
64 * Erik Andersen 64 * Erik Andersen
65 -- Made the insmod options BB_FEATURE_NEW_MODULE_INTERFACE and 65 -- Made the insmod options CONFIG_FEATURE_NEW_MODULE_INTERFACE and
66 BB_FEATURE_OLD_MODULE_INTERFACE mutually exclusive 66 CONFIG_FEATURE_OLD_MODULE_INTERFACE mutually exclusive
67 -- xgetcwd.c now includes sys/param.h to ensure PATH_MAX is defined 67 -- xgetcwd.c now includes sys/param.h to ensure PATH_MAX is defined
68 -- Fixed a potential segfault with lash + BB_FEATURE_CLEAN_UP 68 -- Fixed a potential segfault with lash + CONFIG_FEATURE_CLEAN_UP
69 -- Removed uint64_t from dos2unix, avoiding C lib compat. problems. 69 -- Removed uint64_t from dos2unix, avoiding C lib compat. problems.
70 * Glenn McGrath 70 * Glenn McGrath
71 -- Rewrite of tftp (commands match atftp, accepts -b, can use 71 -- Rewrite of tftp (commands match atftp, accepts -b, can use
@@ -136,7 +136,7 @@
136 * Matt Kraai 136 * Matt Kraai
137 -- Made tar read 20 512byte blocks at a time (like GNU tar) 137 -- Made tar read 20 512byte blocks at a time (like GNU tar)
138 -- Allow msh.c assignments with the export and readonly commands. 138 -- Allow msh.c assignments with the export and readonly commands.
139 -- Added BB_FEATURE_DEVFS to enable devfs device names. 139 -- Added CONFIG_FEATURE_DEVFS to enable devfs device names.
140 -- Better devfs support 140 -- Better devfs support
141 -- Don't save/restore vi readonly flag if vi is compiled read-only. 141 -- Don't save/restore vi readonly flag if vi is compiled read-only.
142 -- Reworked rdate option handling (is now smaller). 142 -- Reworked rdate option handling (is now smaller).
@@ -317,7 +317,7 @@
317 * Magnus Damm -- added a tftp applet 317 * Magnus Damm -- added a tftp applet
318 * Magnus Damm -- powerpc support for busybox insmod. 318 * Magnus Damm -- powerpc support for busybox insmod.
319 * David Douthitt -- fixed a build error in df.c when 319 * David Douthitt -- fixed a build error in df.c when
320 BB_FEATURE_HUMAN_READABLE was disabled 320 CONFIG_FEATURE_HUMAN_READABLE was disabled
321 * John Beppu -- wrote autodocifier.pl, which will be used to auto- 321 * John Beppu -- wrote autodocifier.pl, which will be used to auto-
322 generate the documentation from the source code, making life 322 generate the documentation from the source code, making life
323 much simpler for all. 323 much simpler for all.
@@ -424,7 +424,7 @@
424 * Mark Whitley -- Updates to style guide 424 * Mark Whitley -- Updates to style guide
425 * Mark Whitley -- Big cleanup in utility.c: style guide compliance, 425 * Mark Whitley -- Big cleanup in utility.c: style guide compliance,
426 de-macro-ifying some variables and functions 426 de-macro-ifying some variables and functions
427 * Erik Andersen -- ls now honors BB_FEATURE_AUTOWIDTH so it can find 427 * Erik Andersen -- ls now honors CONFIG_FEATURE_AUTOWIDTH so it can find
428 the width and height of the console. 428 the width and height of the console.
429 * Erik Andersen -- insmod now ignores -L and accepts the -o option. 429 * Erik Andersen -- insmod now ignores -L and accepts the -o option.
430 * Erik Andersen -- updates so you can now select from the Makefile 430 * Erik Andersen -- updates so you can now select from the Makefile
@@ -440,7 +440,7 @@
4400.48 4400.48
441 441
442 * Glenn McGrath -- tar now supports uncompressing tar files, 442 * Glenn McGrath -- tar now supports uncompressing tar files,
443 define BB_FEATURE_TAR_GZIP to use the -z option. 443 define CONFIG_FEATURE_TAR_GZIP to use the -z option.
444 * Matt Kraai -- fix all usage of TRUE and FALSE so all apps now 444 * Matt Kraai -- fix all usage of TRUE and FALSE so all apps now
445 return EXIT_SUCCESS or EXIT_FAILURE to the system. 445 return EXIT_SUCCESS or EXIT_FAILURE to the system.
446 Now TRUE and FALSE are set to the C standard where TRUE=1. 446 Now TRUE and FALSE are set to the C standard where TRUE=1.
@@ -472,7 +472,7 @@
472 GNU-date compatible 472 GNU-date compatible
473 * me -- Progress meter (optional) in wget 473 * me -- Progress meter (optional) in wget
474 * Doolittle/me -- programs invoked by full path name take 474 * Doolittle/me -- programs invoked by full path name take
475 precedence over applets unless BB_FEATURE_SH_BUILTINS_ALWAYS_WIN 475 precedence over applets unless CONFIG_FEATURE_SH_BUILTINS_ALWAYS_WIN
476 * Gaute B Strokkenes <gs234@cam.ac.uk> -- applets found using a 476 * Gaute B Strokkenes <gs234@cam.ac.uk> -- applets found using a
477 binary search instead of linear search. Much faster! 477 binary search instead of linear search. Much faster!
478 * new applets: cmp readlink 478 * new applets: cmp readlink
@@ -605,7 +605,7 @@
6050.45 6050.45
606 * Now compiles vs libc5 (which can save lots of space for 606 * Now compiles vs libc5 (which can save lots of space for
607 embedded systems). 607 embedded systems).
608 * Added BB_FEATURE_TRIVIAL_HELP which compiles out most all of the 608 * Added CONFIG_FEATURE_TRIVIAL_HELP which compiles out most all of the
609 help messages (i.e --help). Saves 17k over a full compile. 609 help messages (i.e --help). Saves 17k over a full compile.
610 * Added cut and tr from minix, since due to the license change, 610 * Added cut and tr from minix, since due to the license change,
611 we can now use minix code. Minix tr saves 4k. 611 we can now use minix code. Minix tr saves 4k.
@@ -626,7 +626,7 @@
626 * Replaced the telnet implementation with one written by 626 * Replaced the telnet implementation with one written by
627 Tomi Ollila <too@iki.fi> It works great and costs 3k. 627 Tomi Ollila <too@iki.fi> It works great and costs 3k.
628 * BusyBox sh (lash) now supports being used as a standalone shell. When 628 * BusyBox sh (lash) now supports being used as a standalone shell. When
629 BB_FEATURE_SH_STANDALONE_SHELL is defined, all the busybox commands may 629 CONFIG_FEATURE_SH_STANDALONE_SHELL is defined, all the busybox commands may
630 be invoked as shell internals. Best used when compiling staticly 630 be invoked as shell internals. Best used when compiling staticly
631 (i.e. DOSTATIC=true) 631 (i.e. DOSTATIC=true)
632 * BusyBox sh (lash) internals now behave as expected wrt pipes 632 * BusyBox sh (lash) internals now behave as expected wrt pipes
@@ -678,7 +678,7 @@
678 * Fixed exit status for killall - Pavel Roskin 678 * Fixed exit status for killall - Pavel Roskin
679 * Fixed 'swapon -a' and 'swapoff -a', which were broken. 679 * Fixed 'swapon -a' and 'swapoff -a', which were broken.
680 * Fixed 'mount -a' so it works as expected. 680 * Fixed 'mount -a' so it works as expected.
681 * Implemented 'ls -R' (enabled by enabling BB_FEATURE_LS_RECURSIVE) 681 * Implemented 'ls -R' (enabled by enabling CONFIG_FEATURE_LS_RECURSIVE)
682 * Implemented "ping -s", fixed error messages and argument parsing - 682 * Implemented "ping -s", fixed error messages and argument parsing -
683 Pavel Roskin 683 Pavel Roskin
684 * Syslogd will not go to background if "-n" is given. Better help 684 * Syslogd will not go to background if "-n" is given. Better help
@@ -716,7 +716,7 @@
716 saving a bunch of memory (kernel /proc support is not thin). This 716 saving a bunch of memory (kernel /proc support is not thin). This
717 is done by making use of some nice kernel patches I wrote up to 717 is done by making use of some nice kernel patches I wrote up to
718 support the features that busybox requires and that /proc usually 718 support the features that busybox requires and that /proc usually
719 provides. To enable this, turn on BB_FEATURE_USE_DEVPS_PATCH and 719 provides. To enable this, turn on CONFIG_FEATURE_USE_DEVPS_PATCH and
720 patch your kernel with the devps patch in the kernel-patches/ 720 patch your kernel with the devps patch in the kernel-patches/
721 directory. 721 directory.
722 * Wrote basename, dirname, killall, and uptime. 722 * Wrote basename, dirname, killall, and uptime.
@@ -761,7 +761,7 @@
761 * An initial telnet implementation was added by 761 * An initial telnet implementation was added by
762 Randolph Chung <tausq@debian.org>. 762 Randolph Chung <tausq@debian.org>.
763 * Fixed a bug where "sed 's/foo/bar/g'" (i.e. a script w/o a "-e") 763 * Fixed a bug where "sed 's/foo/bar/g'" (i.e. a script w/o a "-e")
764 * ps now supports BB_FEATURE_AUTOWIDTH, and can adjust its width 764 * ps now supports CONFIG_FEATURE_AUTOWIDTH, and can adjust its width
765 to match the terminal (defaults to width=79 when this is off). 765 to match the terminal (defaults to width=79 when this is off).
766 * ps now accepts (and ignores) all options except for "--help" (which 766 * ps now accepts (and ignores) all options except for "--help" (which
767 as would be expected displays help). 767 as would be expected displays help).
@@ -784,7 +784,7 @@
784 784
785 * Fairly massive restructuring of umount.c to deal with remounting 785 * Fairly massive restructuring of umount.c to deal with remounting
786 busy devices read-only. Adds a -r option to control that; it is 786 busy devices read-only. Adds a -r option to control that; it is
787 optionally compiled in with BB_FEATURE_REMOUNT 787 optionally compiled in with CONFIG_FEATURE_REMOUNT
788 * Added a bunch of functions to mtab.c to interact with the 788 * Added a bunch of functions to mtab.c to interact with the
789 {get,set,end}mntent interface; as it turns out, those functions do 789 {get,set,end}mntent interface; as it turns out, those functions do
790 not appear to be re-entrant, and that causes a lot of problems with 790 not appear to be re-entrant, and that causes a lot of problems with
@@ -855,7 +855,7 @@
855 * Created a tiny tail implementation, removing -c, -q, -v, and making 855 * Created a tiny tail implementation, removing -c, -q, -v, and making
856 tail -f work only with a single file. This reduced tail from 6k to 856 tail -f work only with a single file. This reduced tail from 6k to
857 2.4k. The bigger/more featured tail can still be had by disabling 857 2.4k. The bigger/more featured tail can still be had by disabling
858 BB_FEATURE_SIMPLE_TAIL in busybox.defs.h 858 CONFIG_FEATURE_SIMPLE_TAIL in busybox.defs.h
859 * Ping now falls back to doing the right thing if /etc/protocols 859 * Ping now falls back to doing the right thing if /etc/protocols
860 turns up missing. 860 turns up missing.
861 * Fixed mount and umount. Previously they could leak loop device 861 * Fixed mount and umount. Previously they could leak loop device
@@ -907,14 +907,14 @@
907 devices. Support is toggled by MOUNT_LOOP feature -- Ben Collins 907 devices. Support is toggled by MOUNT_LOOP feature -- Ben Collins
908 <bcollins@debian.org> 908 <bcollins@debian.org>
909 * Several fixes from Marco Pantaleoni <panta@prosa.it> compile in 909 * Several fixes from Marco Pantaleoni <panta@prosa.it> compile in
910 * fullWrite() not only if BB_TAR is defined, but also 910 * fullWrite() not only if CONFIG_TAR is defined, but also
911 if BB_CP or BB_MV are (fullWrite() is referenced by copyFile()) 911 if CONFIG_CP or CONFIG_MV are (fullWrite() is referenced by copyFile())
912 * add some compiler optimizations to further reduce executable size 912 * add some compiler optimizations to further reduce executable size
913 (as a side note, on my machines the largest code is generated 913 (as a side note, on my machines the largest code is generated
914 by gcc 2.95.2 with -Os ! The smallest by plain gcc 2.7.2.3 with 914 by gcc 2.95.2 with -Os ! The smallest by plain gcc 2.7.2.3 with
915 -O2 -m386 ...) 915 -O2 -m386 ...)
916 * Compile now won't fail if busybox.def.h defines 916 * Compile now won't fail if busybox.def.h defines
917 BB_FEATURE_LINUXRC but not BB_INIT. (init_main used to be 917 CONFIG_FEATURE_INITRD but not CONFIG_INIT. (init_main used to be
918 referenced, but not compiled) 918 referenced, but not compiled)
919 * Fixed a bug in setting TERM for serial console support. TERM now 919 * Fixed a bug in setting TERM for serial console support. TERM now
920 defaults to "ansi" for serial consoles. 920 defaults to "ansi" for serial consoles.
@@ -974,7 +974,7 @@
974 to suit my evil purposes. Costs 6k. I'll make it smaller 974 to suit my evil purposes. Costs 6k. I'll make it smaller
975 sometime. 975 sometime.
976 * on reboot, init called 'umount -a -n', which caused errors 976 * on reboot, init called 'umount -a -n', which caused errors
977 when BB_MTAB was not enabled. Changed to 'umount -a', which does 977 when CONFIG_MTAB was not enabled. Changed to 'umount -a', which does
978 the right thing. 978 the right thing.
979 * init will now try to run /sbin/getty if it is present (for easy 979 * init will now try to run /sbin/getty if it is present (for easy
980 integration with the about-to-be-released tinylogin.) 980 integration with the about-to-be-released tinylogin.)
@@ -1009,7 +1009,7 @@
1009 * I've taken a first step to making busybox not need the /proc 1009 * I've taken a first step to making busybox not need the /proc
1010 filesystem. Most apps don't need it. Those that _require_ it, 1010 filesystem. Most apps don't need it. Those that _require_ it,
1011 will complain if you enable them when you disable 1011 will complain if you enable them when you disable
1012 BB_FEATURE_USE_PROCFS. 1012 CONFIG_FEATURE_USE_PROCFS.
1013 1013
1014 -Erik Andersen, Dec 5, 1999 1014 -Erik Andersen, Dec 5, 1999
1015 1015
@@ -1047,7 +1047,7 @@
1047 * from 1047 * from
1048 Eric Delaunay). 1048 Eric Delaunay).
1049 * Made createPath be quiet (again thanks to Eric Delaunay). If 1049 * Made createPath be quiet (again thanks to Eric Delaunay). If
1050 * BB_CONSOLE_CMD_IF_RC_SCRIPT_EXITS is defined, then whatever 1050 * CONFIG_CONSOLE_CMD_IF_RC_SCRIPT_EXITS is defined, then whatever
1051 command you define it as will be run if the init script exits. 1051 command you define it as will be run if the init script exits.
1052 * Updated install.sh to make it more robust (thanks to Adam Di Carlo) 1052 * Updated install.sh to make it more robust (thanks to Adam Di Carlo)
1053 * NFS support added to mount by Eric Delaunay. It costs 10k when 1053 * NFS support added to mount by Eric Delaunay. It costs 10k when
@@ -1103,7 +1103,7 @@
1103 to Eric Delaunay. 1103 to Eric Delaunay.
1104 * more started to read from stdin after the last file was finished, and 1104 * more started to read from stdin after the last file was finished, and
1105 options were not parsed correctly (fix thanks to Eric Delaunay). 1105 options were not parsed correctly (fix thanks to Eric Delaunay).
1106 * more will now use the terminal size if BB_FEATURE_AUTOWIDTH is on. 1106 * more will now use the terminal size if CONFIG_FEATURE_AUTOWIDTH is on.
1107 * rm wouldn't remove a symlink unless the symlink was valid. This was 1107 * rm wouldn't remove a symlink unless the symlink was valid. This was
1108 a side effect of the busybox 0.32 recursiveAction() fix. Things 1108 a side effect of the busybox 0.32 recursiveAction() fix. Things
1109 should now work correctly. 1109 should now work correctly.
@@ -1121,7 +1121,7 @@
1121 * Removed some debugging noise from init.c 1121 * Removed some debugging noise from init.c
1122 * Fixed ln so it works now (it was very broken). 1122 * Fixed ln so it works now (it was very broken).
1123 * Fixed df so it won't segfault when there is no /etc/fstab, 1123 * Fixed df so it won't segfault when there is no /etc/fstab,
1124 * If BB_MTAB is not defined, df and mount will whine if /etc/fstab 1124 * If CONFIG_MTAB is not defined, df and mount will whine if /etc/fstab
1125 is not installed (since they cannot fixup "/dev/root" to 1125 is not installed (since they cannot fixup "/dev/root" to
1126 state the real root device name) 1126 state the real root device name)
1127 * merged some redundant code from mtab.c/df.c into utility.c 1127 * merged some redundant code from mtab.c/df.c into utility.c
@@ -1129,9 +1129,8 @@
1129 -Erik Andersen, Nov 5, 1999 1129 -Erik Andersen, Nov 5, 1999
1130 1130
11310.32 11310.32
1132 * More changes -- many thanks to Lineo for paying me to work on 1132 * More changes -- If you have any problems please let me know ASAP at
1133 busybox. If you have any problems please let me know ASAP at 1133 andersee@debian.org
1134 andersen@lineo.com or andersee@debian.org
1135 * usage() now prints the BusyBox version. This will help folks 1134 * usage() now prints the BusyBox version. This will help folks
1136 realize that they are not in Kansas anymore. 1135 realize that they are not in Kansas anymore.
1137 * Fixed mkdir -m option so that it works. kill segfaulted w/o any 1136 * Fixed mkdir -m option so that it works. kill segfaulted w/o any
@@ -1142,11 +1141,11 @@
1142 * with full regular expressions!). Fixed a stupid seg-fault in sync 1141 * with full regular expressions!). Fixed a stupid seg-fault in sync
1143 * Fixed mount -- mount -a failed to parse and apply mount options Fixed 1142 * Fixed mount -- mount -a failed to parse and apply mount options Fixed
1144 * umount -n (patch thanks to Matthew Grant <grantma@anathoth.gen.nz>) 1143 * umount -n (patch thanks to Matthew Grant <grantma@anathoth.gen.nz>)
1145 * umount -a no longer umounts /proc Added BB_MTAB, allowing (at the 1144 * umount -a no longer umounts /proc Added CONFIG_MTAB, allowing (at the
1146 * cost of ~1.5k and the need for a rw /etc) 1145 * cost of ~1.5k and the need for a rw /etc)
1147 folks to use a real /etc/mtab file instead of a symlink to 1146 folks to use a real /etc/mtab file instead of a symlink to
1148 /proc/mounts. mount, and umount will add/remove entries and df 1147 /proc/mounts. mount, and umount will add/remove entries and df
1149 will now use /etc/mtab if BB_MTAB is defined. 1148 will now use /etc/mtab if CONFIG_MTAB is defined.
1150 * Fixed a nice bug in recursiveAction() which caused it to infinitely 1149 * Fixed a nice bug in recursiveAction() which caused it to infinitely
1151 hunt through /proc/../fd/* creating new file descriptors if it 1150 hunt through /proc/../fd/* creating new file descriptors if it
1152 followed the /dev/fd link over to /proc. recursiveAction() now 1151 followed the /dev/fd link over to /proc. recursiveAction() now
@@ -1173,10 +1172,9 @@
1173 -Erik Andersen, Oct 21, 1999 1172 -Erik Andersen, Oct 21, 1999
1174 1173
11750.30 11740.30
1176 Major changes -- lots of stuff rewritten. Many thanks to Lineo for 1175 Major changes -- lots of stuff rewritten. If you have any problems
1177 paying me to make these updates. If you have any problems with busybox, 1176 with busybox, or notice any bugs -- please let me know so I can fix
1178 or notice any bugs -- please let me know so I can fix it. These 1177 it. These changes include:
1179 changes include:
1180 1178
1181 Core Changes: 1179 Core Changes:
1182 * busybox can now invoke apps in two ways: via symlinks to the 1180 * busybox can now invoke apps in two ways: via symlinks to the
diff --git a/Config.h b/Config.h
deleted file mode 100644
index 73b0f91f8..000000000
--- a/Config.h
+++ /dev/null
@@ -1,494 +0,0 @@
1/* vi: set sw=4 ts=4: */
2// This file defines the feature set to be compiled into busybox.
3// When you turn things off here, they won't be compiled in at all.
4//
5//// This file is parsed by sed. You MUST use single line comments.
6// i.e., //#define BB_BLAH
7//
8//
9// BusyBox Applications
10//#define BB_ADDGROUP
11//#define BB_ADDUSER
12//#define BB_ADJTIMEX
13//#define BB_AR
14//#define BB_ASH
15#define BB_BASENAME
16//#define BB_BUNZIP2
17#define BB_CAT
18#define BB_CHGRP
19#define BB_CHMOD
20#define BB_CHOWN
21#define BB_CHROOT
22#define BB_CHVT
23#define BB_CLEAR
24//#define BB_CMP
25#define BB_CP
26//#define BB_CPIO
27#define BB_CUT
28#define BB_DATE
29//#define BB_DC
30#define BB_DD
31//#define BB_DEALLOCVT
32//#define BB_DELGROUP
33//#define BB_DELUSER
34#define BB_DF
35#define BB_DIRNAME
36#define BB_DMESG
37//#define BB_DOS2UNIX
38//#define BB_DPKG
39//#define BB_DPKG_DEB
40//#define BB_DUTMP
41#define BB_DU
42//#define BB_DUMPKMAP
43#define BB_ECHO
44#define BB_ENV
45//#define BB_EXPR
46//#define BB_FBSET
47//#define BB_FDFLUSH
48#define BB_FIND
49#define BB_FREE
50//#define BB_FREERAMDISK
51//#define BB_FSCK_MINIX
52//#define BB_GETOPT
53//#define BB_GETTY
54#define BB_GREP
55#define BB_GUNZIP
56#define BB_GZIP
57#define BB_HALT
58#define BB_HEAD
59//#define BB_HOSTID
60//#define BB_HOSTNAME
61//#define BB_HUSH
62#define BB_ID
63//#define BB_IFCONFIG
64#define BB_INIT
65//#define BB_INSMOD
66#define BB_KILL
67#define BB_KILLALL
68#define BB_KLOGD
69//#define BB_LASH
70//#define BB_LENGTH
71#define BB_LN
72//#define BB_LOADACM
73//#define BB_LOADFONT
74//#define BB_LOADKMAP
75#define BB_LOGGER
76//#define BB_LOGNAME
77#define BB_LS
78#define BB_LSMOD
79//#define BB_MAKEDEVS
80//#define BB_MD5SUM
81#define BB_MKDIR
82//#define BB_MKFIFO
83//#define BB_MKFS_MINIX
84#define BB_MKNOD
85#define BB_MKSWAP
86//#define BB_MKTEMP
87#define BB_MODPROBE
88#define BB_MORE
89#define BB_MOUNT
90#define BB_MSH
91//#define BB_MT
92#define BB_MV
93//#define BB_NC
94//#define BB_NSLOOKUP
95#define BB_PIDOF
96//#define BB_PING
97//#define BB_PIVOT_ROOT
98#define BB_POWEROFF
99//#define BB_PRINTF
100#define BB_PS
101#define BB_PWD
102//#define BB_RDATE
103//#define BB_READLINK
104#define BB_REBOOT
105//#define BB_RENICE
106#define BB_RESET
107#define BB_RM
108#define BB_RMDIR
109//#define BB_RMMOD
110//#define BB_ROUTE
111//#define BB_RPM2CPIO
112#define BB_SED
113//#define BB_SETKEYCODES
114#define BB_SLEEP
115#define BB_SORT
116//#define BB_STTY
117//#define BB_START_STOP_DAEMON
118#define BB_SWAPONOFF
119#define BB_SYNC
120#define BB_SYSLOGD
121#define BB_TAIL
122#define BB_TAR
123//#define BB_TEE
124//#define BB_TEST
125//#define BB_TELNET
126//#define BB_TFTP
127#define BB_TOUCH
128//#define BB_TR
129//#define BB_TRACEROUTE
130#define BB_TRUE_FALSE
131#define BB_TTY
132//#define BB_UNIX2DOS
133//#define BB_UUENCODE
134//#define BB_UUDECODE
135#define BB_UMOUNT
136#define BB_UNIQ
137#define BB_UNAME
138//#define BB_UPDATE
139#define BB_UPTIME
140//#define BB_USLEEP
141//#define BB_VI
142//#define BB_WATCHDOG
143#define BB_WC
144//#define BB_WGET
145#define BB_WHICH
146#define BB_WHOAMI
147#define BB_XARGS
148#define BB_YES
149// End of Applications List
150//
151//
152//
153// ---------------------------------------------------------
154// This is where feature definitions go. Generally speaking,
155// turning this stuff off makes things a bit smaller (and less
156// pretty/useful).
157//
158//
159// If you enabled one or more of the shells, you may select which one
160// should be run when sh is invoked:
161//#define BB_FEATURE_SH_IS_ASH
162//#define BB_FEATURE_SH_IS_HUSH
163//#define BB_FEATURE_SH_IS_LASH
164#define BB_FEATURE_SH_IS_MSH
165//
166// BusyBox will, by default, malloc space for its buffers. This costs code
167// size for the call to xmalloc. You can use the following feature to have
168// them put on the stack. For some very small machines with limited stack
169// space, this can be deadly. For most folks, this works just fine...
170//#define BB_FEATURE_BUFFERS_GO_ON_STACK
171// The third alternative for buffer allocation is to use BSS. This works
172// beautifully for computers with a real MMU (and OS support), but wastes
173// runtime RAM for uCLinux. This behavior was the only one available for
174// BusyBox versions 0.48 and earlier.
175//#define BB_FEATURE_BUFFERS_GO_IN_BSS
176//
177// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
178// thereby eliminating the need for the /proc filesystem and thereby saving
179// lots and lots memory for more important things. NOTE: If you enable this
180// feature, you _must_ have patched the kernel to include the devps patch that
181// is included in the busybox/kernel-patches directory. You will also need to
182// create some device special files in /dev on your embedded system:
183// mknod /dev/mtab c 10 22
184// mknod /dev/ps c 10 21
185// I emailed Linus and this patch will not be going into the stock kernel.
186//#define BB_FEATURE_USE_DEVPS_PATCH
187//
188// show verbose usage messages
189//#define BB_FEATURE_VERBOSE_USAGE
190//
191// Use termios to manipulate the screen ('more' is prettier with this on)
192//#define BB_FEATURE_USE_TERMIOS
193//
194// calculate terminal & column widths (for more and ls)
195#define BB_FEATURE_AUTOWIDTH
196//
197// show username/groupnames for ls
198#define BB_FEATURE_LS_USERNAME
199//
200// show file timestamps in ls
201#define BB_FEATURE_LS_TIMESTAMPS
202//
203// enable ls -p and -F
204#define BB_FEATURE_LS_FILETYPES
205//
206// sort the file names
207#define BB_FEATURE_LS_SORTFILES
208//
209// enable ls -R
210#define BB_FEATURE_LS_RECURSIVE
211//
212// enable ls -L
213#define BB_FEATURE_LS_FOLLOWLINKS
214//
215// Disable for a smaller (but less functional) ping
216#define BB_FEATURE_FANCY_PING
217//
218// Make init use a simplified /etc/inittab file (recommended).
219#define BB_FEATURE_USE_INITTAB
220//
221//Enable init being called as /linuxrc
222#define BB_FEATURE_LINUXRC
223//
224//Have init enable core dumping for child processes (for debugging only)
225//#define BB_FEATURE_INIT_COREDUMPS
226//
227//Make sure nothing is printed to the console on boot
228//#define BB_FEATURE_EXTRA_QUIET
229//
230// enable syslogd -R remotehost
231#define BB_FEATURE_REMOTE_LOG
232//
233// enable syslogd -C
234//#define BB_FEATURE_IPC_SYSLOG
235//
236//Disable for a simple tail implementation (2.34k vs 3k for the full one).
237//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v.
238#define BB_FEATURE_FANCY_TAIL
239//
240// Enable support for loop devices in mount
241#define BB_FEATURE_MOUNT_LOOP
242//
243// Enable support for a real /etc/mtab file instead of /proc/mounts
244//#define BB_FEATURE_MTAB_SUPPORT
245//
246// Enable support for mounting remote NFS volumes.
247// You may need to mount with "-o nolock" if you are
248// not running a local portmapper daemon...
249//
250// If you are using uClibc, be sure that you've already compiled
251// uClibc with INCLUDE_RPC=true (contained in the Config file)
252//#define BB_FEATURE_NFSMOUNT
253//
254// Enable support forced filesystem unmounting
255// (i.e., in case of an unreachable NFS system).
256#define BB_FEATURE_MOUNT_FORCE
257//
258// Enable support for creation of tar files.
259#define BB_FEATURE_TAR_CREATE
260//
261// Enable support for "--exclude" and "-X" for excluding files
262#define BB_FEATURE_TAR_EXCLUDE
263//
264// Enable support for tar -z option (currently only works for inflating)
265#define BB_FEATURE_TAR_GZIP
266//
267// Enable reverse sort
268#define BB_FEATURE_SORT_REVERSE
269//
270// Enable uniqe sort
271#define BB_FEATURE_SORT_UNIQUE
272//
273// Enable command line editing in the shell.
274// Only relevant if a shell is enabled. On by default.
275#define BB_FEATURE_COMMAND_EDITING
276//
277// Enable tab completion in the shell. This is now working quite nicely.
278// This feature adds a bit over 4k. Only relevant if a shell is enabled.
279#define BB_FEATURE_COMMAND_TAB_COMPLETION
280//
281// Attempts to match usernames in a ~-prefixed path
282//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
283//
284//Allow the shell to invoke all the compiled in BusyBox applets as if they
285//were shell builtins. Nice for staticly linking an emergency rescue shell,
286//among other things. Off by default.
287// Only relevant if a shell is enabled.
288//#define BB_FEATURE_SH_STANDALONE_SHELL
289//
290//When this is enabled, busybox shell applets can be called using full path
291//names. This causes applets (i.e., most busybox commands) to override
292//real commands on the filesystem. For example, if you run run /bin/cat, it
293//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
294//busybox. Some systems want this, others do not. Choose wisely. :-) This
295//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled.
296// Only relevant if a shell is enabled. Off by default.
297//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN
298//
299// Uncomment this option for a fancy shell prompt that includes the
300// current username and hostname. On systems that don't have usernames
301// or hostnames, this can look hideous.
302// Only relevant if a shell is enabled.
303//#define BB_FEATURE_SH_FANCY_PROMPT
304//
305//Make interactive shells not print busybox messages
306//#define BB_FEATURE_SH_EXTRA_QUIET
307//
308//Turn on extra fbset options
309//#define BB_FEATURE_FBSET_FANCY
310//
311//Turn on fbset readmode support
312//#define BB_FEATURE_FBSET_READMODE
313//
314// Support insmod/lsmod/rmmod for post 2.1 kernels
315//#define BB_FEATURE_NEW_MODULE_INTERFACE
316//
317// Support insmod/lsmod/rmmod for pre 2.1 kernels
318//#define BB_FEATURE_OLD_MODULE_INTERFACE
319//
320// Support module version checking
321//#define BB_FEATURE_INSMOD_VERSION_CHECKING
322//
323// Support for uClinux memory usage optimization, which will load the image
324// directly into the kernel memory. This divides memory requrements by three.
325// If you are not running uClinux (i.e., your CPU has an MMU) leave this
326// disabled...
327//#define BB_FEATURE_INSMOD_LOADINKMEM
328//
329// Support for Minix filesystem, version 2
330//#define BB_FEATURE_MINIX2
331//
332// Enable ifconfig status reporting output -- this feature adds 7k.
333//#define BB_FEATURE_IFCONFIG_STATUS
334//
335// Enable ifconfig slip-specific options "keepalive" and "outfill"
336//#define BB_FEATURE_IFCONFIG_SLIP
337//
338// Enable ifconfig options "mem_start", "io_addr", and "irq".
339//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
340//
341// Enable ifconfig option "hw". Currently works for only with "ether".
342//#define BB_FEATURE_IFCONFIG_HW
343//
344// Allows "broadcast +" to set broadcast automatically based on hostaddr
345// and netmask, at a cost of about 100 bytes of code (i386).
346//#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS
347//
348// Enable busybox --install [-s]
349// to create links (or symlinks) for all the commands that are
350// compiled into the binary. (needs /proc filesystem)
351//#define BB_FEATURE_INSTALLER
352//
353// Enable a nifty progress meter in wget (adds just under 2k)
354#define BB_FEATURE_WGET_STATUSBAR
355//
356// Enable HTTP authentication in wget
357#define BB_FEATURE_WGET_AUTHENTICATION
358//
359// Clean up all memory before exiting -- usually not needed
360// as the OS can clean up... Don't enable this unless you
361// have a really good reason for cleaning things up manually.
362//#define BB_FEATURE_CLEAN_UP
363//
364// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
365#define BB_FEATURE_HUMAN_READABLE
366//
367// Support for the find -type option.
368#define BB_FEATURE_FIND_TYPE
369//
370// Support for the find -perm option.
371#define BB_FEATURE_FIND_PERM
372//
373// Support for the find -mtine option.
374#define BB_FEATURE_FIND_MTIME
375//
376// Support for the -A -B and -C context flags in grep
377//#define BB_FEATURE_GREP_CONTEXT
378//
379// Support for the EGREP applet (alias to the grep applet)
380//#define BB_FEATURE_GREP_EGREP_ALIAS
381//
382// Tell tftp what commands that should be supported.
383#define BB_FEATURE_TFTP_PUT
384#define BB_FEATURE_TFTP_GET
385//#define BB_FEATURE_TFTP_BLOCKSIZE
386//
387// features for vi
388#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode
389#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds
390#define BB_FEATURE_VI_SEARCH // search and replace cmds
391#define BB_FEATURE_VI_USE_SIGNALS // catch signals
392#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd
393#define BB_FEATURE_VI_READONLY // vi -R and "view" mode
394#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch
395#define BB_FEATURE_VI_SET // :set
396#define BB_FEATURE_VI_WIN_RESIZE // handle window resize
397//
398// Enable a if you system have setuped locale
399//#define BB_LOCALE_SUPPORT
400//
401// Support for TELNET to pass TERM type to remote host. Adds 384 bytes.
402#define BB_FEATURE_TELNET_TTYPE
403//
404// Support for devfs.
405//#define BB_FEATURE_DEVFS
406//
407// End of Features List
408//
409//
410//
411//
412//
413//
414//---------------------------------------------------
415// Nothing beyond this point should ever be touched by
416// mere mortals so leave this stuff alone.
417//
418#include <features.h>
419#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__
420 #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */
421 #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */
422 #undef BB_ASH /* Uses fork() */
423 #undef BB_HUSH /* Uses fork() */
424 #undef BB_LASH /* Uses fork() */
425 #undef BB_INIT /* Uses fork() */
426 #undef BB_FEATURE_TAR_GZIP /* Uses fork() */
427 #undef BB_SYSLOGD /* Uses daemon() */
428 #undef BB_KLOGD /* Uses daemon() */
429 #undef BB_UPDATE /* Uses daemon() */
430#endif
431#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH
432 #if defined BB_FEATURE_COMMAND_EDITING
433 #define BB_CMDEDIT
434 #else
435 #undef BB_FEATURE_COMMAND_EDITING
436 #undef BB_FEATURE_COMMAND_TAB_COMPLETION
437 #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
438 #undef BB_FEATURE_SH_FANCY_PROMPT
439 #endif
440#else
441 #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
442 #undef BB_FEATURE_SH_STANDALONE_SHELL
443 #undef BB_FEATURE_SH_FANCY_PROMPT
444#endif
445//
446#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST
447 #define BB_TEST
448#endif
449//
450#ifdef BB_KILLALL
451 #ifndef BB_KILL
452 #define BB_KILL
453 #endif
454#endif
455//
456#ifndef BB_INIT
457 #undef BB_FEATURE_LINUXRC
458#endif
459//
460#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
461 #define BB_NFSMOUNT
462#endif
463//
464#if defined BB_FEATURE_AUTOWIDTH
465 #ifndef BB_FEATURE_USE_TERMIOS
466 #define BB_FEATURE_USE_TERMIOS
467 #endif
468#endif
469//
470#if defined BB_INSMOD || defined BB_LSMOD
471 #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE
472 #define BB_FEATURE_NEW_MODULE_INTERFACE
473 #endif
474#endif
475//
476#ifdef BB_UNIX2DOS
477 #define BB_DOS2UNIX
478#endif
479//
480#ifdef BB_SYSLOGD
481 #if defined BB_FEATURE_IPC_SYSLOG
482 #define BB_LOGREAD
483 #endif
484#endif
485//
486#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH
487# define shell_main ash_main
488#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH
489# define shell_main hush_main
490#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH
491# define shell_main lash_main
492#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH
493# define shell_main msh_main
494#endif
diff --git a/LICENSE b/LICENSE
index 8e5a143d0..375ad2a00 100644
--- a/LICENSE
+++ b/LICENSE
@@ -17,15 +17,14 @@ Copyright 1998 Dave Cinege <dcinege@psychosis.com>
17mini-gzip(gzip), mini-netcat(mnc) 17mini-gzip(gzip), mini-netcat(mnc)
18Copyright 1998 Charles P. Wright <cpwright@villagenet.com> 18Copyright 1998 Charles P. Wright <cpwright@villagenet.com>
19 19
20Tons of new stuff as noted in header files 20Tons of new stuff as noted in header files
21Copyright (C) 1999,2000,2001 by Lineo, inc. and written by 21Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen and Erik Andersen
22Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 22Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
23
24 23
25 24
26Please feed suggestions, bug reports, insults, and bribes back to: 25Please feed suggestions, bug reports, insults, and bribes back to:
27 Erik Andersen 26 Erik Andersen
28 <andersen@lineo.com> 27 <andersen@codepoet.org>
29 <andersee@debian.org> 28 <andersee@debian.org>
30 29
31 30
diff --git a/Makefile b/Makefile
index 3cabc7afa..c8337801f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
1# Makefile for busybox 1# Makefile for busybox
2# 2#
3# Copyright (C) 1999,2000,2001 Erik Andersen <andersee@debian.org> 3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4# 4#
5# This program is free software; you can redistribute it and/or modify 5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by 6# it under the terms of the GNU General Public License as published by
@@ -20,12 +20,19 @@
20PROG := busybox 20PROG := busybox
21VERSION := 0.61.pre 21VERSION := 0.61.pre
22BUILDTIME := $(shell TZ=UTC date -u "+%Y.%m.%d-%H:%M%z") 22BUILDTIME := $(shell TZ=UTC date -u "+%Y.%m.%d-%H:%M%z")
23export VERSION 23TOPDIR := ${shell /bin/pwd}
24HOSTCC := gcc
25HOSTCFLAGS:= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
26
27
28# What OS are you compiling busybox for? This allows you to include
29# OS specific things, syscall overrides, etc.
30TARGET_OS := linux
24 31
25# With a modern GNU make(1) (highly recommended, that's what all the 32# With a modern GNU make(1) (highly recommended, that's what all the
26# developers use), all of the following configuration values can be 33# developers use), all of the following configuration values can be
27# overridden at the command line. For example: 34# overridden at the command line. For example:
28# make CROSS=powerpc-linux- BB_SRC_DIR=$HOME/busybox PREFIX=/mnt/app 35# make CROSS=powerpc-linux- CONFIG_SRC_DIR=$HOME/busybox PREFIX=/mnt/app
29 36
30# If you want to add some simple compiler switches (like -march=i686), 37# If you want to add some simple compiler switches (like -march=i686),
31# especially from the command line, use this instead of CFLAGS directly. 38# especially from the command line, use this instead of CFLAGS directly.
@@ -39,18 +46,6 @@ DOSTATIC = false
39# Leave this set to `false' for production use. 46# Leave this set to `false' for production use.
40DODEBUG = false 47DODEBUG = false
41 48
42# Setting this to `true' will cause busybox to directly use the system's
43# password and group functions. Assuming you use GNU libc, when this is
44# `true', you will need to install the /etc/nsswitch.conf configuration file
45# and the required libnss_* libraries. This generally makes your embedded
46# system quite a bit larger... If you leave this off, busybox will directly use
47# the /etc/password, /etc/group files (and your system will be smaller, and I
48# will get fewer emails asking about how glibc NSS works). Enabling this adds
49# just 1.4k to the binary size (which is a _lot_ less then glibc NSS costs).
50# Note that if you want hostname resolution to work with glibc, you still need
51# the libnss_* libraries.
52USE_SYSTEM_PWD_GRP = true
53
54# This enables compiling with dmalloc ( http://dmalloc.com/ ) 49# This enables compiling with dmalloc ( http://dmalloc.com/ )
55# which is an excellent public domain mem leak and malloc problem 50# which is an excellent public domain mem leak and malloc problem
56# detector. To enable dmalloc, before running busybox you will 51# detector. To enable dmalloc, before running busybox you will
@@ -72,17 +67,24 @@ DOEFENCE = false
72# larger than 2GB! 67# larger than 2GB!
73DOLFS = false 68DOLFS = false
74 69
75# If you have a "pristine" source directory, point BB_SRC_DIR to it. 70# If you have a "pristine" source directory, point CONFIG_SRC_DIR to it.
76# Experimental and incomplete; tell the mailing list 71# Experimental and incomplete; tell the mailing list
77# <busybox@opensource.lineo.com> if you do or don't like it so far. 72# <busybox@opensource.lineo.com> if you do or don't like it so far.
78BB_SRC_DIR = 73CONFIG_SRC_DIR =
79 74
80# If you are running a cross compiler, you may want to set this 75# If you are running a cross compiler, you may want to set CROSS
81# to something more interesting, like "powerpc-linux-". 76# to something more interesting, like "arm-linux-".
82CROSS = 77CROSS =
83CC = $(CROSS)gcc 78CC = $(CROSS)gcc
84AR = $(CROSS)ar 79AR = $(CROSS)ar
85STRIPTOOL = $(CROSS)strip 80AS = $(CROSS)as
81LD = $(CROSS)ld
82NM = $(CROSS)nm
83STRIP = $(CROSS)strip
84CPP = $(CC) -E
85MAKEFILES = $(TOPDIR)/.config
86export VERSION BUILDTIME TOPDIR HOSTCC HOSTCFLAGS CROSS CC AR AS LD NM STRIP CPP
87
86 88
87# To compile vs uClibc, just use the compiler wrapper built by uClibc... 89# To compile vs uClibc, just use the compiler wrapper built by uClibc...
88# Everything should compile and work as expected these days... 90# Everything should compile and work as expected these days...
@@ -107,10 +109,11 @@ STRIPTOOL = $(CROSS)strip
107#GCCINCDIR = $(shell gcc -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp") 109#GCCINCDIR = $(shell gcc -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp")
108 110
109# use '-Os' optimization if available, else use -O2 111# use '-Os' optimization if available, else use -O2
110OPTIMIZATION := $(shell if $(CC) -Os -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ 112OPTIMIZATION := ${shell if $(CC) -Os -S -o /dev/null -xc /dev/null \
111 then echo "-Os"; else echo "-O2" ; fi) 113 >/dev/null 2>&1; then echo "-Os"; else echo "-O2" ; fi}
112 114
113WARNINGS=-Wall -Wstrict-prototypes -Wshadow 115WARNINGS=-Wall -Wstrict-prototypes -Wshadow
116CFLAGS = -I $(TOPDIR)/include -I $(TOPDIR)/busybox
114ARFLAGS = -r 117ARFLAGS = -r
115 118
116# 119#
@@ -142,25 +145,14 @@ endif
142ifeq ($(strip $(DODEBUG)),true) 145ifeq ($(strip $(DODEBUG)),true)
143 CFLAGS += $(WARNINGS) -g -D_GNU_SOURCE 146 CFLAGS += $(WARNINGS) -g -D_GNU_SOURCE
144 LDFLAGS += -Wl,-warn-common 147 LDFLAGS += -Wl,-warn-common
145 STRIP = 148 STRIPCMD =
146else 149else
147 CFLAGS += $(WARNINGS) $(OPTIMIZATION) -fomit-frame-pointer -D_GNU_SOURCE 150 CFLAGS += $(WARNINGS) $(OPTIMIZATION) -fomit-frame-pointer -D_GNU_SOURCE
148 LDFLAGS += -s -Wl,-warn-common 151 LDFLAGS += -s -Wl,-warn-common
149 STRIP = $(STRIPTOOL) --remove-section=.note --remove-section=.comment $(PROG) 152 STRIPCMD = $(STRIP) --remove-section=.note --remove-section=.comment $(PROG)
150endif 153endif
151ifeq ($(strip $(DOSTATIC)),true) 154ifeq ($(strip $(DOSTATIC)),true)
152 LDFLAGS += --static 155 LDFLAGS += --static
153 #
154 #use '-ffunction-sections -fdata-sections' and '--gc-sections' (if they
155 # work) to try and strip out any unused junk. Doesn't do much for me,
156 # but you may want to give it a shot...
157 #
158 #ifeq ($(shell $(CC) -ffunction-sections -fdata-sections -S \
159 # -o /dev/null -xc /dev/null 2>/dev/null && $(LD) \
160 # --gc-sections -v >/dev/null && echo 1),1)
161 # CFLAGS += -ffunction-sections -fdata-sections
162 # LDFLAGS += --gc-sections
163 #endif
164endif 156endif
165 157
166ifndef $(PREFIX) 158ifndef $(PREFIX)
@@ -169,125 +161,77 @@ endif
169 161
170# Additional complications due to support for pristine source dir. 162# Additional complications due to support for pristine source dir.
171# Include files in the build directory should take precedence over 163# Include files in the build directory should take precedence over
172# the copy in BB_SRC_DIR, both during the compilation phase and the 164# the copy in CONFIG_SRC_DIR, both during the compilation phase and the
173# shell script that finds the list of object files. 165# shell script that finds the list of object files.
174# Work in progress by <ldoolitt@recycle.lbl.gov>. 166# Work in progress by <ldoolitt@recycle.lbl.gov>.
175# 167#
176ifneq ($(strip $(BB_SRC_DIR)),) 168ifneq ($(strip $(CONFIG_SRC_DIR)),)
177 VPATH = $(BB_SRC_DIR) 169 VPATH = $(CONFIG_SRC_DIR)
178endif 170endif
179#ifneq ($(strip $(VPATH)),)
180# CFLAGS += -I- -I. $(patsubst %,-I%,$(subst :, ,$(VPATH)))
181#endif
182
183# We need to set APPLET_SOURCES to something like
184# $(shell busybox.sh Config.h)
185# but in a manner that works with VPATH and BB_SRC_DIR.
186# Possible ways to approach this:
187#
188# 1. Explicitly search through .:$(VPATH) for busybox.sh and config.h,
189# then $(shell $(BUSYBOX_SH) $(CONFIG_H) $(BB_SRC_DIR))
190#
191# 2. Explicity search through .:$(VPATH) for slist.mk,
192# then $(shell $(MAKE) -f $(SLIST_MK) VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR))
193#
194# 3. Create slist.mk in this directory, with commands embedded in
195# a $(shell ...) command, and $(MAKE) it immediately.
196#
197# 4. Use a real rule within this makefile to create a file that sets
198# APPLET_SOURCE_LIST, then include that file. Has complications
199# with the first trip through the makefile (before processing the
200# include) trying to do too much, and a spurious warning the first
201# time make is run.
202#
203# This is option 3:
204#
205#APPLET_SOURCES = $(shell \
206# echo -e 'all: busybox.sh Config.h\n\t@ $$(SHELL) $$^ $$(BB_SRC_DIR)' >slist.mk; \
207# make -f slist.mk VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR) \
208#)
209# And option 4:
210-include applet_source_list
211 171
212OBJECTS = $(APPLET_SOURCES:.c=.o) busybox.o usage.o applets.o 172OBJECTS = $(APPLET_SOURCES:.c=.o) busybox.o usage.o applets.o
213CFLAGS += $(CROSS_CFLAGS) 173CFLAGS += $(CROSS_CFLAGS)
214CFLAGS += -DBB_VER='"$(VERSION)"' 174ifdef CONFIG_INIT_SCRIPT
215CFLAGS += -DBB_BT='"$(BUILDTIME)"' 175 CFLAGS += -DINIT_SCRIPT='"$(CONFIG_INIT_SCRIPT)"'
216ifdef BB_INIT_SCRIPT
217 CFLAGS += -DINIT_SCRIPT='"$(BB_INIT_SCRIPT)"'
218endif 176endif
219 177
220ifneq ($(strip $(USE_SYSTEM_PWD_GRP)),true) 178# Put user-supplied flags at the end, where they
221 PWD_GRP = pwd_grp 179# have a chance of winning.
222 PWD_GRP_DIR = $(BB_SRC_DIR:=/)$(PWD_GRP) 180CFLAGS += $(CFLAGS_EXTRA)
223 PWD_LIB = libpwd.a 181
224 PWD_CSRC=__getpwent.c pwent.c getpwnam.c getpwuid.c putpwent.c getpw.c \ 182.EXPORT_ALL_VARIABLES:
225 fgetpwent.c __getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c \ 183
226 initgroups.c setgroups.c 184all: do-it-all
227 PWD_OBJS=$(patsubst %.c,$(PWD_GRP)/%.o, $(PWD_CSRC)) 185
228ifneq ($(strip $(BB_SRC_DIR)),) 186#
229 PWD_CFLAGS = -I- -I. 187# Make "config" the default target if there is no configuration file or
230endif 188# "depend" the target if there is no top-level dependency information.
231 PWD_CFLAGS += -I$(PWD_GRP_DIR) 189ifeq (.config,$(wildcard .config))
190include .config
191ifeq (.depend,$(wildcard .depend))
192include .depend
193do-it-all: busybox busybox.links doc
232else 194else
233 CFLAGS += -DUSE_SYSTEM_PWD_GRP 195CONFIGURATION = depend
196do-it-all: depend
234endif 197endif
235
236LIBBB = libbb
237LIBBB_LIB = libbb.a
238LIBBB_CSRC= ask_confirmation.c chomp.c concat_path_file.c copy_file.c \
239copy_file_chunk.c libc5.c device_open.c error_msg.c \
240error_msg_and_die.c fgets_str.c find_mount_point.c find_pid_by_name.c \
241find_root_device.c full_read.c full_write.c get_console.c \
242get_last_path_component.c get_line_from_file.c gz_open.c human_readable.c \
243isdirectory.c kernel_version.c loop.c mode_string.c module_syscalls.c mtab.c \
244mtab_file.c my_getgrnam.c my_getgrgid.c my_getpwnam.c my_getpwnamegid.c \
245my_getpwuid.c parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \
246print_file.c process_escape_sequence.c read_package_field.c recursive_action.c \
247safe_read.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \
248trim.c unzip.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \
249xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \
250copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \
251dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \
252simplify_path.c
253LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC))
254ifeq ($(strip $(BB_SRC_DIR)),)
255 LIBBB_CFLAGS += -I$(LIBBB)
256else 198else
257 LIBBB_CFLAGS = -I- -I. -I./$(LIBBB) -I$(BB_SRC_DIR)/$(LIBBB) -I$(BB_SRC_DIR) 199CONFIGURATION = menuconfig
200do-it-all: menuconfig
258endif 201endif
259 202
260LIBBB_MSRC=libbb/messages.c 203SUBDIRS =applets archival console-tools editors fileutils findutils init \
261LIBBB_MESSAGES= full_version name_too_long omitting_directory not_a_directory \ 204 miscutils modutils networking pwd_grp shell shellutils sysklogd \
262memory_exhausted invalid_date invalid_option io_error dash_dash_help \ 205 textutils tinylogin util-linux libbb
263write_error too_few_args name_longer_than_foo unknown can_not_create_raw_socket
264LIBBB_MOBJ=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_MESSAGES))
265 206
266LIBBB_ARCSRC=libbb/unarchive.c 207bbsubdirs: $(patsubst %, _dir_%, $(SUBDIRS))
267LIBBB_ARCOBJ= archive_offset seek_sub_file extract_archive unarchive \
268get_header_ar get_header_cpio get_header_tar deb_extract
269LIBBB_AROBJS=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_ARCOBJ))
270 208
209$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/config/MARKER
210 $(MAKE) CFLAGS="$(CFLAGS)" -C $(patsubst _dir_%, %, $@)
271 211
272# Put user-supplied flags at the end, where they 212busybox: bbsubdirs
273# have a chance of winning. 213 $(CC) $(LDFLAGS) -o $@ $(shell find $(SUBDIRS) -name \*.a) $(LIBCONFIG_LIB) $(LIBRARIES)
274CFLAGS += $(CFLAGS_EXTRA) 214 $(STRIPCMD)
275 215
276.EXPORT_ALL_VARIABLES: 216busybox.links: applets/busybox.mkll
217 - $(SHELL) $^ >$@
218
219install: applets/install.sh busybox busybox.links
220 $(SHELL) $< $(PREFIX)
277 221
278all: applet_source_list busybox busybox.links doc 222install-hardlinks: applets/install.sh busybox busybox.links
223 $(SHELL) $< $(PREFIX) --hardlinks
279 224
280applet_source_list: busybox.sh Config.h
281 (echo -n "APPLET_SOURCES := "; CC="$(CC)" BB_SRC_DIR="$(BB_SRC_DIR)" $(SHELL) $^) > $@
282 225
226# Documentation Targets
283doc: olddoc 227doc: olddoc
284 228
285# Old Docs... 229# Old Docs...
286olddoc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html 230olddoc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html
287 231
288docs/busybox.pod : docs/busybox_header.pod usage.h docs/busybox_footer.pod 232docs/busybox.pod : docs/busybox_header.pod applets/usage.h docs/busybox_footer.pod
289 - ( cat docs/busybox_header.pod; \ 233 - ( cat docs/busybox_header.pod; \
290 docs/autodocifier.pl usage.h; \ 234 docs/autodocifier.pl applets/usage.h; \
291 cat docs/busybox_footer.pod ) > docs/busybox.pod 235 cat docs/busybox_footer.pod ) > docs/busybox.pod
292 236
293docs/BusyBox.txt: docs/busybox.pod 237docs/BusyBox.txt: docs/busybox.pod
@@ -340,86 +284,89 @@ docs/busybox/busyboxdocumentation.html: docs/busybox.sgml
340 - mkdir -p docs 284 - mkdir -p docs
341 (cd docs/busybox.lineo.com; sgmltools -b html ../busybox.sgml) 285 (cd docs/busybox.lineo.com; sgmltools -b html ../busybox.sgml)
342 286
287# The nifty new buildsystem stuff
288scripts/mkdep: scripts/mkdep.c
289 $(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c
343 290
344busybox: $(PWD_LIB) $(LIBBB_LIB) $(OBJECTS) 291scripts/split-include: scripts/split-include.c
345 $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBBB_LIB) $(PWD_LIB) $(LIBRARIES) 292 $(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c
346 $(STRIP)
347 293
348# Without VPATH, rule expands to "/bin/sh busybox.mkll Config.h applets.h" 294dep-files: scripts/mkdep #archdep
349# but with VPATH, some or all of those file names are resolved to the 295 rm -f .depend .hdepend
350# directories in which they live. 296 scripts/mkdep -I $(TOPDIR)/include -- `find $(TOPDIR) -name \*.c -print` >> .depend
351busybox.links: busybox.mkll Config.h applets.h 297 scripts/mkdep -I $(TOPDIR)/include -- `find $(TOPDIR) -name \*.h -print` >> .hdepend
352 - $(SHELL) $^ >$@ 298 $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
353 299
354nfsmount.o cmdedit.o: %.o: %.h 300depend dep: dep-files
355ash.o hush.o lash.o msh.o: cmdedit.h 301 @ echo -e "\n\nNow run 'make' to build BusyBox\n\n"
356$(OBJECTS): %.o: %.c Config.h busybox.h applets.h Makefile
357ifeq ($(strip $(BB_SRC_DIR)),)
358 $(CC) $(CFLAGS) -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o
359else
360 $(CC) $(CFLAGS) -I- -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o
361endif
362 302
363$(PWD_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile 303CONFIG_SHELL := ${shell if [ -x "$$BASH" ]; then echo $$BASH; \
364 - mkdir -p $(PWD_GRP) 304 else if [ -x /bin/bash ]; then echo /bin/bash; \
365 $(CC) $(CFLAGS) $(PWD_CFLAGS) -c $< -o $*.o 305 else echo sh; fi ; fi}
366 306
367$(LIBBB_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile libbb/libbb.h 307include/config/MARKER: scripts/split-include include/config.h
368 - mkdir -p $(LIBBB) 308 scripts/split-include include/config.h include/config
369 $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -c $< -o $*.o 309 @ touch include/config/MARKER
370 310
371$(LIBBB_MOBJ): $(LIBBB_MSRC) 311menuconfig:
372 - mkdir -p $(LIBBB) 312 $(MAKE) -C scripts/lxdialog all
373 $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o 313 $(CONFIG_SHELL) scripts/Menuconfig sysdeps/$(TARGET_OS)/config.in
374 314
375$(LIBBB_AROBJS): $(LIBBB_ARCSRC) 315config:
376 - mkdir -p $(LIBBB) 316 $(CONFIG_SHELL) scripts/Configure sysdeps/$(TARGET_OS)/config.in
377 $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o
378 317
379libpwd.a: $(PWD_OBJS) 318oldconfig:
380 $(AR) $(ARFLAGS) $@ $^ 319 $(CONFIG_SHELL) scripts/Configure -d sysdeps/$(TARGET_OS)/config.in
381 320
382libbb.a: $(LIBBB_MOBJ) $(LIBBB_AROBJS) $(LIBBB_OBJS)
383 $(AR) $(ARFLAGS) $@ $^
384 321
385usage.o: usage.h 322ifdef CONFIGURATION
323..$(CONFIGURATION):
324 @echo
325 @echo "You have a bad or nonexistent" .$(CONFIGURATION) ": running 'make" $(CONFIGURATION)"'"
326 @echo
327 $(MAKE) $(CONFIGURATION)
328 @echo
329 @echo "Successful. Try re-making (ignore the error that follows)"
330 @echo
331 exit 1
386 332
387libbb/loop.o: libbb/loop.h 333dummy:
388 334
389libbb/loop.h: mk_loop_h.sh 335else
390 @ $(SHELL) $< > $@
391 336
337dummy:
338
339endif
340
341include Rules.mak
342
343# Testing...
392test tests: 344test tests:
393 # old way of doing it 345 # old way of doing it
394 #cd tests && $(MAKE) all 346 #cd tests && $(MAKE) all
395 # new way of doing it 347 # new way of doing it
396 cd tests && ./tester.sh 348 cd tests && ./tester.sh
397 349
350# Cleanup
398clean: 351clean:
399 - cd tests && $(MAKE) clean 352 - $(MAKE) -C tests clean
353 - $(MAKE) -C scripts/lxdialog clean
400 - rm -f docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html \ 354 - rm -f docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html \
401 docs/busybox.lineo.com/BusyBox.html 355 docs/busybox.lineo.com/BusyBox.html
402 - rm -f docs/busybox.txt docs/busybox.dvi docs/busybox.ps \ 356 - rm -f docs/busybox.txt docs/busybox.dvi docs/busybox.ps \
403 docs/busybox.pdf docs/busybox.lineo.com/busybox.html 357 docs/busybox.pdf docs/busybox.lineo.com/busybox.html \
404 - rm -f multibuild.log Config.h.orig *.gdb *.elf 358 docs/busybox _install pod2htm* *.gdb *.elf *~ core
405 - rm -rf docs/busybox _install libpwd.a libbb.a pod2htm* 359 - rm -f busybox.links libbb/loop.h .config.old .hdepend
406 - rm -f busybox.links libbb/loop.h *~ slist.mk core applet_source_list 360 - rm -f scripts/split-include scripts/mkdep .*config.log
361 - rm -rf include/config include/config.h
362 - find -name .\*.flags -o -name .depend -exec rm -f {} \;
407 - find -name \*.o -exec rm -f {} \; 363 - find -name \*.o -exec rm -f {} \;
364 - find -name \*.a -exec rm -f {} \;
408 365
409distclean: clean 366distclean: clean
410 - rm -f busybox applet_source_list 367 - rm -f busybox
411 - cd tests && $(MAKE) distclean 368 - cd tests && $(MAKE) distclean
412 369
413install: install.sh busybox busybox.links
414 $(SHELL) $< $(PREFIX)
415
416install-hardlinks: install.sh busybox busybox.links
417 $(SHELL) $< $(PREFIX) --hardlinks
418
419debug_pristine:
420 @ echo VPATH=\"$(VPATH)\"
421 @ echo OBJECTS=\"$(OBJECTS)\"
422
423dist release: distclean doc 370dist release: distclean doc
424 cd ..; \ 371 cd ..; \
425 rm -rf busybox-$(VERSION); \ 372 rm -rf busybox-$(VERSION); \
@@ -437,6 +384,8 @@ dist release: distclean doc
437 \ 384 \
438 tar -cvzf busybox-$(VERSION).tar.gz busybox-$(VERSION)/; 385 tar -cvzf busybox-$(VERSION).tar.gz busybox-$(VERSION)/;
439 386
387
388
440.PHONY: tags 389.PHONY: tags
441tags: 390tags:
442 ctags -R . 391 ctags -R .
diff --git a/README b/README
index b45ef57f4..4fbc76380 100644
--- a/README
+++ b/README
@@ -82,7 +82,7 @@ top of ash.c as well, so check those out if you want to tweak things.
82Getting help: 82Getting help:
83 83
84When you find you need help, you can check out the BusyBox mailing list 84When you find you need help, you can check out the BusyBox mailing list
85archives at http://opensource.lineo.com/lists/busybox/ or even join 85archives at http://oss.lineo.com/lists/busybox/ or even join
86the mailing list if you are interested. 86the mailing list if you are interested.
87 87
88---------------- 88----------------
@@ -130,23 +130,18 @@ Source for the latest released version can always be downloaded from
130CVS: 130CVS:
131 131
132BusyBox now has its own publicly browsable CVS tree at: 132BusyBox now has its own publicly browsable CVS tree at:
133 http://opensource.lineo.com/cgi-bin/cvsweb/busybox/ 133 http://oss.lineo.com/cgi-bin/cvsweb/busybox/
134 134
135Anonymous CVS access is available. For instructions, check out: 135Anonymous CVS access is available. For instructions, check out:
136 http://opensource.lineo.com/cvs_anon.html 136 http://oss.lineo.com/cvs_anon.html
137 137
138For those that are actively contributing there is even CVS write access: 138For those that are actively contributing there is even CVS write access:
139 http://opensource.lineo.com/cvs_write.html 139 http://oss.lineo.com/cvs_write.html
140 140
141---------------- 141----------------
142 142
143Please feed suggestions, bug reports, insults, and bribes back to: 143Please feed suggestions, bug reports, insults, and bribes back to:
144 Erik Andersen 144 Erik Andersen
145 <andersen@lineo.com> 145 <andersen@codepoet.org>
146 <andersee@debian.org> 146 <andersee@debian.org>
147 <andersee@codepoet.org>
148
149<blatant plug>
150Many thanks to go to Lineo for paying me to work on busybox.
151</blatant plug>
152 147
diff --git a/addgroup.c b/addgroup.c
deleted file mode 100644
index 3d932011c..000000000
--- a/addgroup.c
+++ /dev/null
@@ -1,178 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * addgroup - add users to /etc/passwd and /etc/shadow
4 *
5 *
6 * Copyright (C) 1999 by Lineo, inc.
7 * Written by John Beppu <beppu@lineo.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <errno.h>
26#include <fcntl.h>
27#include <stdarg.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <sys/param.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34#include <unistd.h>
35#include "busybox.h"
36#include "pwd_grp/pwd.h"
37#include "pwd_grp/grp.h"
38
39#define GROUP_FILE "/etc/group"
40#define SHADOW_FILE "/etc/gshadow"
41
42
43/* structs __________________________ */
44
45/* data _____________________________ */
46
47/* defaults : should this be in an external file? */
48static char *default_passwd = "x";
49
50
51/* make sure gr_name isn't taken, make sure gid is kosher
52 * return 1 on failure */
53static int group_study(const char *filename, struct group *g)
54{
55 FILE *etc_group;
56 gid_t desired;
57
58 struct group *grp;
59 const int max = 65000;
60
61 /* FIXME : make an fopen_wrapper */
62 etc_group = fopen(filename, "r");
63 if (!etc_group) {
64 perror_msg_and_die("%s", filename);
65 }
66
67 /* make sure gr_name isn't taken, make sure gid is kosher */
68 desired = g->gr_gid;
69 while ((grp = fgetgrent(etc_group))) {
70 if ((strcmp(grp->gr_name, g->gr_name)) == 0) {
71 error_msg_and_die("%s: group already in use\n", g->gr_name);
72 }
73 if ((desired) && grp->gr_gid == desired) {
74 error_msg_and_die("%d: gid has already been allocated\n",
75 desired);
76 }
77 if ((grp->gr_gid > g->gr_gid) && (grp->gr_gid < max)) {
78 g->gr_gid = grp->gr_gid;
79 }
80 }
81 fclose(etc_group);
82
83 /* gid */
84 if (desired) {
85 g->gr_gid = desired;
86 } else {
87 g->gr_gid++;
88 }
89 /* return 1; */
90 return 0;
91}
92
93/* append a new user to the passwd file */
94static int addgroup(const char *filename, char *group, gid_t gid)
95{
96 FILE *etc_group;
97 FILE *etc_gshadow;
98 char *gshadow = SHADOW_FILE;
99
100 struct group gr;
101
102 /* group:passwd:gid:userlist */
103 const char *entryfmt = "%s:%s:%d:%s\n";
104
105 /* make sure gid and group haven't already been allocated */
106 gr.gr_gid = gid;
107 gr.gr_name = group;
108 if (group_study(filename, &gr))
109 return 1;
110
111 /* add entry to group */
112 etc_group = fopen(filename, "a");
113 if (!etc_group) {
114 perror_msg_and_die("%s", filename);
115 }
116 fprintf(etc_group, entryfmt, group, default_passwd, gr.gr_gid, "");
117 fclose(etc_group);
118
119 /* add entry to gshadow if necessary */
120 if (access(gshadow, F_OK|W_OK) == 0) {
121 etc_gshadow = xfopen(gshadow, "a");
122 fprintf(etc_gshadow, "%s:!::\n", group);
123 fclose(etc_gshadow);
124 }
125
126 /* return 1; */
127 return 0;
128}
129
130/*
131 * addgroup will take a login_name as its first parameter.
132 *
133 * gid
134 *
135 * can be customized via command-line parameters.
136 * ________________________________________________________________________ */
137int addgroup_main(int argc, char **argv)
138{
139 int i;
140 char opt;
141 char *group;
142 gid_t gid = 0;
143
144 /* get remaining args */
145 for (i = 1; i < argc; i++) {
146 if (argv[i][0] == '-') {
147 opt = argv[i][1];
148 switch (opt) {
149 case 'h':
150 show_usage();
151 break;
152 case 'g':
153 gid = strtol(argv[++i], NULL, 10);
154 break;
155 default:
156 error_msg_and_die("addgroup: invalid option -- %c\n", opt);
157 }
158 } else {
159 break;
160 }
161 }
162
163 if (i >= argc) {
164 show_usage();
165 } else {
166 group = argv[i];
167 }
168
169 if (geteuid() != 0) {
170 error_msg_and_die
171 ("addgroup: Only root may add a group to the system.\n");
172 }
173
174 /* werk */
175 return addgroup(GROUP_FILE, group, gid);
176}
177
178/* $Id: addgroup.c,v 1.1 2001/08/21 16:18:59 andersen Exp $ */
diff --git a/adduser.c b/adduser.c
deleted file mode 100644
index 6bd2c253e..000000000
--- a/adduser.c
+++ /dev/null
@@ -1,366 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * adduser - add users to /etc/passwd and /etc/shadow
4 *
5 *
6 * Copyright (C) 1999 by Lineo, inc.
7 * Written by John Beppu <beppu@lineo.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <errno.h>
26#include <fcntl.h>
27#include <stdarg.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <shadow.h>
32#include <time.h>
33#include <unistd.h>
34#include <sys/param.h>
35#include <sys/stat.h>
36#include <sys/types.h>
37#include "busybox.h"
38#include "pwd_grp/pwd.h"
39#include "pwd_grp/grp.h"
40
41#define PASSWD_FILE "/etc/passwd"
42#define SHADOW_FILE "/etc/gshadow"
43
44#if 0
45# define PASSWD_FILE "passwd"
46# define SHADOW_FILE "shadow"
47#endif
48
49/* structs __________________________ */
50
51typedef struct {
52 uid_t u;
53 gid_t g;
54} Id;
55
56/* data _____________________________ */
57
58/* defaults : should this be in an external file? */
59static char *default_passwd = "x";
60static char *default_gecos = "Embedix User,,,";
61static char *default_home_prefix = "/home";
62static char *default_shell = "/bin/sh";
63
64/* shadow in use? */
65static int shadow_enabled = 0;
66
67/* I was doing this all over the place */
68static FILE *fopen_wrapper(const char *filename, const char *mode)
69{
70 FILE *f;
71
72 f = fopen(filename, mode);
73 if (f == NULL) {
74 fprintf(stderr, "adduser: %s: %s\n", filename, strerror(errno));
75 }
76 return f;
77}
78
79/* remix */
80/* EDR recoded such that the uid may be passed in *p */
81static int passwd_study(const char *filename, struct passwd *p)
82{
83 struct passwd *pw;
84 FILE *passwd;
85
86 const int min = 500;
87 const int max = 65000;
88
89 passwd = fopen_wrapper(filename, "r");
90 if (!passwd)
91 return 4;
92
93 /* EDR if uid is out of bounds, set to min */
94 if ((p->pw_uid > max) || (p->pw_uid < min))
95 p->pw_uid = min;
96
97 /* stuff to do:
98 * make sure login isn't taken;
99 * find free uid and gid;
100 */
101 while ((pw = fgetpwent(passwd))) {
102 if (strcmp(pw->pw_name, p->pw_name) == 0) {
103 /* return 0; */
104 return 1;
105 }
106 if ((pw->pw_uid >= p->pw_uid) && (pw->pw_uid < max)
107 && (pw->pw_uid >= min)) {
108 p->pw_uid = pw->pw_uid + 1;
109 }
110 }
111
112 /* EDR check for an already existing gid */
113 while (getgrgid(p->pw_uid) != NULL)
114 p->pw_uid++;
115
116 /* EDR also check for an existing group definition */
117 if (getgrnam(p->pw_name) != NULL)
118 return 3;
119
120 /* EDR bounds check */
121 if ((p->pw_uid > max) || (p->pw_uid < min))
122 return 2;
123
124 /* EDR create new gid always = uid */
125 p->pw_gid = p->pw_uid;
126
127 /* return 1; */
128 return 0;
129}
130
131static void addgroup_wrapper(const char *login, gid_t gid)
132{
133 int argc = 4;
134 char *argv[] = { "addgroup", "-g", NULL, NULL };
135 char group_id[8];
136 char group_name[32];
137
138 strncpy(group_name, login, 32);
139 argv[3] = group_name;
140 sprintf(group_id, "%d", gid);
141 argv[2] = group_id;
142 addgroup_main(argc, argv);
143}
144
145static void passwd_wrapper(const char *login)
146{
147 char *prog = "passwd";
148 execlp(prog, prog, login, NULL);
149 error_msg_and_die("Failed to execute 'passwd', you must set the password for '%s' manually\n", login);
150}
151
152/*
153 * pwd_to_spwd - create entries for new spwd structure
154 *
155 * pwd_to_spwd() creates a new (struct spwd) containing the
156 * information in the pointed-to (struct passwd).
157 */
158#define DAY (24L*3600L)
159#define WEEK (7*DAY)
160#define SCALE DAY
161static struct spwd *pwd_to_spwd(const struct passwd *pw)
162{
163 static struct spwd sp;
164
165 /*
166 * Nice, easy parts first. The name and passwd map directly
167 * from the old password structure to the new one.
168 */
169 sp.sp_namp = pw->pw_name;
170 sp.sp_pwdp = pw->pw_passwd;
171
172 /*
173 * Defaults used if there is no pw_age information.
174 */
175 sp.sp_min = 0;
176 sp.sp_max = (10000L * DAY) / SCALE;
177 sp.sp_lstchg = time((time_t *) 0) / SCALE;
178
179 /*
180 * These fields have no corresponding information in the password
181 * file. They are set to uninitialized values.
182 */
183 sp.sp_warn = -1;
184 sp.sp_expire = -1;
185 sp.sp_inact = -1;
186 sp.sp_flag = -1;
187
188 return &sp;
189}
190
191/* putpwent(3) remix */
192static int adduser(const char *filename, struct passwd *p)
193{
194 FILE *passwd;
195 int r;
196 FILE *shadow;
197 struct spwd *sp;
198
199 /* make sure everything is kosher and setup uid && gid */
200 passwd = fopen_wrapper(filename, "a");
201 if (passwd == NULL) {
202 /* return -1; */
203 return 1;
204 }
205 fseek(passwd, 0, SEEK_END);
206
207 /* if (passwd_study(filename, p) == 0) { */
208 r = passwd_study(filename, p);
209 if (r) {
210 if (r == 1)
211 error_msg("%s: login already in use\n", p->pw_name);
212 else if (r == 2)
213 error_msg("illegal uid or no uids left\n");
214 else if (r == 3)
215 error_msg("group name %s already in use\n", p->pw_name);
216 else
217 error_msg("generic error.\n");
218 /* return -1; */
219 return 1;
220 }
221
222 /* add to passwd */
223 if (putpwent(p, passwd) == -1) {
224 /* return -1; */
225 return 1;
226 }
227 fclose(passwd);
228
229 /* add to shadow if necessary */
230 if (shadow_enabled) {
231 shadow = fopen_wrapper(SHADOW_FILE, "a");
232 if (shadow == NULL) {
233 /* return -1; */
234 return 1;
235 }
236 fseek(shadow, 0, SEEK_END);
237 sp = pwd_to_spwd(p);
238 sp->sp_max = 99999; /* debianish */
239 sp->sp_warn = 7;
240 fprintf(shadow, "%s:!:%ld:%ld:%ld:%ld:::\n",
241 sp->sp_namp, sp->sp_lstchg, sp->sp_min, sp->sp_max,
242 sp->sp_warn);
243 fclose(shadow);
244 }
245
246 /* add to group */
247 /* addgroup should be responsible for dealing w/ gshadow */
248 addgroup_wrapper(p->pw_name, p->pw_gid);
249
250 /* Clear the umask for this process so it doesn't
251 * * screw up the permissions on the mkdir and chown. */
252 umask(0);
253
254 /* mkdir */
255 if (mkdir(p->pw_dir, 0755)) {
256 perror_msg("%s", p->pw_dir);
257 }
258 /* Set the owner and group so it is owned by the new user. */
259 if (chown(p->pw_dir, p->pw_uid, p->pw_gid)) {
260 perror_msg("%s", p->pw_dir);
261 }
262 /* Now fix up the permissions to 2755. Can't do it before now
263 * since chown will clear the setgid bit */
264 if (chmod(p->pw_dir, 02755)) {
265 perror_msg("%s", p->pw_dir);
266 }
267 /* interactively set passwd */
268 passwd_wrapper(p->pw_name);
269
270 return 0;
271}
272
273
274/* return current uid (root is always uid == 0, right?) */
275static uid_t i_am_not_root()
276{
277 return geteuid();
278}
279
280/*
281 * adduser will take a login_name as its first parameter.
282 *
283 * home
284 * shell
285 * gecos
286 *
287 * can be customized via command-line parameters.
288 * ________________________________________________________________________ */
289int adduser_main(int argc, char **argv)
290{
291 int i;
292 char opt;
293 char *login;
294 char *gecos;
295 char *home = NULL;
296 char *shell;
297 char path[MAXPATHLEN];
298
299 struct passwd pw;
300
301 /* init */
302 if (argc < 2) {
303 show_usage();
304 }
305 gecos = default_gecos;
306 shell = default_shell;
307
308 /* get args */
309 for (i = 1; i < argc; i++) {
310 if (argv[i][0] == '-') {
311 opt = argv[i][1];
312 switch (opt) {
313 case 'h':
314 home = argv[++i];
315 break;
316 case 'g':
317 gecos = argv[++i];
318 break;
319 case 's':
320 shell = argv[++i];
321 break;
322 default:
323 error_msg("invalid option -- %c\n", opt);
324 break;
325 }
326 } else {
327 break;
328 }
329 }
330
331 /* got root? */
332 if (i_am_not_root()) {
333 error_msg_and_die( "Only root may add a user or group to the system.\n");
334 }
335
336 /* get login */
337 if (i >= argc) {
338 error_msg_and_die( "adduser: no user specified\n");
339 }
340 login = argv[i];
341
342 /* create string for $HOME if not specified already */
343 if (!home) {
344 snprintf(path, MAXPATHLEN, "%s/%s", default_home_prefix, login);
345 path[MAXPATHLEN - 1] = 0;
346 home = path;
347 }
348 /* is /etc/shadow in use? */
349 shadow_enabled = (0 == access(SHADOW_FILE, F_OK));
350
351 /* create a passwd struct */
352 pw.pw_name = login;
353 pw.pw_passwd = default_passwd;
354 pw.pw_uid = 0;
355 pw.pw_gid = 0;
356 pw.pw_gecos = gecos;
357 pw.pw_dir = home;
358 pw.pw_shell = shell;
359
360 /* grand finale */
361 i = adduser(PASSWD_FILE, &pw);
362
363 return (i);
364}
365
366/* $Id: adduser.c,v 1.1 2001/08/21 16:18:59 andersen Exp $ */
diff --git a/adjtimex.c b/adjtimex.c
deleted file mode 100644
index e3c160d87..000000000
--- a/adjtimex.c
+++ /dev/null
@@ -1,176 +0,0 @@
1/*
2 * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables.
3 *
4 * Originally written: October 1997
5 * Last hack: March 2001
6 * Copyright 1997, 2000, 2001 Larry Doolittle <LRDoolittle@lbl.gov>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License (Version 2,
10 * June 1991) as published by the Free Software Foundation. At the
11 * time of writing, that license was published by the FSF with the URL
12 * http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by
13 * reference.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * This adjtimex(1) is very similar in intent to adjtimex(8) by Steven
21 * Dick <ssd@nevets.oau.org> and Jim Van Zandt <jrv@vanzandt.mv.com>
22 * (see http://metalab.unc.edu/pub/Linux/system/admin/time/adjtimex*).
23 * That version predates this one, and is _much_ bigger and more
24 * featureful. My independently written version was very similar to
25 * Steven's from the start, because they both follow the kernel timex
26 * structure. I further tweaked this version to be equivalent to Steven's
27 * where possible, but I don't like getopt_long, so the actual usage
28 * syntax is incompatible.
29 *
30 * Amazingly enough, my Red Hat 5.2 sys/timex (and sub-includes)
31 * don't actually give a prototype for adjtimex(2), so building
32 * this code (with -Wall) gives a warning. Later versions of
33 * glibc fix this issue.
34 *
35 * This program is too simple for a Makefile, just build with:
36 * gcc -Wall -O adjtimex.c -o adjtimex
37 *
38 * busyboxed 20 March 2001, Larry Doolittle <ldoolitt@recycle.lbl.gov>
39 * It will autosense if it is built in a busybox environment, based
40 * on the BB_VER preprocessor macro.
41 */
42
43#include <stdio.h>
44#include <sys/types.h>
45#include <stdlib.h>
46#include <unistd.h>
47
48#if __GNU_LIBRARY__ < 5
49#include <sys/timex.h>
50extern int adjtimex(struct timex *buf);
51#else
52#include <sys/timex.h>
53#endif
54
55#ifdef BB_VER
56#include "busybox.h"
57#endif
58
59static struct {int bit; char *name;} statlist[] = {
60 { STA_PLL, "PLL" },
61 { STA_PPSFREQ, "PPSFREQ" },
62 { STA_PPSTIME, "PPSTIME" },
63 { STA_FLL, "FFL" },
64 { STA_INS, "INS" },
65 { STA_DEL, "DEL" },
66 { STA_UNSYNC, "UNSYNC" },
67 { STA_FREQHOLD, "FREQHOLD" },
68 { STA_PPSSIGNAL, "PPSSIGNAL" },
69 { STA_PPSJITTER, "PPSJITTER" },
70 { STA_PPSWANDER, "PPSWANDER" },
71 { STA_PPSERROR, "PPSERROR" },
72 { STA_CLOCKERR, "CLOCKERR" },
73 { 0, NULL } };
74
75static char *ret_code_descript[] = {
76 "clock synchronized",
77 "insert leap second",
78 "delete leap second",
79 "leap second in progress",
80 "leap second has occurred",
81 "clock not synchronized" };
82
83#ifdef BB_VER
84#define main adjtimex_main
85#else
86void usage(char *prog)
87{
88 fprintf(stderr,
89 "Usage: %s [ -q ] [ -o offset ] [ -f frequency ] [ -p timeconstant ] [ -t tick ]\n",
90 prog);
91}
92#define show_usage() usage(argv[0])
93#endif
94
95int main(int argc, char ** argv)
96{
97 struct timex txc;
98 int quiet=0;
99 int c, i, ret, sep;
100 char *descript;
101 txc.modes=0;
102 for (;;) {
103 c = getopt( argc, argv, "qo:f:p:t:");
104 if (c == EOF) break;
105 switch (c) {
106 case 'q':
107 quiet=1;
108 break;
109 case 'o':
110 txc.offset = atoi(optarg);
111 txc.modes |= ADJ_OFFSET_SINGLESHOT;
112 break;
113 case 'f':
114 txc.freq = atoi(optarg);
115 txc.modes |= ADJ_FREQUENCY;
116 break;
117 case 'p':
118 txc.constant = atoi(optarg);
119 txc.modes |= ADJ_TIMECONST;
120 break;
121 case 't':
122 txc.tick = atoi(optarg);
123 txc.modes |= ADJ_TICK;
124 break;
125 default:
126 show_usage();
127 exit(1);
128 }
129 }
130 if (argc != optind) { /* no valid non-option parameters */
131 show_usage();
132 exit(1);
133 }
134
135 ret = adjtimex(&txc);
136
137 if (ret < 0) perror("adjtimex");
138
139 if (!quiet && ret>=0) {
140 printf(
141 " mode: %d\n"
142 "-o offset: %ld\n"
143 "-f frequency: %ld\n"
144 " maxerror: %ld\n"
145 " esterror: %ld\n"
146 " status: %d ( ",
147 txc.modes, txc.offset, txc.freq, txc.maxerror,
148 txc.esterror, txc.status);
149
150 /* representative output of next code fragment:
151 "PLL | PPSTIME" */
152 sep=0;
153 for (i=0; statlist[i].name; i++) {
154 if (txc.status & statlist[i].bit) {
155 if (sep) fputs(" | ",stdout);
156 fputs(statlist[i].name,stdout);
157 sep=1;
158 }
159 }
160
161 descript = "error";
162 if (ret >= 0 && ret <= 5) descript = ret_code_descript[ret];
163 printf(" )\n"
164 "-p timeconstant: %ld\n"
165 " precision: %ld\n"
166 " tolerance: %ld\n"
167 "-t tick: %ld\n"
168 " time.tv_sec: %ld\n"
169 " time.tv_usec: %ld\n"
170 " return value: %d (%s)\n",
171 txc.constant,
172 txc.precision, txc.tolerance, txc.tick,
173 (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript);
174 }
175 return (ret<0);
176}
diff --git a/applets.c b/applets.c
deleted file mode 100644
index f3e56a9f3..000000000
--- a/applets.c
+++ /dev/null
@@ -1,116 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include "busybox.h"
32
33#undef APPLET
34#undef APPLET_NOUSAGE
35#undef PROTOTYPES
36#include "applets.h"
37
38struct BB_applet *applet_using;
39
40/* The -1 arises because of the {0,NULL,0,-1} entry above. */
41const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1);
42
43extern void show_usage(void)
44{
45 const char *format_string;
46 const char *usage_string = usage_messages;
47 int i;
48
49 for (i = applet_using - applets; i > 0; ) {
50 if (!*usage_string++) {
51 --i;
52 }
53 }
54 format_string = "%s\n\nUsage: %s %s\n\n";
55 if(*usage_string == 0)
56 format_string = "%s\n\nNo help available.\n\n";
57 fprintf(stderr, format_string,
58 full_version, applet_using->name, usage_string);
59 exit(EXIT_FAILURE);
60}
61
62static int applet_name_compare(const void *x, const void *y)
63{
64 const char *name = x;
65 const struct BB_applet *applet = y;
66
67 return strcmp(name, applet->name);
68}
69
70extern const size_t NUM_APPLETS;
71
72struct BB_applet *find_applet_by_name(const char *name)
73{
74 return bsearch(name, applets, NUM_APPLETS, sizeof(struct BB_applet),
75 applet_name_compare);
76}
77
78void run_applet_by_name(const char *name, int argc, char **argv)
79{
80 static int recurse_level = 0;
81 extern int been_there_done_that; /* From busybox.c */
82
83 recurse_level++;
84 /* Do a binary search to find the applet entry given the name. */
85 if ((applet_using = find_applet_by_name(name)) != NULL) {
86 applet_name = applet_using->name;
87 if (argv[1] && strcmp(argv[1], "--help") == 0) {
88 if (strcmp(applet_using->name, "busybox")==0) {
89 if(argv[2])
90 applet_using = find_applet_by_name(argv[2]);
91 else
92 applet_using = NULL;
93 }
94 if(applet_using)
95 show_usage();
96 been_there_done_that=1;
97 busybox_main(0, NULL);
98 }
99 exit((*(applet_using->main)) (argc, argv));
100 }
101 /* Just in case they have renamed busybox - Check argv[1] */
102 if (recurse_level == 1) {
103 run_applet_by_name("busybox", argc, argv);
104 }
105 recurse_level--;
106}
107
108
109/* END CODE */
110/*
111Local Variables:
112c-file-style: "linux"
113c-basic-offset: 4
114tab-width: 4
115End:
116*/
diff --git a/applets.h b/applets.h
deleted file mode 100644
index 5ecfe3cba..000000000
--- a/applets.h
+++ /dev/null
@@ -1,500 +0,0 @@
1/*
2 * applets.h - a listing of all busybox applets.
3 *
4 * If you write a new applet, you need to add an entry to this list to make
5 * busybox aware of it.
6 *
7 * It is CRUCIAL that this listing be kept in ascii order, otherwise the binary
8 * search lookup contributed by Gaute B Strokkenes stops working. If you value
9 * your kneecaps, you'll be sure to *make sure* that any changes made to this
10 * file result in the listing remaining in ascii order. You have been warned.
11 */
12
13#undef APPLET
14#undef APPLET_ODDNAME
15#undef APPLET_NOUSAGE
16
17
18#if defined(PROTOTYPES)
19 #define APPLET(a,b,c) extern int b(int argc, char **argv);
20 #define APPLET_NOUSAGE(a,b,c) extern int b(int argc, char **argv);
21 #define APPLET_ODDNAME(a,b,c,d) extern int b(int argc, char **argv);
22 extern const char usage_messages[];
23#elif defined(MAKE_USAGE)
24 #ifdef BB_FEATURE_VERBOSE_USAGE
25 #define APPLET(a,b,c) a##_trivial_usage "\n\n" a##_full_usage "\0"
26 #define APPLET_NOUSAGE(a,b,c) "\0"
27 #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\n\n" d##_full_usage "\0"
28 #else
29 #define APPLET(a,b,c) a##_trivial_usage "\0"
30 #define APPLET_NOUSAGE(a,b,c) "\0"
31 #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\0"
32 #endif
33#elif defined(MAKE_LINKS)
34# define APPLET(a,b,c) LINK c a
35# define APPLET_NOUSAGE(a,b,c) LINK c a
36# define APPLET_ODDNAME(a,b,c,d) LINK c a
37#else
38 const struct BB_applet applets[] = {
39 #define APPLET(a,b,c) {#a,b,c},
40 #define APPLET_NOUSAGE(a,b,c) {a,b,c},
41 #define APPLET_ODDNAME(a,b,c,d) {a,b,c},
42#endif
43
44
45
46#ifdef BB_TEST
47 APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN)
48#endif
49#ifdef BB_ADDGROUP
50 APPLET(addgroup, addgroup_main, _BB_DIR_BIN)
51#endif
52#ifdef BB_ADDUSER
53 APPLET(adduser, adduser_main, _BB_DIR_BIN)
54#endif
55#ifdef BB_ADJTIMEX
56 APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN)
57#endif
58#ifdef BB_AR
59 APPLET(ar, ar_main, _BB_DIR_USR_BIN)
60#endif
61#ifdef BB_ASH
62 APPLET_NOUSAGE("ash", ash_main, _BB_DIR_BIN)
63#endif
64#ifdef BB_BASENAME
65 APPLET(basename, basename_main, _BB_DIR_USR_BIN)
66#endif
67#ifdef BB_BUNZIP2
68 APPLET(bunzip2, bunzip2_main, _BB_DIR_USR_BIN)
69#endif
70 APPLET_NOUSAGE("busybox", busybox_main, _BB_DIR_BIN)
71#ifdef BB_CAT
72 APPLET(cat, cat_main, _BB_DIR_BIN)
73#endif
74#ifdef BB_CHGRP
75 APPLET(chgrp, chgrp_main, _BB_DIR_BIN)
76#endif
77#ifdef BB_CHMOD
78 APPLET(chmod, chmod_main, _BB_DIR_BIN)
79#endif
80#ifdef BB_CHOWN
81 APPLET(chown, chown_main, _BB_DIR_BIN)
82#endif
83#ifdef BB_CHROOT
84 APPLET(chroot, chroot_main, _BB_DIR_USR_SBIN)
85#endif
86#ifdef BB_CHVT
87 APPLET(chvt, chvt_main, _BB_DIR_USR_BIN)
88#endif
89#ifdef BB_CLEAR
90 APPLET(clear, clear_main, _BB_DIR_USR_BIN)
91#endif
92#ifdef BB_CMP
93 APPLET(cmp, cmp_main, _BB_DIR_USR_BIN)
94#endif
95#ifdef BB_CP
96 APPLET(cp, cp_main, _BB_DIR_BIN)
97#endif
98#ifdef BB_CPIO
99 APPLET(cpio, cpio_main, _BB_DIR_BIN)
100#endif
101#ifdef BB_CUT
102 APPLET(cut, cut_main, _BB_DIR_USR_BIN)
103#endif
104#ifdef BB_DATE
105 APPLET(date, date_main, _BB_DIR_BIN)
106#endif
107#ifdef BB_DC
108 APPLET(dc, dc_main, _BB_DIR_USR_BIN)
109#endif
110#ifdef BB_DD
111 APPLET(dd, dd_main, _BB_DIR_BIN)
112#endif
113#ifdef BB_DEALLOCVT
114 APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN)
115#endif
116#ifdef BB_DELGROUP
117 APPLET(delgroup, delgroup_main, _BB_DIR_BIN)
118#endif
119#ifdef BB_DELUSER
120 APPLET(deluser, deluser_main, _BB_DIR_BIN)
121#endif
122#ifdef BB_DF
123 APPLET(df, df_main, _BB_DIR_BIN)
124#endif
125#ifdef BB_DIRNAME
126 APPLET(dirname, dirname_main, _BB_DIR_USR_BIN)
127#endif
128#ifdef BB_DMESG
129 APPLET(dmesg, dmesg_main, _BB_DIR_BIN)
130#endif
131#ifdef BB_DOS2UNIX
132 APPLET(dos2unix, dos2unix_main, _BB_DIR_USR_BIN)
133#endif
134#ifdef BB_DPKG
135 APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN)
136#endif
137#ifdef BB_DPKG_DEB
138 APPLET_ODDNAME("dpkg-deb", dpkg_deb_main, _BB_DIR_USR_BIN, dpkg_deb)
139#endif
140#ifdef BB_DU
141 APPLET(du, du_main, _BB_DIR_USR_BIN)
142#endif
143#ifdef BB_DUMPKMAP
144 APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN)
145#endif
146#ifdef BB_DUTMP
147 APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN)
148#endif
149#ifdef BB_ECHO
150 APPLET(echo, echo_main, _BB_DIR_BIN)
151#endif
152#if defined(BB_FEATURE_GREP_EGREP_ALIAS) && defined(BB_GREP)
153 APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN)
154#endif
155#ifdef BB_ENV
156 APPLET(env, env_main, _BB_DIR_USR_BIN)
157#endif
158#ifdef BB_EXPR
159 APPLET(expr, expr_main, _BB_DIR_USR_BIN)
160#endif
161#ifdef BB_TRUE_FALSE
162 APPLET(false, false_main, _BB_DIR_BIN)
163#endif
164#ifdef BB_FBSET
165 APPLET(fbset, fbset_main, _BB_DIR_USR_SBIN)
166#endif
167#ifdef BB_FDFLUSH
168 APPLET(fdflush, fdflush_main, _BB_DIR_BIN)
169#endif
170#ifdef BB_FIND
171 APPLET(find, find_main, _BB_DIR_USR_BIN)
172#endif
173#ifdef BB_FREE
174 APPLET(free, free_main, _BB_DIR_USR_BIN)
175#endif
176#ifdef BB_FREERAMDISK
177 APPLET(freeramdisk, freeramdisk_main, _BB_DIR_SBIN)
178#endif
179#ifdef BB_FSCK_MINIX
180 APPLET_ODDNAME("fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix)
181#endif
182#ifdef BB_GETOPT
183 APPLET(getopt, getopt_main, _BB_DIR_BIN)
184#endif
185#ifdef BB_GETTY
186 APPLET(getty, getty_main, _BB_DIR_SBIN)
187#endif
188#ifdef BB_GREP
189 APPLET(grep, grep_main, _BB_DIR_BIN)
190#endif
191#ifdef BB_GUNZIP
192 APPLET(gunzip, gunzip_main, _BB_DIR_BIN)
193#endif
194#ifdef BB_GZIP
195 APPLET(gzip, gzip_main, _BB_DIR_BIN)
196#endif
197#ifdef BB_HALT
198 APPLET(halt, halt_main, _BB_DIR_SBIN)
199#endif
200#ifdef BB_HEAD
201 APPLET(head, head_main, _BB_DIR_USR_BIN)
202#endif
203#ifdef BB_HOSTID
204 APPLET(hostid, hostid_main, _BB_DIR_USR_BIN)
205#endif
206#ifdef BB_HOSTNAME
207 APPLET(hostname, hostname_main, _BB_DIR_BIN)
208#endif
209#ifdef BB_HUSH
210 APPLET_NOUSAGE("hush", hush_main, _BB_DIR_BIN)
211#endif
212#ifdef BB_ID
213 APPLET(id, id_main, _BB_DIR_USR_BIN)
214#endif
215#ifdef BB_IFCONFIG
216 APPLET(ifconfig, ifconfig_main, _BB_DIR_SBIN)
217#endif
218#ifdef BB_INIT
219 APPLET(init, init_main, _BB_DIR_SBIN)
220#endif
221#ifdef BB_INSMOD
222 APPLET(insmod, insmod_main, _BB_DIR_SBIN)
223#endif
224#ifdef BB_KILL
225 APPLET(kill, kill_main, _BB_DIR_BIN)
226#endif
227#ifdef BB_KILLALL
228 APPLET(killall, kill_main, _BB_DIR_USR_BIN)
229#endif
230#ifdef BB_KLOGD
231 APPLET(klogd, klogd_main, _BB_DIR_SBIN)
232#endif
233#ifdef BB_LASH
234 APPLET(lash, lash_main, _BB_DIR_BIN)
235#endif
236#ifdef BB_LENGTH
237 APPLET(length, length_main, _BB_DIR_USR_BIN)
238#endif
239#ifdef BB_FEATURE_LINUXRC
240 APPLET_NOUSAGE("linuxrc", init_main, _BB_DIR_ROOT)
241#endif
242#ifdef BB_LN
243 APPLET(ln, ln_main, _BB_DIR_BIN)
244#endif
245#ifdef BB_LOADACM
246 APPLET(loadacm, loadacm_main, _BB_DIR_USR_BIN)
247#endif
248#ifdef BB_LOADFONT
249 APPLET(loadfont, loadfont_main, _BB_DIR_USR_BIN)
250#endif
251#ifdef BB_LOADKMAP
252 APPLET(loadkmap, loadkmap_main, _BB_DIR_SBIN)
253#endif
254#ifdef BB_LOGGER
255 APPLET(logger, logger_main, _BB_DIR_USR_BIN)
256#endif
257#ifdef BB_LOGNAME
258 APPLET(logname, logname_main, _BB_DIR_USR_BIN)
259#endif
260#ifdef BB_LOGREAD
261 APPLET(logread, logread_main, _BB_DIR_SBIN)
262#endif
263#ifdef BB_LS
264 APPLET(ls, ls_main, _BB_DIR_BIN)
265#endif
266#ifdef BB_LSMOD
267 APPLET(lsmod, lsmod_main, _BB_DIR_SBIN)
268#endif
269#ifdef BB_MAKEDEVS
270 APPLET(makedevs, makedevs_main, _BB_DIR_SBIN)
271#endif
272#ifdef BB_MD5SUM
273 APPLET(md5sum, md5sum_main, _BB_DIR_USR_BIN)
274#endif
275#ifdef BB_MKDIR
276 APPLET(mkdir, mkdir_main, _BB_DIR_BIN)
277#endif
278#ifdef BB_MKFIFO
279 APPLET(mkfifo, mkfifo_main, _BB_DIR_USR_BIN)
280#endif
281#ifdef BB_MKFS_MINIX
282 APPLET_ODDNAME("mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN, mkfs_minix)
283#endif
284#ifdef BB_MKNOD
285 APPLET(mknod, mknod_main, _BB_DIR_BIN)
286#endif
287#ifdef BB_MKSWAP
288 APPLET(mkswap, mkswap_main, _BB_DIR_SBIN)
289#endif
290#ifdef BB_MKTEMP
291 APPLET(mktemp, mktemp_main, _BB_DIR_BIN)
292#endif
293#ifdef BB_MODPROBE
294 APPLET(modprobe, modprobe_main, _BB_DIR_SBIN)
295#endif
296#ifdef BB_MORE
297 APPLET(more, more_main, _BB_DIR_BIN)
298#endif
299#ifdef BB_MOUNT
300 APPLET(mount, mount_main, _BB_DIR_BIN)
301#endif
302#ifdef BB_MSH
303 APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN)
304#endif
305#ifdef BB_MT
306 APPLET(mt, mt_main, _BB_DIR_BIN)
307#endif
308#ifdef BB_MV
309 APPLET(mv, mv_main, _BB_DIR_BIN)
310#endif
311#ifdef BB_NC
312 APPLET(nc, nc_main, _BB_DIR_USR_BIN)
313#endif
314#ifdef BB_NSLOOKUP
315 APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN)
316#endif
317#ifdef BB_PIDOF
318 APPLET(pidof, pidof_main, _BB_DIR_BIN)
319#endif
320#ifdef BB_PING
321 APPLET(ping, ping_main, _BB_DIR_BIN)
322#endif
323#ifdef BB_PIVOT_ROOT
324 APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN)
325#endif
326#ifdef BB_POWEROFF
327 APPLET(poweroff, poweroff_main, _BB_DIR_SBIN)
328#endif
329#ifdef BB_PRINTF
330 APPLET(printf, printf_main, _BB_DIR_USR_BIN)
331#endif
332#ifdef BB_PS
333 APPLET(ps, ps_main, _BB_DIR_BIN)
334#endif
335#ifdef BB_PWD
336 APPLET(pwd, pwd_main, _BB_DIR_BIN)
337#endif
338#ifdef BB_RDATE
339 APPLET(rdate, rdate_main, _BB_DIR_USR_BIN)
340#endif
341#ifdef BB_READLINK
342 APPLET(readlink, readlink_main, _BB_DIR_USR_BIN)
343#endif
344#ifdef BB_REBOOT
345 APPLET(reboot, reboot_main, _BB_DIR_SBIN)
346#endif
347#ifdef BB_RENICE
348 APPLET(renice, renice_main, _BB_DIR_USR_BIN)
349#endif
350#ifdef BB_RESET
351 APPLET(reset, reset_main, _BB_DIR_USR_BIN)
352#endif
353#ifdef BB_RM
354 APPLET(rm, rm_main, _BB_DIR_BIN)
355#endif
356#ifdef BB_RMDIR
357 APPLET(rmdir, rmdir_main, _BB_DIR_BIN)
358#endif
359#ifdef BB_RMMOD
360 APPLET(rmmod, rmmod_main, _BB_DIR_SBIN)
361#endif
362#ifdef BB_ROUTE
363 APPLET(route, route_main, _BB_DIR_SBIN)
364#endif
365#ifdef BB_RPM2CPIO
366 APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN)
367#endif
368#ifdef BB_SED
369 APPLET(sed, sed_main, _BB_DIR_BIN)
370#endif
371#ifdef BB_SETKEYCODES
372 APPLET(setkeycodes, setkeycodes_main, _BB_DIR_USR_BIN)
373#endif
374#if defined(BB_FEATURE_SH_IS_ASH) && defined(BB_ASH)
375 APPLET_NOUSAGE("sh", ash_main, _BB_DIR_BIN)
376#elif defined(BB_FEATURE_SH_IS_HUSH) && defined(BB_HUSH)
377 APPLET_NOUSAGE("sh", hush_main, _BB_DIR_BIN)
378#elif defined(BB_FEATURE_SH_IS_LASH) && defined(BB_LASH)
379 APPLET_NOUSAGE("sh", lash_main, _BB_DIR_BIN)
380#elif defined(BB_FEATURE_SH_IS_MSH) && defined(BB_MSH)
381 APPLET_NOUSAGE("sh", msh_main, _BB_DIR_BIN)
382#endif
383#ifdef BB_SLEEP
384 APPLET(sleep, sleep_main, _BB_DIR_BIN)
385#endif
386#ifdef BB_SORT
387 APPLET(sort, sort_main, _BB_DIR_USR_BIN)
388#endif
389#ifdef BB_START_STOP_DAEMON
390 APPLET_ODDNAME("start-stop-daemon", start_stop_daemon_main, _BB_DIR_SBIN, start_stop_daemon)
391#endif
392#ifdef BB_STTY
393 APPLET(stty, stty_main, _BB_DIR_BIN)
394#endif
395#ifdef BB_SWAPONOFF
396 APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN)
397#endif
398#ifdef BB_SWAPONOFF
399 APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN)
400#endif
401#ifdef BB_SYNC
402 APPLET(sync, sync_main, _BB_DIR_BIN)
403#endif
404#ifdef BB_SYSLOGD
405 APPLET(syslogd, syslogd_main, _BB_DIR_SBIN)
406#endif
407#ifdef BB_TAIL
408 APPLET(tail, tail_main, _BB_DIR_USR_BIN)
409#endif
410#ifdef BB_TAR
411 APPLET(tar, tar_main, _BB_DIR_BIN)
412#endif
413#ifdef BB_TEE
414 APPLET(tee, tee_main, _BB_DIR_USR_BIN)
415#endif
416#ifdef BB_TELNET
417 APPLET(telnet, telnet_main, _BB_DIR_USR_BIN)
418#endif
419#ifdef BB_TEST
420 APPLET(test, test_main, _BB_DIR_USR_BIN)
421#endif
422#ifdef BB_TFTP
423 APPLET(tftp, tftp_main, _BB_DIR_USR_BIN)
424#endif
425#ifdef BB_TOUCH
426 APPLET(touch, touch_main, _BB_DIR_BIN)
427#endif
428#ifdef BB_TR
429 APPLET(tr, tr_main, _BB_DIR_USR_BIN)
430#endif
431#ifdef BB_TRACEROUTE
432 APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN)
433#endif
434#ifdef BB_TRUE_FALSE
435 APPLET(true, true_main, _BB_DIR_BIN)
436#endif
437#ifdef BB_TTY
438 APPLET(tty, tty_main, _BB_DIR_USR_BIN)
439#endif
440#ifdef BB_UMOUNT
441 APPLET(umount, umount_main, _BB_DIR_BIN)
442#endif
443#ifdef BB_UNAME
444 APPLET(uname, uname_main, _BB_DIR_BIN)
445#endif
446#ifdef BB_UNIQ
447 APPLET(uniq, uniq_main, _BB_DIR_USR_BIN)
448#endif
449#ifdef BB_UNIX2DOS
450 APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN)
451#endif
452#ifdef BB_UPDATE
453 APPLET(update, update_main, _BB_DIR_SBIN)
454#endif
455#ifdef BB_UPTIME
456 APPLET(uptime, uptime_main, _BB_DIR_USR_BIN)
457#endif
458#ifdef BB_USLEEP
459 APPLET(usleep, usleep_main, _BB_DIR_BIN)
460#endif
461#ifdef BB_UUDECODE
462 APPLET(uudecode, uudecode_main, _BB_DIR_USR_BIN)
463#endif
464#ifdef BB_UUENCODE
465 APPLET(uuencode, uuencode_main, _BB_DIR_USR_BIN)
466#endif
467#ifdef BB_VI
468 APPLET(vi, vi_main, _BB_DIR_BIN)
469#endif
470#ifdef BB_WATCHDOG
471 APPLET(watchdog, watchdog_main, _BB_DIR_SBIN)
472#endif
473#ifdef BB_WC
474 APPLET(wc, wc_main, _BB_DIR_USR_BIN)
475#endif
476#ifdef BB_WGET
477 APPLET(wget, wget_main, _BB_DIR_USR_BIN)
478#endif
479#ifdef BB_WHICH
480 APPLET(which, which_main, _BB_DIR_USR_BIN)
481#endif
482#ifdef BB_WHOAMI
483 APPLET(whoami, whoami_main, _BB_DIR_USR_BIN)
484#endif
485#ifdef BB_XARGS
486 APPLET(xargs, xargs_main, _BB_DIR_USR_BIN)
487#endif
488#ifdef BB_YES
489 APPLET(yes, yes_main, _BB_DIR_USR_BIN)
490#endif
491#ifdef BB_GUNZIP
492 APPLET(zcat, gunzip_main, _BB_DIR_BIN)
493#endif
494
495#if !defined(PROTOTYPES) && !defined(MAKE_USAGE)
496 { 0,NULL,0 }
497};
498
499#endif
500
diff --git a/applets/busybox.c b/applets/busybox.c
index 33efb5d84..e6e5eca2d 100644
--- a/applets/busybox.c
+++ b/applets/busybox.c
@@ -5,14 +5,14 @@
5#include <errno.h> 5#include <errno.h>
6#include <stdlib.h> 6#include <stdlib.h>
7#include "busybox.h" 7#include "busybox.h"
8#ifdef BB_LOCALE_SUPPORT 8#ifdef CONFIG_LOCALE_SUPPORT
9#include <locale.h> 9#include <locale.h>
10#endif 10#endif
11 11
12int been_there_done_that = 0; /* Also used in applets.c */ 12int been_there_done_that = 0; /* Also used in applets.c */
13const char *applet_name; 13const char *applet_name;
14 14
15#ifdef BB_FEATURE_INSTALLER 15#ifdef CONFIG_FEATURE_INSTALLER
16/* 16/*
17 * directory table 17 * directory table
18 * this should be consistent w/ the enum, busybox.h::Location, 18 * this should be consistent w/ the enum, busybox.h::Location,
@@ -63,7 +63,7 @@ static void install_links(const char *busybox, int use_symbolic_links)
63 } 63 }
64} 64}
65 65
66#endif /* BB_FEATURE_INSTALLER */ 66#endif /* CONFIG_FEATURE_INSTALLER */
67 67
68int main(int argc, char **argv) 68int main(int argc, char **argv)
69{ 69{
@@ -79,8 +79,8 @@ int main(int argc, char **argv)
79 applet_name = s; 79 applet_name = s;
80 } 80 }
81 81
82#ifdef BB_LOCALE_SUPPORT 82#ifdef CONFIG_LOCALE_SUPPORT
83#ifdef BB_INIT 83#ifdef CONFIG_INIT
84 if(getpid()!=1) /* Do not set locale for `init' */ 84 if(getpid()!=1) /* Do not set locale for `init' */
85#endif 85#endif
86 { 86 {
@@ -97,7 +97,7 @@ int busybox_main(int argc, char **argv)
97{ 97{
98 int col = 0, len, i; 98 int col = 0, len, i;
99 99
100#ifdef BB_FEATURE_INSTALLER 100#ifdef CONFIG_FEATURE_INSTALLER
101 /* 101 /*
102 * This style of argument parsing doesn't scale well 102 * This style of argument parsing doesn't scale well
103 * in the event that busybox starts wanting more --options. 103 * in the event that busybox starts wanting more --options.
@@ -125,7 +125,7 @@ int busybox_main(int argc, char **argv)
125 } 125 }
126 return rc; 126 return rc;
127 } 127 }
128#endif /* BB_FEATURE_INSTALLER */ 128#endif /* CONFIG_FEATURE_INSTALLER */
129 129
130 argc--; 130 argc--;
131 131
diff --git a/applets/busybox.sh b/applets/busybox.sh
index 9ab0f4bdb..6ac4e8043 100755
--- a/applets/busybox.sh
+++ b/applets/busybox.sh
@@ -5,11 +5,11 @@ export LC_CTYPE=POSIX
5 5
6RAW=` \ 6RAW=` \
7 $CC -E -dM ${1:-Config.h} | \ 7 $CC -E -dM ${1:-Config.h} | \
8 sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1.c/gp;' \ 8 sed -n -e '/^.*CONFIG_FEATURE.*$/d;s/^#define.*\<CONFIG_\(.*\)\>/\1.c/gp;' \
9 | tr A-Z a-z | sort 9 | tr A-Z a-z | sort
10` 10`
11test "${RAW}" != "" || exit 11test "${RAW}" != "" || exit
12if [ -d "$BB_SRC_DIR" ]; then cd $BB_SRC_DIR; fi 12if [ -d "$CONFIG_SRC_DIR" ]; then cd $CONFIG_SRC_DIR; fi
13# By running $RAW through "ls", we avoid listing 13# By running $RAW through "ls", we avoid listing
14# source files that don't exist. 14# source files that don't exist.
15ls $RAW 2>/dev/null | tr '\n' ' ' 15ls $RAW 2>/dev/null | tr '\n' ' '
diff --git a/applets/usage.h b/applets/usage.h
index 5e514274a..1de29666e 100644
--- a/applets/usage.h
+++ b/applets/usage.h
@@ -247,7 +247,7 @@
247#define deluser_full_usage \ 247#define deluser_full_usage \
248 "Deletes user USER from the system" 248 "Deletes user USER from the system"
249 249
250#ifdef BB_FEATURE_HUMAN_READABLE 250#ifdef CONFIG_FEATURE_HUMAN_READABLE
251 #define USAGE_HUMAN_READABLE(a) a 251 #define USAGE_HUMAN_READABLE(a) a
252 #define USAGE_NOT_HUMAN_READABLE(a) 252 #define USAGE_NOT_HUMAN_READABLE(a)
253#else 253#else
@@ -464,17 +464,17 @@
464#define fdflush_full_usage \ 464#define fdflush_full_usage \
465 "Forces floppy disk drive to detect disk change" 465 "Forces floppy disk drive to detect disk change"
466 466
467#ifdef BB_FEATURE_FIND_TYPE 467#ifdef CONFIG_FEATURE_FIND_TYPE
468 #define USAGE_FIND_TYPE(a) a 468 #define USAGE_FIND_TYPE(a) a
469#else 469#else
470 #define USAGE_FIND_TYPE(a) 470 #define USAGE_FIND_TYPE(a)
471#endif 471#endif
472#ifdef BB_FEATURE_FIND_PERM 472#ifdef CONFIG_FEATURE_FIND_PERM
473 #define USAGE_FIND_PERM(a) a 473 #define USAGE_FIND_PERM(a) a
474#else 474#else
475 #define USAGE_FIND_PERM(a) 475 #define USAGE_FIND_PERM(a)
476#endif 476#endif
477#ifdef BB_FEATURE_FIND_MTIME 477#ifdef CONFIG_FEATURE_FIND_MTIME
478 #define USAGE_FIND_MTIME(a) a 478 #define USAGE_FIND_MTIME(a) a
479#else 479#else
480 #define USAGE_FIND_MTIME(a) 480 #define USAGE_FIND_MTIME(a)
@@ -678,22 +678,22 @@
678 "$ id\n" \ 678 "$ id\n" \
679 "uid=1000(andersen) gid=1000(andersen)\n" 679 "uid=1000(andersen) gid=1000(andersen)\n"
680 680
681#ifdef BB_FEATURE_IFCONFIG_SLIP 681#ifdef CONFIG_FEATURE_IFCONFIG_SLIP
682 #define USAGE_SIOCSKEEPALIVE(a) a 682 #define USAGE_SIOCSKEEPALIVE(a) a
683#else 683#else
684 #define USAGE_SIOCSKEEPALIVE(a) 684 #define USAGE_SIOCSKEEPALIVE(a)
685#endif 685#endif
686#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 686#ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
687 #define USAGE_IFCONFIG_MII(a) a 687 #define USAGE_IFCONFIG_MII(a) a
688#else 688#else
689 #define USAGE_IFCONFIG_MII(a) 689 #define USAGE_IFCONFIG_MII(a)
690#endif 690#endif
691#ifdef BB_FEATURE_IFCONFIG_HW 691#ifdef CONFIG_FEATURE_IFCONFIG_HW
692 #define USAGE_IFCONFIG_HW(a) a 692 #define USAGE_IFCONFIG_HW(a) a
693#else 693#else
694 #define USAGE_IFCONFIG_HW(a) 694 #define USAGE_IFCONFIG_HW(a)
695#endif 695#endif
696#ifdef BB_FEATURE_IFCONFIG_STATUS 696#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
697 #define USAGE_IFCONFIG_OPT_A(a) a 697 #define USAGE_IFCONFIG_OPT_A(a) a
698#else 698#else
699 #define USAGE_IFCONFIG_OPT_A(a) 699 #define USAGE_IFCONFIG_OPT_A(a)
@@ -950,32 +950,32 @@
950#define logread_full_usage \ 950#define logread_full_usage \
951 "Shows the messages from syslogd (using circular buffer)." 951 "Shows the messages from syslogd (using circular buffer)."
952 952
953#ifdef BB_FEATURE_LS_TIMESTAMPS 953#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
954 #define USAGE_LS_TIMESTAMPS(a) a 954 #define USAGE_LS_TIMESTAMPS(a) a
955#else 955#else
956 #define USAGE_LS_TIMESTAMPS(a) 956 #define USAGE_LS_TIMESTAMPS(a)
957#endif 957#endif
958#ifdef BB_FEATURE_LS_FILETYPES 958#ifdef CONFIG_FEATURE_LS_FILETYPES
959 #define USAGE_LS_FILETYPES(a) a 959 #define USAGE_LS_FILETYPES(a) a
960#else 960#else
961 #define USAGE_LS_FILETYPES(a) 961 #define USAGE_LS_FILETYPES(a)
962#endif 962#endif
963#ifdef BB_FEATURE_LS_FOLLOWLINKS 963#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
964 #define USAGE_LS_FOLLOWLINKS(a) a 964 #define USAGE_LS_FOLLOWLINKS(a) a
965#else 965#else
966 #define USAGE_LS_FOLLOWLINKS(a) 966 #define USAGE_LS_FOLLOWLINKS(a)
967#endif 967#endif
968#ifdef BB_FEATURE_LS_RECURSIVE 968#ifdef CONFIG_FEATURE_LS_RECURSIVE
969 #define USAGE_LS_RECURSIVE(a) a 969 #define USAGE_LS_RECURSIVE(a) a
970#else 970#else
971 #define USAGE_LS_RECURSIVE(a) 971 #define USAGE_LS_RECURSIVE(a)
972#endif 972#endif
973#ifdef BB_FEATURE_LS_SORTFILES 973#ifdef CONFIG_FEATURE_LS_SORTFILES
974 #define USAGE_LS_SORTFILES(a) a 974 #define USAGE_LS_SORTFILES(a) a
975#else 975#else
976 #define USAGE_LS_SORTFILES(a) 976 #define USAGE_LS_SORTFILES(a)
977#endif 977#endif
978#ifdef BB_FEATURE_AUTOWIDTH 978#ifdef CONFIG_FEATURE_AUTOWIDTH
979 #define USAGE_AUTOWIDTH(a) a 979 #define USAGE_AUTOWIDTH(a) a
980#else 980#else
981 #define USAGE_AUTOWIDTH(a) 981 #define USAGE_AUTOWIDTH(a)
@@ -1145,12 +1145,12 @@
1145#define more_example_usage \ 1145#define more_example_usage \
1146 "$ dmesg | more\n" 1146 "$ dmesg | more\n"
1147 1147
1148#ifdef BB_FEATURE_MOUNT_LOOP 1148#ifdef CONFIG_FEATURE_MOUNT_LOOP
1149 #define USAGE_MOUNT_LOOP(a) a 1149 #define USAGE_MOUNT_LOOP(a) a
1150#else 1150#else
1151 #define USAGE_MOUNT_LOOP(a) 1151 #define USAGE_MOUNT_LOOP(a)
1152#endif 1152#endif
1153#ifdef BB_FEATURE_MTAB_SUPPORT 1153#ifdef CONFIG_FEATURE_MTAB_SUPPORT
1154 #define USAGE_MTAB(a) a 1154 #define USAGE_MTAB(a) a
1155#else 1155#else
1156 #define USAGE_MTAB(a) 1156 #define USAGE_MTAB(a)
@@ -1245,7 +1245,7 @@
1245 "$ pidof init\n" \ 1245 "$ pidof init\n" \
1246 "1\n" 1246 "1\n"
1247 1247
1248#ifndef BB_FEATURE_FANCY_PING 1248#ifndef CONFIG_FEATURE_FANCY_PING
1249#define ping_trivial_usage "host" 1249#define ping_trivial_usage "host"
1250#define ping_full_usage "Send ICMP ECHO_REQUEST packets to network hosts" 1250#define ping_full_usage "Send ICMP ECHO_REQUEST packets to network hosts"
1251#else 1251#else
@@ -1431,12 +1431,12 @@
1431 "[2 second delay results]\n" 1431 "[2 second delay results]\n"
1432 1432
1433 1433
1434#ifdef BB_FEATURE_SORT_UNIQUE 1434#ifdef CONFIG_FEATURE_SORT_UNIQUE
1435 #define USAGE_SORT_UNIQUE(a) a 1435 #define USAGE_SORT_UNIQUE(a) a
1436#else 1436#else
1437 #define USAGE_SORT_UNIQUE(a) 1437 #define USAGE_SORT_UNIQUE(a)
1438#endif 1438#endif
1439#ifdef BB_FEATURE_SORT_REVERSE 1439#ifdef CONFIG_FEATURE_SORT_REVERSE
1440 #define USAGE_SORT_REVERSE(a) a 1440 #define USAGE_SORT_REVERSE(a) a
1441#else 1441#else
1442 #define USAGE_SORT_REVERSE(a) 1442 #define USAGE_SORT_REVERSE(a)
@@ -1503,7 +1503,7 @@
1503 "Write all buffered filesystem blocks to disk." 1503 "Write all buffered filesystem blocks to disk."
1504 1504
1505 1505
1506#ifdef BB_FEATURE_REMOTE_LOG 1506#ifdef CONFIG_FEATURE_REMOTE_LOG
1507 #define USAGE_REMOTE_LOG(a) a 1507 #define USAGE_REMOTE_LOG(a) a
1508#else 1508#else
1509 #define USAGE_REMOTE_LOG(a) 1509 #define USAGE_REMOTE_LOG(a)
@@ -1525,7 +1525,7 @@
1525 "$ syslogd -R 192.168.1.1:601\n" 1525 "$ syslogd -R 192.168.1.1:601\n"
1526 1526
1527 1527
1528#ifndef BB_FEATURE_FANCY_TAIL 1528#ifndef CONFIG_FEATURE_FANCY_TAIL
1529 #define USAGE_UNSIMPLE_TAIL(a) 1529 #define USAGE_UNSIMPLE_TAIL(a)
1530#else 1530#else
1531 #define USAGE_UNSIMPLE_TAIL(a) a 1531 #define USAGE_UNSIMPLE_TAIL(a) a
@@ -1550,12 +1550,12 @@
1550 "$ tail -n 1 /etc/resolv.conf\n" \ 1550 "$ tail -n 1 /etc/resolv.conf\n" \
1551 "nameserver 10.0.0.1\n" 1551 "nameserver 10.0.0.1\n"
1552 1552
1553#ifdef BB_FEATURE_TAR_CREATE 1553#ifdef CONFIG_FEATURE_TAR_CREATE
1554 #define USAGE_TAR_CREATE(a) a 1554 #define USAGE_TAR_CREATE(a) a
1555#else 1555#else
1556 #define USAGE_TAR_CREATE(a) 1556 #define USAGE_TAR_CREATE(a)
1557#endif 1557#endif
1558#ifdef BB_FEATURE_TAR_EXCLUDE 1558#ifdef CONFIG_FEATURE_TAR_EXCLUDE
1559 #define USAGE_TAR_EXCLUDE(a) a 1559 #define USAGE_TAR_EXCLUDE(a) a
1560#else 1560#else
1561 #define USAGE_TAR_EXCLUDE(a) 1561 #define USAGE_TAR_EXCLUDE(a)
@@ -1619,17 +1619,17 @@
1619 "$ echo $?\n" \ 1619 "$ echo $?\n" \
1620 "1\n" 1620 "1\n"
1621 1621
1622#ifdef BB_FEATURE_TFTP_GET 1622#ifdef CONFIG_FEATURE_TFTP_GET
1623 #define USAGE_TFTP_GET(a) a 1623 #define USAGE_TFTP_GET(a) a
1624#else 1624#else
1625 #define USAGE_TFTP_GET(a) 1625 #define USAGE_TFTP_GET(a)
1626#endif 1626#endif
1627#ifdef BB_FEATURE_TFTP_PUT 1627#ifdef CONFIG_FEATURE_TFTP_PUT
1628 #define USAGE_TFTP_PUT(a) a 1628 #define USAGE_TFTP_PUT(a) a
1629#else 1629#else
1630 #define USAGE_TFTP_PUT(a) 1630 #define USAGE_TFTP_PUT(a)
1631#endif 1631#endif
1632#ifdef BB_FEATURE_TFTP_BLOCKSIZE 1632#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
1633 #define USAGE_TFTP_BS(a) a 1633 #define USAGE_TFTP_BS(a) a
1634#else 1634#else
1635 #define USAGE_TFTP_BS(a) 1635 #define USAGE_TFTP_BS(a)
@@ -1719,7 +1719,7 @@
1719 "$ tty\n" \ 1719 "$ tty\n" \
1720 "/dev/tty2\n" 1720 "/dev/tty2\n"
1721 1721
1722#ifdef BB_FEATURE_MOUNT_FORCE 1722#ifdef CONFIG_FEATURE_MOUNT_FORCE
1723 #define USAGE_MOUNT_FORCE(a) a 1723 #define USAGE_MOUNT_FORCE(a) a
1724#else 1724#else
1725 #define USAGE_MOUNT_FORCE(a) 1725 #define USAGE_MOUNT_FORCE(a)
diff --git a/ar.c b/ar.c
deleted file mode 100644
index e02b2651e..000000000
--- a/ar.c
+++ /dev/null
@@ -1,89 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini ar implementation for busybox
4 *
5 * Copyright (C) 2000 by Glenn McGrath
6 * Written by Glenn McGrath <bug1@optushome.com.au> 1 June 2000
7 *
8 * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25#include <fcntl.h>
26#include <stdlib.h>
27#include <string.h>
28#include <getopt.h>
29#include <unistd.h>
30#include "busybox.h"
31
32extern int ar_main(int argc, char **argv)
33{
34 FILE *src_stream = NULL;
35 char **extract_names = NULL;
36 char ar_magic[8];
37 int extract_function = extract_unconditional;
38 int opt;
39 int num_of_entries = 0;
40 extern off_t archive_offset;
41
42 while ((opt = getopt(argc, argv, "ovtpx")) != -1) {
43 switch (opt) {
44 case 'o':
45 extract_function |= extract_preserve_date;
46 break;
47 case 'v':
48 extract_function |= extract_verbose_list;
49 break;
50 case 't':
51 extract_function |= extract_list;
52 break;
53 case 'p':
54 extract_function |= extract_to_stdout;
55 break;
56 case 'x':
57 extract_function |= extract_all_to_fs;
58 break;
59 default:
60 show_usage();
61 }
62 }
63
64 /* check the src filename was specified */
65 if (optind == argc) {
66 show_usage();
67 }
68
69 src_stream = xfopen(argv[optind++], "r");
70
71 /* check ar magic */
72 fread(ar_magic, 1, 8, src_stream);
73 archive_offset = 8;
74 if (strncmp(ar_magic,"!<arch>",7) != 0) {
75 error_msg_and_die("invalid magic");
76 }
77
78 /* Create a list of files to extract */
79 while (optind < argc) {
80 extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
81 extract_names[num_of_entries] = xstrdup(argv[optind]);
82 num_of_entries++;
83 extract_names[num_of_entries] = NULL;
84 optind++;
85 }
86
87 unarchive(src_stream, stdout, &get_header_ar, extract_function, "./", extract_names, NULL);
88 return EXIT_SUCCESS;
89}
diff --git a/archival/Makefile b/archival/Makefile
new file mode 100644
index 000000000..66c2d0b6b
--- /dev/null
+++ b/archival/Makefile
@@ -0,0 +1,43 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := archival.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27obj-$(CONFIG_AR) += ar.o
28obj-$(CONFIG_BUNZIP2) += bunzip2.o
29obj-$(CONFIG_CPIO) += cpio.o
30obj-$(CONFIG_DPKG) += dpkg.o
31obj-$(CONFIG_DPKG_DEB) += dpkg_deb.o
32obj-$(CONFIG_GUNZIP) += gunzip.o
33obj-$(CONFIG_GZIP) += gzip.o
34obj-$(CONFIG_RPMUNPACK) += rpm2cpio.o
35obj-$(CONFIG_TAR) += tar.o
36
37
38# Hand off to toplevel Rules.mak
39include $(TOPDIR)/Rules.mak
40
41clean:
42 rm -f $(L_TARGET) *.o core
43
diff --git a/archival/config.in b/archival/config.in
new file mode 100644
index 000000000..c195f24a1
--- /dev/null
+++ b/archival/config.in
@@ -0,0 +1,19 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Archival Utilities'
8
9bool 'ar' CONFIG_AR
10bool 'bunzip2' CONFIG_BUNZIP2
11bool 'cpio' CONFIG_CPIO
12bool 'dpkg' CONFIG_DPKG
13bool 'dpkg_deb' CONFIG_DPKG_DEB
14bool 'gunzip' CONFIG_GUNZIP
15bool 'gzip' CONFIG_GZIP
16bool 'rpm2cpio' CONFIG_RPM2CPIO
17bool 'tar' CONFIG_TAR
18endmenu
19
diff --git a/archival/gzip.c b/archival/gzip.c
index 5c86c1070..df665c121 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -1231,7 +1231,7 @@ int gzip_main(int argc, char **argv)
1231 break; 1231 break;
1232 case 'q': 1232 case 'q':
1233 break; 1233 break;
1234#ifdef BB_GUNZIP 1234#ifdef CONFIG_GUNZIP
1235 case 'd': 1235 case 'd':
1236 optind = 1; 1236 optind = 1;
1237 return gunzip_main(argc, argv); 1237 return gunzip_main(argc, argv);
diff --git a/archival/tar.c b/archival/tar.c
index f7a3da66f..9e38eea75 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -9,8 +9,8 @@
9 * ground up. It still has remnents of the old code lying about, but it is 9 * ground up. It still has remnents of the old code lying about, but it is
10 * very different now (i.e., cleaner, less global variables, etc.) 10 * very different now (i.e., cleaner, less global variables, etc.)
11 * 11 *
12 * Copyright (C) 1999,2000,2001 by Lineo, inc. 12 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
13 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 13 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
14 * 14 *
15 * Based in part in the tar implementation in sash 15 * Based in part in the tar implementation in sash
16 * Copyright (c) 1999 by David I. Bell 16 * Copyright (c) 1999 by David I. Bell
@@ -49,7 +49,7 @@
49#include <errno.h> 49#include <errno.h>
50#include "busybox.h" 50#include "busybox.h"
51 51
52#ifdef BB_FEATURE_TAR_CREATE 52#ifdef CONFIG_FEATURE_TAR_CREATE
53 53
54/* Tar file constants */ 54/* Tar file constants */
55# define TAR_MAGIC "ustar" /* ustar and a null */ 55# define TAR_MAGIC "ustar" /* ustar and a null */
@@ -395,11 +395,11 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
395 if (header_name[0] == '\0') 395 if (header_name[0] == '\0')
396 return TRUE; 396 return TRUE;
397 397
398# if defined BB_FEATURE_TAR_EXCLUDE 398# if defined CONFIG_FEATURE_TAR_EXCLUDE
399 if (exclude_file(tbInfo->excludeList, header_name)) { 399 if (exclude_file(tbInfo->excludeList, header_name)) {
400 return SKIP; 400 return SKIP;
401 } 401 }
402# endif //BB_FEATURE_TAR_EXCLUDE 402# endif //CONFIG_FEATURE_TAR_EXCLUDE
403 403
404 if (writeTarHeader(tbInfo, header_name, fileName, statbuf)==FALSE) { 404 if (writeTarHeader(tbInfo, header_name, fileName, statbuf)==FALSE) {
405 return( FALSE); 405 return( FALSE);
@@ -527,7 +527,7 @@ void append_file_list_to_list(char *filename, char ***name_list, int *num_of_ent
527 fclose(src_stream); 527 fclose(src_stream);
528} 528}
529 529
530#ifdef BB_FEATURE_TAR_EXCLUDE 530#ifdef CONFIG_FEATURE_TAR_EXCLUDE
531/* 531/*
532 * Create a list of names that are in the include list AND NOT in the exclude lists 532 * Create a list of names that are in the include list AND NOT in the exclude lists
533 */ 533 */
@@ -626,7 +626,7 @@ int tar_main(int argc, char **argv)
626 626
627 /* These are optional */ 627 /* These are optional */
628 /* Exclude or Include files listed in <filename>*/ 628 /* Exclude or Include files listed in <filename>*/
629#ifdef BB_FEATURE_TAR_EXCLUDE 629#ifdef CONFIG_FEATURE_TAR_EXCLUDE
630 case 'X': 630 case 'X':
631 append_file_list_to_list(optarg, &exclude_list, &exclude_list_count); 631 append_file_list_to_list(optarg, &exclude_list, &exclude_list_count);
632 break; 632 break;
@@ -660,7 +660,7 @@ int tar_main(int argc, char **argv)
660 } 660 }
661 extract_function |= extract_list; 661 extract_function |= extract_list;
662 break; 662 break;
663#ifdef BB_FEATURE_TAR_GZIP 663#ifdef CONFIG_FEATURE_TAR_GZIP
664 case 'z': 664 case 'z':
665 untar_funct |= untar_unzip; 665 untar_funct |= untar_unzip;
666 break; 666 break;
@@ -698,43 +698,43 @@ int tar_main(int argc, char **argv)
698 } else { 698 } else {
699 src_stream = stdin; 699 src_stream = stdin;
700 } 700 }
701#ifdef BB_FEATURE_TAR_GZIP 701#ifdef CONFIG_FEATURE_TAR_GZIP
702 /* Get a binary tree of all the tar file headers */ 702 /* Get a binary tree of all the tar file headers */
703 if (untar_funct & untar_unzip) { 703 if (untar_funct & untar_unzip) {
704 uncompressed_stream = gz_open(src_stream, &gunzip_pid); 704 uncompressed_stream = gz_open(src_stream, &gunzip_pid);
705 } else 705 } else
706#endif // BB_FEATURE_TAR_GZIP 706#endif // CONFIG_FEATURE_TAR_GZIP
707 uncompressed_stream = src_stream; 707 uncompressed_stream = src_stream;
708 708
709 /* extract or list archive */ 709 /* extract or list archive */
710 unarchive(uncompressed_stream, stdout, &get_header_tar, extract_function, dst_prefix, include_list, exclude_list); 710 unarchive(uncompressed_stream, stdout, &get_header_tar, extract_function, dst_prefix, include_list, exclude_list);
711 fclose(uncompressed_stream); 711 fclose(uncompressed_stream);
712 } 712 }
713#ifdef BB_FEATURE_TAR_CREATE 713#ifdef CONFIG_FEATURE_TAR_CREATE
714 /* create an archive */ 714 /* create an archive */
715 else if (untar_funct & untar_create) { 715 else if (untar_funct & untar_create) {
716 int verboseFlag = FALSE; 716 int verboseFlag = FALSE;
717 717
718#ifdef BB_FEATURE_TAR_GZIP 718#ifdef CONFIG_FEATURE_TAR_GZIP
719 if (untar_funct && untar_unzip) { 719 if (untar_funct && untar_unzip) {
720 error_msg_and_die("Creation of compressed tarfile not internally support by tar, pipe to busybox gunzip"); 720 error_msg_and_die("Creation of compressed tarfile not internally support by tar, pipe to busybox gunzip");
721 } 721 }
722#endif // BB_FEATURE_TAR_GZIP 722#endif // CONFIG_FEATURE_TAR_GZIP
723 if (extract_function & extract_verbose_list) { 723 if (extract_function & extract_verbose_list) {
724 verboseFlag = TRUE; 724 verboseFlag = TRUE;
725 } 725 }
726 writeTarFile(src_filename, verboseFlag, &argv[argc - 1], include_list); 726 writeTarFile(src_filename, verboseFlag, &argv[argc - 1], include_list);
727 } 727 }
728#endif // BB_FEATURE_TAR_CREATE 728#endif // CONFIG_FEATURE_TAR_CREATE
729 729
730 /* Cleanups */ 730 /* Cleanups */
731#ifdef BB_FEATURE_TAR_GZIP 731#ifdef CONFIG_FEATURE_TAR_GZIP
732 if (untar_funct & untar_unzip) { 732 if (untar_funct & untar_unzip) {
733 fclose(src_stream); 733 fclose(src_stream);
734 close(gz_fd); 734 close(gz_fd);
735 gz_close(gunzip_pid); 735 gz_close(gunzip_pid);
736 } 736 }
737#endif // BB_FEATURE_TAR_GZIP 737#endif // CONFIG_FEATURE_TAR_GZIP
738 if (src_filename) { 738 if (src_filename) {
739 free(src_filename); 739 free(src_filename);
740 } 740 }
diff --git a/ash.c b/ash.c
deleted file mode 100644
index 486386a25..000000000
--- a/ash.c
+++ /dev/null
@@ -1,12825 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
27 *
28 * Modified by Erik Andersen <andersee@debian.org> and
29 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
30 *
31 *
32 * Original copyright notice is retained at the end of this file.
33 */
34
35
36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
39 * 60k to busybox on an x86 system.*/
40
41
42/* Enable job control. This allows you to run jobs in the background,
43 * which is great when ash is being used as an interactive shell, but
44 * it completely useless for is all you are doing is running scripts.
45 * This adds about 2.5k on an x86 system. */
46#undef JOBS
47
48/* This enables alias support in ash. If you want to support things
49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
50 * when ash is used as an intractive shell. This adds about 1.5k */
51#define ASH_ALIAS
52
53/* If you need ash to act as a full Posix shell, with full math
54 * support, enable this. This adds a bit over 2k an x86 system. */
55//#undef ASH_MATH_SUPPORT
56#define ASH_MATH_SUPPORT
57
58/* Getopts is used by shell procedures to parse positional parameters.
59 * You probably want to leave this disabled, and use the busybox getopt
60 * applet if you want to do this sort of thing. There are some scripts
61 * out there that use it, so it you need it, enable. Most people will
62 * leave this disabled. This adds 1k on an x86 system. */
63#undef ASH_GETOPTS
64
65/* This allows you to override shell builtins and use whatever is on
66 * the filesystem. This is most useful when ash is acting as a
67 * standalone shell. Adds about 272 bytes. */
68#undef ASH_CMDCMD
69
70
71/* Optimize size vs speed as size */
72#define ASH_OPTIMIZE_FOR_SIZE
73
74/* Enable this to compile in extra debugging noise. When debugging is
75 * on, debugging info will be written to $HOME/trace and a quit signal
76 * will generate a core dump. */
77#undef DEBUG
78
79/* These are here to work with glibc -- Don't change these... */
80#undef FNMATCH_BROKEN
81#undef GLOB_BROKEN
82#define IFS_BROKEN
83
84#include <assert.h>
85#include <stddef.h>
86#include <ctype.h>
87#include <dirent.h>
88#include <errno.h>
89#include <fcntl.h>
90#include <limits.h>
91#include <paths.h>
92#include <pwd.h>
93#include <setjmp.h>
94#include <signal.h>
95#include <stdarg.h>
96#include <stdio.h>
97#include <stdlib.h>
98#include <string.h>
99#include <sysexits.h>
100#include <unistd.h>
101#include <sys/stat.h>
102#include <sys/cdefs.h>
103#include <sys/ioctl.h>
104#include <sys/param.h>
105#include <sys/resource.h>
106#include <sys/time.h>
107#include <sys/times.h>
108#include <sys/types.h>
109#include <sys/wait.h>
110
111
112#if !defined(FNMATCH_BROKEN)
113#include <fnmatch.h>
114#endif
115#if !defined(GLOB_BROKEN)
116#include <glob.h>
117#endif
118
119#ifdef JOBS
120#include <termios.h>
121#endif
122
123#include "busybox.h"
124#include "cmdedit.h"
125
126/*
127 * This file was generated by the mksyntax program.
128 */
129
130/* Syntax classes */
131#define CWORD 0 /* character is nothing special */
132#define CNL 1 /* newline character */
133#define CBACK 2 /* a backslash character */
134#define CSQUOTE 3 /* single quote */
135#define CDQUOTE 4 /* double quote */
136#define CENDQUOTE 5 /* a terminating quote */
137#define CBQUOTE 6 /* backwards single quote */
138#define CVAR 7 /* a dollar sign */
139#define CENDVAR 8 /* a '}' character */
140#define CLP 9 /* a left paren in arithmetic */
141#define CRP 10 /* a right paren in arithmetic */
142#define CENDFILE 11 /* end of file */
143#define CCTL 12 /* like CWORD, except it must be escaped */
144#define CSPCL 13 /* these terminate a word */
145#define CIGN 14 /* character should be ignored */
146
147#define SYNBASE 130
148#define PEOF -130
149
150#define PEOA -129
151
152#define TEOF 0
153#define TNL 1
154#define TREDIR 2
155#define TWORD 3
156#define TASSIGN 4
157#define TSEMI 5
158#define TBACKGND 6
159#define TAND 7
160#define TOR 8
161#define TPIPE 9
162#define TLP 10
163#define TRP 11
164#define TENDCASE 12
165#define TENDBQUOTE 13
166#define TNOT 14
167#define TCASE 15
168#define TDO 16
169#define TDONE 17
170#define TELIF 18
171#define TELSE 19
172#define TESAC 20
173#define TFI 21
174#define TFOR 22
175#define TIF 23
176#define TIN 24
177#define TTHEN 25
178#define TUNTIL 26
179#define TWHILE 27
180#define TBEGIN 28
181#define TEND 29
182
183
184
185/* control characters in argument strings */
186#define CTLESC '\201'
187#define CTLVAR '\202'
188#define CTLENDVAR '\203'
189#define CTLBACKQ '\204'
190#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
191/* CTLBACKQ | CTLQUOTE == '\205' */
192#define CTLARI '\206'
193#define CTLENDARI '\207'
194#define CTLQUOTEMARK '\210'
195
196
197#define is_digit(c) ((c)>='0' && (c)<='9')
198#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
199#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
200
201/*
202 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
203 * (assuming ascii char codes, as the original implementation did)
204 */
205#define is_special(c) \
206 ( (((unsigned int)c) - 33 < 32) \
207 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
208
209#define digit_val(c) ((c) - '0')
210
211
212#define _DIAGASSERT(x)
213
214
215
216#define S_DFL 1 /* default signal handling (SIG_DFL) */
217#define S_CATCH 2 /* signal is caught */
218#define S_IGN 3 /* signal is ignored (SIG_IGN) */
219#define S_HARD_IGN 4 /* signal is ignored permenantly */
220#define S_RESET 5 /* temporary - to reset a hard ignored sig */
221
222
223/* variable substitution byte (follows CTLVAR) */
224#define VSTYPE 0x0f /* type of variable substitution */
225#define VSNUL 0x10 /* colon--treat the empty string as unset */
226#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
227
228/* values of VSTYPE field */
229#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
230#define VSMINUS 0x2 /* ${var-text} */
231#define VSPLUS 0x3 /* ${var+text} */
232#define VSQUESTION 0x4 /* ${var?message} */
233#define VSASSIGN 0x5 /* ${var=text} */
234#define VSTRIMLEFT 0x6 /* ${var#pattern} */
235#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
236#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
237#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
238#define VSLENGTH 0xa /* ${#var} */
239
240/* flags passed to redirect */
241#define REDIR_PUSH 01 /* save previous values of file descriptors */
242#define REDIR_BACKQ 02 /* save the command output to pipe */
243
244/*
245 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
246 * so we use _setjmp instead.
247 */
248
249#if defined(BSD)
250#define setjmp(jmploc) _setjmp(jmploc)
251#define longjmp(jmploc, val) _longjmp(jmploc, val)
252#endif
253
254/*
255 * Most machines require the value returned from malloc to be aligned
256 * in some way. The following macro will get this right on many machines.
257 */
258
259#ifndef ALIGN
260union align {
261 int i;
262 char *cp;
263};
264
265#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
266#endif
267
268#ifdef BB_LOCALE_SUPPORT
269#include <locale.h>
270static void change_lc_all(const char *value);
271static void change_lc_ctype(const char *value);
272#endif
273
274/*
275 * These macros allow the user to suspend the handling of interrupt signals
276 * over a period of time. This is similar to SIGHOLD to or sigblock, but
277 * much more efficient and portable. (But hacking the kernel is so much
278 * more fun than worrying about efficiency and portability. :-))
279 */
280
281static void onint (void);
282static volatile int suppressint;
283static volatile int intpending;
284
285#define INTOFF suppressint++
286#ifndef ASH_OPTIMIZE_FOR_SIZE
287#define INTON { if (--suppressint == 0 && intpending) onint(); }
288#define FORCEINTON {suppressint = 0; if (intpending) onint();}
289#else
290static void __inton (void);
291static void forceinton (void);
292#define INTON __inton()
293#define FORCEINTON forceinton()
294#endif
295
296#define CLEAR_PENDING_INT intpending = 0
297#define int_pending() intpending
298
299
300typedef void *pointer;
301#ifndef NULL
302#define NULL (void *)0
303#endif
304
305static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
306static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
307static inline char * savestr (const char *s) { return xstrdup(s); }
308
309static pointer stalloc (int);
310static void stunalloc (pointer);
311static void ungrabstackstr (char *, char *);
312static char * growstackstr(void);
313static char * makestrspace(size_t newlen);
314static char *sstrdup (const char *);
315
316/*
317 * Parse trees for commands are allocated in lifo order, so we use a stack
318 * to make this more efficient, and also to avoid all sorts of exception
319 * handling code to handle interrupts in the middle of a parse.
320 *
321 * The size 504 was chosen because the Ultrix malloc handles that size
322 * well.
323 */
324
325#define MINSIZE 504 /* minimum size of a block */
326
327
328struct stack_block {
329 struct stack_block *prev;
330 char space[MINSIZE];
331};
332
333static struct stack_block stackbase;
334static struct stack_block *stackp = &stackbase;
335static struct stackmark *markp;
336static char *stacknxt = stackbase.space;
337static int stacknleft = MINSIZE;
338
339
340#define equal(s1, s2) (strcmp(s1, s2) == 0)
341
342#define stackblock() stacknxt
343#define stackblocksize() stacknleft
344#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
345
346#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
347#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
348#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
349
350
351#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
352#define STUNPUTC(p) (++sstrnleft, --p)
353#define STTOPC(p) p[-1]
354#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
355#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
356
357#define ckfree(p) free((pointer)(p))
358
359
360#ifdef DEBUG
361#define TRACE(param) trace param
362static void trace (const char *, ...);
363static void trargs (char **);
364static void showtree (union node *);
365static void trputc (int);
366static void trputs (const char *);
367static void opentrace (void);
368#else
369#define TRACE(param)
370#endif
371
372#define NSEMI 0
373#define NCMD 1
374#define NPIPE 2
375#define NREDIR 3
376#define NBACKGND 4
377#define NSUBSHELL 5
378#define NAND 6
379#define NOR 7
380#define NIF 8
381#define NWHILE 9
382#define NUNTIL 10
383#define NFOR 11
384#define NCASE 12
385#define NCLIST 13
386#define NDEFUN 14
387#define NARG 15
388#define NTO 16
389#define NFROM 17
390#define NFROMTO 18
391#define NAPPEND 19
392#define NTOOV 20
393#define NTOFD 21
394#define NFROMFD 22
395#define NHERE 23
396#define NXHERE 24
397#define NNOT 25
398
399/*
400 * expandarg() flags
401 */
402#define EXP_FULL 0x1 /* perform word splitting & file globbing */
403#define EXP_TILDE 0x2 /* do normal tilde expansion */
404#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
405#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
406#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
407#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
408
409
410#define NOPTS 16
411
412static char optet_vals[NOPTS];
413
414static const char * const optlist[NOPTS] = {
415 "e" "errexit",
416 "f" "noglob",
417 "I" "ignoreeof",
418 "i" "interactive",
419 "m" "monitor",
420 "n" "noexec",
421 "s" "stdin",
422 "x" "xtrace",
423 "v" "verbose",
424 "V" "vi",
425 "E" "emacs",
426 "C" "noclobber",
427 "a" "allexport",
428 "b" "notify",
429 "u" "nounset",
430 "q" "quietprofile"
431};
432
433#define optent_name(optent) (optent+1)
434#define optent_letter(optent) optent[0]
435#define optent_val(optent) optet_vals[optent]
436
437#define eflag optent_val(0)
438#define fflag optent_val(1)
439#define Iflag optent_val(2)
440#define iflag optent_val(3)
441#define mflag optent_val(4)
442#define nflag optent_val(5)
443#define sflag optent_val(6)
444#define xflag optent_val(7)
445#define vflag optent_val(8)
446#define Vflag optent_val(9)
447#define Eflag optent_val(10)
448#define Cflag optent_val(11)
449#define aflag optent_val(12)
450#define bflag optent_val(13)
451#define uflag optent_val(14)
452#define qflag optent_val(15)
453
454
455/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
456#define FORK_FG 0
457#define FORK_BG 1
458#define FORK_NOJOB 2
459
460
461struct nbinary {
462 int type;
463 union node *ch1;
464 union node *ch2;
465};
466
467
468struct ncmd {
469 int type;
470 int backgnd;
471 union node *assign;
472 union node *args;
473 union node *redirect;
474};
475
476
477struct npipe {
478 int type;
479 int backgnd;
480 struct nodelist *cmdlist;
481};
482
483
484struct nredir {
485 int type;
486 union node *n;
487 union node *redirect;
488};
489
490
491struct nif {
492 int type;
493 union node *test;
494 union node *ifpart;
495 union node *elsepart;
496};
497
498
499struct nfor {
500 int type;
501 union node *args;
502 union node *body;
503 char *var;
504};
505
506
507struct ncase {
508 int type;
509 union node *expr;
510 union node *cases;
511};
512
513
514struct nclist {
515 int type;
516 union node *next;
517 union node *pattern;
518 union node *body;
519};
520
521
522struct narg {
523 int type;
524 union node *next;
525 char *text;
526 struct nodelist *backquote;
527};
528
529
530struct nfile {
531 int type;
532 union node *next;
533 int fd;
534 union node *fname;
535 char *expfname;
536};
537
538
539struct ndup {
540 int type;
541 union node *next;
542 int fd;
543 int dupfd;
544 union node *vname;
545};
546
547
548struct nhere {
549 int type;
550 union node *next;
551 int fd;
552 union node *doc;
553};
554
555
556struct nnot {
557 int type;
558 union node *com;
559};
560
561
562union node {
563 int type;
564 struct nbinary nbinary;
565 struct ncmd ncmd;
566 struct npipe npipe;
567 struct nredir nredir;
568 struct nif nif;
569 struct nfor nfor;
570 struct ncase ncase;
571 struct nclist nclist;
572 struct narg narg;
573 struct nfile nfile;
574 struct ndup ndup;
575 struct nhere nhere;
576 struct nnot nnot;
577};
578
579
580struct nodelist {
581 struct nodelist *next;
582 union node *n;
583};
584
585struct backcmd { /* result of evalbackcmd */
586 int fd; /* file descriptor to read from */
587 char *buf; /* buffer */
588 int nleft; /* number of chars in buffer */
589 struct job *jp; /* job structure for command */
590};
591
592struct cmdentry {
593 int cmdtype;
594 union param {
595 int index;
596 union node *func;
597 const struct builtincmd *cmd;
598 } u;
599};
600
601struct strlist {
602 struct strlist *next;
603 char *text;
604};
605
606
607struct arglist {
608 struct strlist *list;
609 struct strlist **lastp;
610};
611
612struct strpush {
613 struct strpush *prev; /* preceding string on stack */
614 char *prevstring;
615 int prevnleft;
616#ifdef ASH_ALIAS
617 struct alias *ap; /* if push was associated with an alias */
618#endif
619 char *string; /* remember the string since it may change */
620};
621
622struct parsefile {
623 struct parsefile *prev; /* preceding file on stack */
624 int linno; /* current line */
625 int fd; /* file descriptor (or -1 if string) */
626 int nleft; /* number of chars left in this line */
627 int lleft; /* number of chars left in this buffer */
628 char *nextc; /* next char in buffer */
629 char *buf; /* input buffer */
630 struct strpush *strpush; /* for pushing strings at this level */
631 struct strpush basestrpush; /* so pushing one is fast */
632};
633
634struct stackmark {
635 struct stack_block *stackp;
636 char *stacknxt;
637 int stacknleft;
638 struct stackmark *marknext;
639};
640
641struct shparam {
642 int nparam; /* # of positional parameters (without $0) */
643 unsigned char malloc; /* if parameter list dynamically allocated */
644 char **p; /* parameter list */
645 int optind; /* next parameter to be processed by getopts */
646 int optoff; /* used by getopts */
647};
648
649/*
650 * When commands are first encountered, they are entered in a hash table.
651 * This ensures that a full path search will not have to be done for them
652 * on each invocation.
653 *
654 * We should investigate converting to a linear search, even though that
655 * would make the command name "hash" a misnomer.
656 */
657#define CMDTABLESIZE 31 /* should be prime */
658#define ARB 1 /* actual size determined at run time */
659
660
661
662struct tblentry {
663 struct tblentry *next; /* next entry in hash chain */
664 union param param; /* definition of builtin function */
665 short cmdtype; /* index identifying command */
666 char rehash; /* if set, cd done since entry created */
667 char cmdname[ARB]; /* name of command */
668};
669
670
671static struct tblentry *cmdtable[CMDTABLESIZE];
672static int builtinloc = -1; /* index in path of %builtin, or -1 */
673static int exerrno = 0; /* Last exec error */
674
675
676static void tryexec (char *, char **, char **);
677static void printentry (struct tblentry *, int);
678static void clearcmdentry (int);
679static struct tblentry *cmdlookup (const char *, int);
680static void delete_cmd_entry (void);
681static int path_change (const char *, int *);
682
683
684static void flushall (void);
685static void out2fmt (const char *, ...)
686 __attribute__((__format__(__printf__,1,2)));
687static int xwrite (int, const char *, int);
688
689static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
690static void out1str(const char *p) { outstr(p, stdout); }
691static void out2str(const char *p) { outstr(p, stderr); }
692
693#ifndef ASH_OPTIMIZE_FOR_SIZE
694#define out2c(c) putc((c), stderr)
695#else
696static void out2c(int c) { putc(c, stderr); }
697#endif
698
699
700#ifdef ASH_OPTIMIZE_FOR_SIZE
701#define USE_SIT_FUNCTION
702#endif
703
704/* number syntax index */
705#define BASESYNTAX 0 /* not in quotes */
706#define DQSYNTAX 1 /* in double quotes */
707#define SQSYNTAX 2 /* in single quotes */
708#define ARISYNTAX 3 /* in arithmetic */
709
710static const char S_I_T[][4] = {
711 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
712 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
713 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
714 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
715 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
716 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
717 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
718 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
719 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
720 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
721 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
722 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
723#ifndef USE_SIT_FUNCTION
724 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
725 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
726 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
727#endif
728};
729
730#ifdef USE_SIT_FUNCTION
731
732#define U_C(c) ((unsigned char)(c))
733
734static int SIT(int c, int syntax)
735{
736 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
737 static const char syntax_index_table [] = {
738 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
739 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
740 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
741 11,3 }; /* "}~" */
742 const char *s;
743 int indx;
744
745 if(c==PEOF) /* 2^8+2 */
746 return CENDFILE;
747 if(c==PEOA) /* 2^8+1 */
748 indx = 0;
749 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
750 return CCTL;
751 else {
752 s = strchr(spec_symbls, c);
753 if(s==0)
754 return CWORD;
755 indx = syntax_index_table[(s-spec_symbls)];
756 }
757 return S_I_T[indx][syntax];
758}
759
760#else /* USE_SIT_FUNCTION */
761
762#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
763
764#define CSPCL_CIGN_CIGN_CIGN 0
765#define CSPCL_CWORD_CWORD_CWORD 1
766#define CNL_CNL_CNL_CNL 2
767#define CWORD_CCTL_CCTL_CWORD 3
768#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
769#define CVAR_CVAR_CWORD_CVAR 5
770#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
771#define CSPCL_CWORD_CWORD_CLP 7
772#define CSPCL_CWORD_CWORD_CRP 8
773#define CBACK_CBACK_CCTL_CBACK 9
774#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
775#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
776#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
777#define CWORD_CWORD_CWORD_CWORD 13
778#define CCTL_CCTL_CCTL_CCTL 14
779
780static const char syntax_index_table[258] = {
781 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
782 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
783 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
784 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
785 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
786 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
787 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
788 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
789 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
790 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
791 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
792 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
793 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
794 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
795 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
796 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
797 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
798 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
799 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
800 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
801 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
802 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
803 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
804 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
805 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
806 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
807 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
808 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
809 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
810 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
811 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
812 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
813 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
814 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
815 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
816 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
817 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
818 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
819 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
820 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
821 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
822 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
823 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
824 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
825 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
826 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
827 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
828 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
829 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
830 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
831 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
832 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
833 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
834 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
835 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
836 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
837 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
838 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
839 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
840 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
841 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
842 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
843 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
844 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
845 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
846 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
847 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
848 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
849 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
850 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
851 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
852 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
853 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
854 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
855 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
856 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
857 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
858 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
859 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
860 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
861 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
862 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
863 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
864 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
865 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
866 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
867 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
868 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
869 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
870 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
871 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
872 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
873 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
874 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
875 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
876 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
877 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
878 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
879 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
880 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
881 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
882 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
883 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
884 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
885 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
886 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
887 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
888 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
889 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
890 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
891 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
892 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
893 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
894 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
895 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
896 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
897 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
898 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
899 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
900 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
901 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
902 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
903 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
904 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
905 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
906 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
907 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
908 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
909 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
910 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
911 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
912 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
913 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
914 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
915 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
916 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
917 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
918 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
919 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
920 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
921 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
922 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
923 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
924 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
925 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
926 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
927 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
928 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
929 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
930 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
931 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
932 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
933 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
934 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
935 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
936 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
937 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
938 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
939 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
940 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
941 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
942 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
943 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
944 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
945 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
946 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
947 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
948 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
949 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
950 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
951 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
952 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
953 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
954 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
955 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
956 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
957 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
958 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
959 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
960 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
961 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
962 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
963 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
964 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
965 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
966 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
967 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
968 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
969 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
970 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
971 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
972 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
973 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
974 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
975 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
976 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
977 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
978 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
979 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
980 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
981 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
982 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
983 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
984 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
985 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
986 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
987 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
988 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
989 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
990 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
991 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
992 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
993 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
994 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
995 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
996 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
997 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
998 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
999 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1000 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1001 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1003 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1004 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1005 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1006 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1007 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1008 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1009 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1010 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1011 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1012 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1013 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1014 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1015 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1016 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1017 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1018 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1019 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1020 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1021 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1022 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1023 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1024 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1025 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1026 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1027 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1028 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1029 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1030 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1031 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1032 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1033 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1034 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1035 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1036 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1037 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1038 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1039 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1040};
1041
1042#endif /* USE_SIT_FUNCTION */
1043
1044
1045/* first char is indicating which tokens mark the end of a list */
1046static const char *const tokname_array[] = {
1047 "\1end of file",
1048 "\0newline",
1049 "\0redirection",
1050 "\0word",
1051 "\0assignment",
1052 "\0;",
1053 "\0&",
1054 "\0&&",
1055 "\0||",
1056 "\0|",
1057 "\0(",
1058 "\1)",
1059 "\1;;",
1060 "\1`",
1061#define KWDOFFSET 14
1062 /* the following are keywords */
1063 "\0!",
1064 "\0case",
1065 "\1do",
1066 "\1done",
1067 "\1elif",
1068 "\1else",
1069 "\1esac",
1070 "\1fi",
1071 "\0for",
1072 "\0if",
1073 "\0in",
1074 "\1then",
1075 "\0until",
1076 "\0while",
1077 "\0{",
1078 "\1}",
1079};
1080
1081static const char *tokname(int tok)
1082{
1083 static char buf[16];
1084
1085 if(tok>=TSEMI)
1086 buf[0] = '"';
1087 sprintf(buf+(tok>=TSEMI), "%s%c",
1088 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1089 return buf;
1090}
1091
1092static int plinno = 1; /* input line number */
1093
1094static int parselleft; /* copy of parsefile->lleft */
1095
1096static struct parsefile basepf; /* top level input file */
1097static char basebuf[BUFSIZ]; /* buffer for top level input file */
1098static struct parsefile *parsefile = &basepf; /* current input file */
1099
1100/*
1101 * NEOF is returned by parsecmd when it encounters an end of file. It
1102 * must be distinct from NULL, so we use the address of a variable that
1103 * happens to be handy.
1104 */
1105
1106static int tokpushback; /* last token pushed back */
1107#define NEOF ((union node *)&tokpushback)
1108static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1109
1110
1111static void error (const char *, ...) __attribute__((__noreturn__));
1112static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1113static void shellexec (char **, char **, const char *, int)
1114 __attribute__((noreturn));
1115static void exitshell (int) __attribute__((noreturn));
1116
1117static int goodname(const char *);
1118static void ignoresig (int);
1119static void onsig (int);
1120static void dotrap (void);
1121static int decode_signal (const char *, int);
1122
1123static void shprocvar(void);
1124static void deletefuncs(void);
1125static void setparam (char **);
1126static void freeparam (volatile struct shparam *);
1127
1128/* reasons for skipping commands (see comment on breakcmd routine) */
1129#define SKIPBREAK 1
1130#define SKIPCONT 2
1131#define SKIPFUNC 3
1132#define SKIPFILE 4
1133
1134/* values of cmdtype */
1135#define CMDUNKNOWN -1 /* no entry in table for command */
1136#define CMDNORMAL 0 /* command is an executable program */
1137#define CMDBUILTIN 1 /* command is a shell builtin */
1138#define CMDFUNCTION 2 /* command is a shell function */
1139
1140#define DO_ERR 1 /* find_command prints errors */
1141#define DO_ABS 2 /* find_command checks absolute paths */
1142#define DO_NOFUN 4 /* find_command ignores functions */
1143#define DO_BRUTE 8 /* find_command ignores hash table */
1144
1145/*
1146 * Shell variables.
1147 */
1148
1149/* flags */
1150#define VEXPORT 0x01 /* variable is exported */
1151#define VREADONLY 0x02 /* variable cannot be modified */
1152#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1153#define VTEXTFIXED 0x08 /* text is staticly allocated */
1154#define VSTACK 0x10 /* text is allocated on the stack */
1155#define VUNSET 0x20 /* the variable is not set */
1156#define VNOFUNC 0x40 /* don't call the callback function */
1157
1158
1159struct var {
1160 struct var *next; /* next entry in hash list */
1161 int flags; /* flags are defined above */
1162 char *text; /* name=value */
1163 void (*func) (const char *);
1164 /* function to be called when */
1165 /* the variable gets set/unset */
1166};
1167
1168struct localvar {
1169 struct localvar *next; /* next local variable in list */
1170 struct var *vp; /* the variable that was made local */
1171 int flags; /* saved flags */
1172 char *text; /* saved text */
1173};
1174
1175
1176#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
1177#define rmescapes(p) _rmescapes((p), 0)
1178static char *_rmescapes (char *, int);
1179#else
1180static void rmescapes (char *);
1181#endif
1182
1183static int casematch (union node *, const char *);
1184static void clearredir(void);
1185static void popstring(void);
1186static void readcmdfile (const char *);
1187
1188static int number (const char *);
1189static int is_number (const char *, int *num);
1190static char *single_quote (const char *);
1191static int nextopt (const char *);
1192
1193static void redirect (union node *, int);
1194static void popredir (void);
1195static int dup_as_newfd (int, int);
1196
1197static void changepath(const char *newval);
1198static void getoptsreset(const char *value);
1199
1200
1201static int parsenleft; /* copy of parsefile->nleft */
1202static char *parsenextc; /* copy of parsefile->nextc */
1203static int rootpid; /* pid of main shell */
1204static int rootshell; /* true if we aren't a child of the main shell */
1205
1206static const char spcstr[] = " ";
1207static const char snlfmt[] = "%s\n";
1208
1209static int sstrnleft;
1210static int herefd = -1;
1211
1212static struct localvar *localvars;
1213
1214static struct var vifs;
1215static struct var vmail;
1216static struct var vmpath;
1217static struct var vpath;
1218static struct var vps1;
1219static struct var vps2;
1220static struct var voptind;
1221#ifdef BB_LOCALE_SUPPORT
1222static struct var vlc_all;
1223static struct var vlc_ctype;
1224#endif
1225
1226struct varinit {
1227 struct var *var;
1228 int flags;
1229 const char *text;
1230 void (*func) (const char *);
1231};
1232
1233static const char defpathvar[] =
1234 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1235#define defpath (defpathvar + 5)
1236
1237#ifdef IFS_BROKEN
1238static const char defifsvar[] = "IFS= \t\n";
1239#define defifs (defifsvar + 4)
1240#else
1241static const char defifs[] = " \t\n";
1242#endif
1243
1244static const struct varinit varinit[] = {
1245#ifdef IFS_BROKEN
1246 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1247#else
1248 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1249#endif
1250 NULL },
1251 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1252 NULL },
1253 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1254 NULL },
1255 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1256 changepath },
1257 /*
1258 * vps1 depends on uid
1259 */
1260 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1261 NULL },
1262 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1263 getoptsreset },
1264#ifdef BB_LOCALE_SUPPORT
1265 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1266 change_lc_all },
1267 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1268 change_lc_ctype },
1269#endif
1270 { NULL, 0, NULL,
1271 NULL }
1272};
1273
1274#define VTABSIZE 39
1275
1276static struct var *vartab[VTABSIZE];
1277
1278/*
1279 * The following macros access the values of the above variables.
1280 * They have to skip over the name. They return the null string
1281 * for unset variables.
1282 */
1283
1284#define ifsval() (vifs.text + 4)
1285#define ifsset() ((vifs.flags & VUNSET) == 0)
1286#define mailval() (vmail.text + 5)
1287#define mpathval() (vmpath.text + 9)
1288#define pathval() (vpath.text + 5)
1289#define ps1val() (vps1.text + 4)
1290#define ps2val() (vps2.text + 4)
1291#define optindval() (voptind.text + 7)
1292
1293#define mpathset() ((vmpath.flags & VUNSET) == 0)
1294
1295static void initvar (void);
1296static void setvar (const char *, const char *, int);
1297static void setvareq (char *, int);
1298static void listsetvar (struct strlist *);
1299static const char *lookupvar (const char *);
1300static const char *bltinlookup (const char *);
1301static char **environment (void);
1302static int showvarscmd (int, char **);
1303static void mklocal (char *);
1304static void poplocalvars (void);
1305static int unsetvar (const char *);
1306static int varequal (const char *, const char *);
1307
1308
1309static char *arg0; /* value of $0 */
1310static struct shparam shellparam; /* current positional parameters */
1311static char **argptr; /* argument list for builtin commands */
1312static char *optionarg; /* set by nextopt (like getopt) */
1313static char *optptr; /* used by nextopt */
1314static char *minusc; /* argument to -c option */
1315
1316
1317#ifdef ASH_ALIAS
1318
1319#define ALIASINUSE 1
1320#define ALIASDEAD 2
1321
1322#define ATABSIZE 39
1323
1324struct alias {
1325 struct alias *next;
1326 char *name;
1327 char *val;
1328 int flag;
1329};
1330
1331static struct alias *atab[ATABSIZE];
1332
1333static void setalias (char *, char *);
1334static struct alias **hashalias (const char *);
1335static struct alias *freealias (struct alias *);
1336static struct alias **__lookupalias (const char *);
1337
1338static void
1339setalias(name, val)
1340 char *name, *val;
1341{
1342 struct alias *ap, **app;
1343
1344 app = __lookupalias(name);
1345 ap = *app;
1346 INTOFF;
1347 if (ap) {
1348 if (!(ap->flag & ALIASINUSE)) {
1349 ckfree(ap->val);
1350 }
1351 ap->val = savestr(val);
1352 ap->flag &= ~ALIASDEAD;
1353 } else {
1354 /* not found */
1355 ap = ckmalloc(sizeof (struct alias));
1356 ap->name = savestr(name);
1357 ap->val = savestr(val);
1358 ap->flag = 0;
1359 ap->next = 0;
1360 *app = ap;
1361 }
1362 INTON;
1363}
1364
1365static int
1366unalias(char *name)
1367{
1368 struct alias **app;
1369
1370 app = __lookupalias(name);
1371
1372 if (*app) {
1373 INTOFF;
1374 *app = freealias(*app);
1375 INTON;
1376 return (0);
1377 }
1378
1379 return (1);
1380}
1381
1382static void
1383rmaliases(void)
1384{
1385 struct alias *ap, **app;
1386 int i;
1387
1388 INTOFF;
1389 for (i = 0; i < ATABSIZE; i++) {
1390 app = &atab[i];
1391 for (ap = *app; ap; ap = *app) {
1392 *app = freealias(*app);
1393 if (ap == *app) {
1394 app = &ap->next;
1395 }
1396 }
1397 }
1398 INTON;
1399}
1400
1401static struct alias *
1402lookupalias(const char *name, int check)
1403{
1404 struct alias *ap = *__lookupalias(name);
1405
1406 if (check && ap && (ap->flag & ALIASINUSE))
1407 return (NULL);
1408 return (ap);
1409}
1410
1411static void
1412printalias(const struct alias *ap) {
1413 char *p;
1414
1415 p = single_quote(ap->val);
1416 printf("alias %s=%s\n", ap->name, p);
1417 stunalloc(p);
1418}
1419
1420
1421/*
1422 * TODO - sort output
1423 */
1424static int
1425aliascmd(int argc, char **argv)
1426{
1427 char *n, *v;
1428 int ret = 0;
1429 struct alias *ap;
1430
1431 if (argc == 1) {
1432 int i;
1433
1434 for (i = 0; i < ATABSIZE; i++)
1435 for (ap = atab[i]; ap; ap = ap->next) {
1436 printalias(ap);
1437 }
1438 return (0);
1439 }
1440 while ((n = *++argv) != NULL) {
1441 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1442 if ((ap = *__lookupalias(n)) == NULL) {
1443 out2fmt("%s: %s not found\n", "alias", n);
1444 ret = 1;
1445 } else
1446 printalias(ap);
1447 }
1448 else {
1449 *v++ = '\0';
1450 setalias(n, v);
1451 }
1452 }
1453
1454 return (ret);
1455}
1456
1457static int
1458unaliascmd(int argc, char **argv)
1459{
1460 int i;
1461
1462 while ((i = nextopt("a")) != '\0') {
1463 if (i == 'a') {
1464 rmaliases();
1465 return (0);
1466 }
1467 }
1468 for (i = 0; *argptr; argptr++) {
1469 if (unalias(*argptr)) {
1470 out2fmt("%s: %s not found\n", "unalias", *argptr);
1471 i = 1;
1472 }
1473 }
1474
1475 return (i);
1476}
1477
1478static struct alias **
1479hashalias(p)
1480 const char *p;
1481 {
1482 unsigned int hashval;
1483
1484 hashval = *p << 4;
1485 while (*p)
1486 hashval+= *p++;
1487 return &atab[hashval % ATABSIZE];
1488}
1489
1490static struct alias *
1491freealias(struct alias *ap) {
1492 struct alias *next;
1493
1494 if (ap->flag & ALIASINUSE) {
1495 ap->flag |= ALIASDEAD;
1496 return ap;
1497 }
1498
1499 next = ap->next;
1500 ckfree(ap->name);
1501 ckfree(ap->val);
1502 ckfree(ap);
1503 return next;
1504}
1505
1506
1507static struct alias **
1508__lookupalias(const char *name) {
1509 struct alias **app = hashalias(name);
1510
1511 for (; *app; app = &(*app)->next) {
1512 if (equal(name, (*app)->name)) {
1513 break;
1514 }
1515 }
1516
1517 return app;
1518}
1519#endif
1520
1521#ifdef ASH_MATH_SUPPORT
1522/* The generated file arith.c has been replaced with a custom hand
1523 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1524 * This is now part of libbb, so that it can be used by all the shells
1525 * in busybox. */
1526static void expari (int);
1527#endif
1528
1529static char *trap[NSIG]; /* trap handler commands */
1530static char sigmode[NSIG - 1]; /* current value of signal */
1531static char gotsig[NSIG - 1]; /* indicates specified signal received */
1532static int pendingsigs; /* indicates some signal received */
1533
1534/*
1535 * This file was generated by the mkbuiltins program.
1536 */
1537
1538#ifdef JOBS
1539static int bgcmd (int, char **);
1540static int fgcmd (int, char **);
1541static int killcmd (int, char **);
1542#endif
1543static int bltincmd (int, char **);
1544static int cdcmd (int, char **);
1545static int breakcmd (int, char **);
1546#ifdef ASH_CMDCMD
1547static int commandcmd (int, char **);
1548#endif
1549static int dotcmd (int, char **);
1550static int evalcmd (int, char **);
1551static int execcmd (int, char **);
1552static int exitcmd (int, char **);
1553static int exportcmd (int, char **);
1554static int histcmd (int, char **);
1555static int hashcmd (int, char **);
1556static int helpcmd (int, char **);
1557static int jobscmd (int, char **);
1558static int localcmd (int, char **);
1559#ifndef BB_PWD
1560static int pwdcmd (int, char **);
1561#endif
1562static int readcmd (int, char **);
1563static int returncmd (int, char **);
1564static int setcmd (int, char **);
1565static int setvarcmd (int, char **);
1566static int shiftcmd (int, char **);
1567static int trapcmd (int, char **);
1568static int umaskcmd (int, char **);
1569#ifdef ASH_ALIAS
1570static int aliascmd (int, char **);
1571static int unaliascmd (int, char **);
1572#endif
1573static int unsetcmd (int, char **);
1574static int waitcmd (int, char **);
1575static int ulimitcmd (int, char **);
1576static int timescmd (int, char **);
1577#ifdef ASH_MATH_SUPPORT
1578static int letcmd (int, char **);
1579#endif
1580static int typecmd (int, char **);
1581#ifdef ASH_GETOPTS
1582static int getoptscmd (int, char **);
1583#endif
1584
1585#ifndef BB_TRUE_FALSE
1586static int true_main (int, char **);
1587static int false_main (int, char **);
1588#endif
1589
1590static void setpwd (const char *, int);
1591
1592
1593#define BUILTIN_NOSPEC "0"
1594#define BUILTIN_SPECIAL "1"
1595#define BUILTIN_REGULAR "2"
1596#define BUILTIN_ASSIGN "4"
1597#define BUILTIN_SPEC_ASSG "5"
1598#define BUILTIN_REG_ASSG "6"
1599
1600#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1601#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1602#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1603
1604struct builtincmd {
1605 const char *name;
1606 int (*const builtinfunc) (int, char **);
1607 //unsigned flags;
1608};
1609
1610
1611/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1612 * the binary search in find_builtin() will stop working. If you value
1613 * your kneecaps, you'll be sure to *make sure* that any changes made
1614 * to this array result in the listing remaining in ascii order. You
1615 * have been warned.
1616 */
1617static const struct builtincmd builtincmds[] = {
1618 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
1619 { BUILTIN_SPECIAL ":", true_main },
1620#ifdef ASH_ALIAS
1621 { BUILTIN_REG_ASSG "alias", aliascmd },
1622#endif
1623#ifdef JOBS
1624 { BUILTIN_REGULAR "bg", bgcmd },
1625#endif
1626 { BUILTIN_SPECIAL "break", breakcmd },
1627 { BUILTIN_SPECIAL "builtin", bltincmd },
1628 { BUILTIN_REGULAR "cd", cdcmd },
1629 { BUILTIN_NOSPEC "chdir", cdcmd },
1630#ifdef ASH_CMDCMD
1631 { BUILTIN_REGULAR "command", commandcmd },
1632#endif
1633 { BUILTIN_SPECIAL "continue", breakcmd },
1634 { BUILTIN_SPECIAL "eval", evalcmd },
1635 { BUILTIN_SPECIAL "exec", execcmd },
1636 { BUILTIN_SPECIAL "exit", exitcmd },
1637 { BUILTIN_SPEC_ASSG "export", exportcmd },
1638 { BUILTIN_REGULAR "false", false_main },
1639 { BUILTIN_REGULAR "fc", histcmd },
1640#ifdef JOBS
1641 { BUILTIN_REGULAR "fg", fgcmd },
1642#endif
1643#ifdef ASH_GETOPTS
1644 { BUILTIN_REGULAR "getopts", getoptscmd },
1645#endif
1646 { BUILTIN_NOSPEC "hash", hashcmd },
1647 { BUILTIN_NOSPEC "help", helpcmd },
1648 { BUILTIN_REGULAR "jobs", jobscmd },
1649#ifdef JOBS
1650 { BUILTIN_REGULAR "kill", killcmd },
1651#endif
1652#ifdef ASH_MATH_SUPPORT
1653 { BUILTIN_REGULAR "let", letcmd },
1654#endif
1655 { BUILTIN_ASSIGN "local", localcmd },
1656#ifndef BB_PWD
1657 { BUILTIN_NOSPEC "pwd", pwdcmd },
1658#endif
1659 { BUILTIN_REGULAR "read", readcmd },
1660 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1661 { BUILTIN_SPECIAL "return", returncmd },
1662 { BUILTIN_SPECIAL "set", setcmd },
1663 { BUILTIN_NOSPEC "setvar", setvarcmd },
1664 { BUILTIN_SPECIAL "shift", shiftcmd },
1665 { BUILTIN_SPECIAL "times", timescmd },
1666 { BUILTIN_SPECIAL "trap", trapcmd },
1667 { BUILTIN_REGULAR "true", true_main },
1668 { BUILTIN_NOSPEC "type", typecmd },
1669 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1670 { BUILTIN_REGULAR "umask", umaskcmd },
1671#ifdef ASH_ALIAS
1672 { BUILTIN_REGULAR "unalias", unaliascmd },
1673#endif
1674 { BUILTIN_SPECIAL "unset", unsetcmd },
1675 { BUILTIN_REGULAR "wait", waitcmd },
1676};
1677#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1678
1679#define DOTCMD &builtincmds[0]
1680static struct builtincmd *BLTINCMD;
1681static struct builtincmd *EXECCMD;
1682static struct builtincmd *EVALCMD;
1683
1684/* states */
1685#define JOBSTOPPED 1 /* all procs are stopped */
1686#define JOBDONE 2 /* all procs are completed */
1687
1688/*
1689 * A job structure contains information about a job. A job is either a
1690 * single process or a set of processes contained in a pipeline. In the
1691 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1692 * array of pids.
1693 */
1694
1695struct procstat {
1696 pid_t pid; /* process id */
1697 int status; /* status flags (defined above) */
1698 char *cmd; /* text of command being run */
1699};
1700
1701
1702static int job_warning; /* user was warned about stopped jobs */
1703
1704#ifdef JOBS
1705static void setjobctl(int enable);
1706#else
1707#define setjobctl(on) /* do nothing */
1708#endif
1709
1710
1711struct job {
1712 struct procstat ps0; /* status of process */
1713 struct procstat *ps; /* status or processes when more than one */
1714 short nprocs; /* number of processes */
1715 short pgrp; /* process group of this job */
1716 char state; /* true if job is finished */
1717 char used; /* true if this entry is in used */
1718 char changed; /* true if status has changed */
1719#ifdef JOBS
1720 char jobctl; /* job running under job control */
1721#endif
1722};
1723
1724static struct job *jobtab; /* array of jobs */
1725static int njobs; /* size of array */
1726static int backgndpid = -1; /* pid of last background process */
1727#ifdef JOBS
1728static int initialpgrp; /* pgrp of shell on invocation */
1729static int curjob; /* current job */
1730static int jobctl;
1731#endif
1732static int intreceived;
1733
1734static struct job *makejob (const union node *, int);
1735static int forkshell (struct job *, const union node *, int);
1736static int waitforjob (struct job *);
1737
1738static int docd (char *, int);
1739static char *getcomponent (void);
1740static void updatepwd (const char *);
1741static void getpwd (void);
1742
1743static char *padvance (const char **, const char *);
1744
1745static char nullstr[1]; /* zero length string */
1746static char *curdir = nullstr; /* current working directory */
1747static char *cdcomppath;
1748
1749static int
1750cdcmd(argc, argv)
1751 int argc;
1752 char **argv;
1753{
1754 const char *dest;
1755 const char *path;
1756 char *p;
1757 struct stat statb;
1758 int print = 0;
1759
1760 nextopt(nullstr);
1761 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1762 error("HOME not set");
1763 if (*dest == '\0')
1764 dest = ".";
1765 if (dest[0] == '-' && dest[1] == '\0') {
1766 dest = bltinlookup("OLDPWD");
1767 if (!dest || !*dest) {
1768 dest = curdir;
1769 }
1770 print = 1;
1771 if (dest)
1772 print = 1;
1773 else
1774 dest = ".";
1775 }
1776 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1777 path = nullstr;
1778 while ((p = padvance(&path, dest)) != NULL) {
1779 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1780 if (!print) {
1781 /*
1782 * XXX - rethink
1783 */
1784 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1785 p += 2;
1786 print = strcmp(p, dest);
1787 }
1788 if (docd(p, print) >= 0)
1789 return 0;
1790
1791 }
1792 }
1793 error("can't cd to %s", dest);
1794 /* NOTREACHED */
1795}
1796
1797
1798/*
1799 * Actually do the chdir. In an interactive shell, print the
1800 * directory name if "print" is nonzero.
1801 */
1802
1803static int
1804docd(dest, print)
1805 char *dest;
1806 int print;
1807{
1808 char *p;
1809 char *q;
1810 char *component;
1811 struct stat statb;
1812 int first;
1813 int badstat;
1814
1815 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1816
1817 /*
1818 * Check each component of the path. If we find a symlink or
1819 * something we can't stat, clear curdir to force a getcwd()
1820 * next time we get the value of the current directory.
1821 */
1822 badstat = 0;
1823 cdcomppath = sstrdup(dest);
1824 STARTSTACKSTR(p);
1825 if (*dest == '/') {
1826 STPUTC('/', p);
1827 cdcomppath++;
1828 }
1829 first = 1;
1830 while ((q = getcomponent()) != NULL) {
1831 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1832 continue;
1833 if (! first)
1834 STPUTC('/', p);
1835 first = 0;
1836 component = q;
1837 while (*q)
1838 STPUTC(*q++, p);
1839 if (equal(component, ".."))
1840 continue;
1841 STACKSTRNUL(p);
1842 if ((lstat(stackblock(), &statb) < 0)
1843 || (S_ISLNK(statb.st_mode))) {
1844 /* print = 1; */
1845 badstat = 1;
1846 break;
1847 }
1848 }
1849
1850 INTOFF;
1851 if (chdir(dest) < 0) {
1852 INTON;
1853 return -1;
1854 }
1855 updatepwd(badstat ? NULL : dest);
1856 INTON;
1857 if (print && iflag)
1858 printf(snlfmt, curdir);
1859 return 0;
1860}
1861
1862
1863/*
1864 * Get the next component of the path name pointed to by cdcomppath.
1865 * This routine overwrites the string pointed to by cdcomppath.
1866 */
1867
1868static char *
1869getcomponent() {
1870 char *p;
1871 char *start;
1872
1873 if ((p = cdcomppath) == NULL)
1874 return NULL;
1875 start = cdcomppath;
1876 while (*p != '/' && *p != '\0')
1877 p++;
1878 if (*p == '\0') {
1879 cdcomppath = NULL;
1880 } else {
1881 *p++ = '\0';
1882 cdcomppath = p;
1883 }
1884 return start;
1885}
1886
1887
1888
1889/*
1890 * Update curdir (the name of the current directory) in response to a
1891 * cd command. We also call hashcd to let the routines in exec.c know
1892 * that the current directory has changed.
1893 */
1894
1895static void hashcd (void);
1896
1897static void
1898updatepwd(const char *dir)
1899{
1900 char *new;
1901 char *p;
1902 size_t len;
1903
1904 hashcd(); /* update command hash table */
1905
1906 /*
1907 * If our argument is NULL, we don't know the current directory
1908 * any more because we traversed a symbolic link or something
1909 * we couldn't stat().
1910 */
1911 if (dir == NULL || curdir == nullstr) {
1912 setpwd(0, 1);
1913 return;
1914 }
1915 len = strlen(dir);
1916 cdcomppath = sstrdup(dir);
1917 STARTSTACKSTR(new);
1918 if (*dir != '/') {
1919 p = curdir;
1920 while (*p)
1921 STPUTC(*p++, new);
1922 if (p[-1] == '/')
1923 STUNPUTC(new);
1924 }
1925 while ((p = getcomponent()) != NULL) {
1926 if (equal(p, "..")) {
1927 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1928 } else if (*p != '\0' && ! equal(p, ".")) {
1929 STPUTC('/', new);
1930 while (*p)
1931 STPUTC(*p++, new);
1932 }
1933 }
1934 if (new == stackblock())
1935 STPUTC('/', new);
1936 STACKSTRNUL(new);
1937 setpwd(stackblock(), 1);
1938}
1939
1940
1941#ifndef BB_PWD
1942static int
1943pwdcmd(argc, argv)
1944 int argc;
1945 char **argv;
1946{
1947 printf(snlfmt, curdir);
1948 return 0;
1949}
1950#endif
1951
1952/*
1953 * Find out what the current directory is. If we already know the current
1954 * directory, this routine returns immediately.
1955 */
1956static void
1957getpwd(void)
1958{
1959 curdir = xgetcwd(0);
1960 if(curdir==0)
1961 curdir = nullstr;
1962}
1963
1964static void
1965setpwd(const char *val, int setold)
1966{
1967 if (setold) {
1968 setvar("OLDPWD", curdir, VEXPORT);
1969 }
1970 INTOFF;
1971 if (curdir != nullstr) {
1972 free(curdir);
1973 curdir = nullstr;
1974 }
1975 if (!val) {
1976 getpwd();
1977 } else {
1978 curdir = savestr(val);
1979 }
1980 INTON;
1981 setvar("PWD", curdir, VEXPORT);
1982}
1983
1984/*
1985 * Errors and exceptions.
1986 */
1987
1988/*
1989 * Code to handle exceptions in C.
1990 */
1991
1992/*
1993 * We enclose jmp_buf in a structure so that we can declare pointers to
1994 * jump locations. The global variable handler contains the location to
1995 * jump to when an exception occurs, and the global variable exception
1996 * contains a code identifying the exeception. To implement nested
1997 * exception handlers, the user should save the value of handler on entry
1998 * to an inner scope, set handler to point to a jmploc structure for the
1999 * inner scope, and restore handler on exit from the scope.
2000 */
2001
2002struct jmploc {
2003 jmp_buf loc;
2004};
2005
2006/* exceptions */
2007#define EXINT 0 /* SIGINT received */
2008#define EXERROR 1 /* a generic error */
2009#define EXSHELLPROC 2 /* execute a shell procedure */
2010#define EXEXEC 3 /* command execution failed */
2011
2012static struct jmploc *handler;
2013static int exception;
2014
2015static void exverror (int, const char *, va_list)
2016 __attribute__((__noreturn__));
2017
2018/*
2019 * Called to raise an exception. Since C doesn't include exceptions, we
2020 * just do a longjmp to the exception handler. The type of exception is
2021 * stored in the global variable "exception".
2022 */
2023
2024static void exraise (int) __attribute__((__noreturn__));
2025
2026static void
2027exraise(int e)
2028{
2029#ifdef DEBUG
2030 if (handler == NULL)
2031 abort();
2032#endif
2033 flushall();
2034 exception = e;
2035 longjmp(handler->loc, 1);
2036}
2037
2038
2039/*
2040 * Called from trap.c when a SIGINT is received. (If the user specifies
2041 * that SIGINT is to be trapped or ignored using the trap builtin, then
2042 * this routine is not called.) Suppressint is nonzero when interrupts
2043 * are held using the INTOFF macro. The call to _exit is necessary because
2044 * there is a short period after a fork before the signal handlers are
2045 * set to the appropriate value for the child. (The test for iflag is
2046 * just defensive programming.)
2047 */
2048
2049static void
2050onint(void) {
2051 sigset_t mysigset;
2052
2053 if (suppressint) {
2054 intpending++;
2055 return;
2056 }
2057 intpending = 0;
2058 sigemptyset(&mysigset);
2059 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2060 if (rootshell && iflag)
2061 exraise(EXINT);
2062 else {
2063 signal(SIGINT, SIG_DFL);
2064 raise(SIGINT);
2065 }
2066 /* NOTREACHED */
2067}
2068
2069
2070static char *commandname; /* currently executing command */
2071
2072/*
2073 * Exverror is called to raise the error exception. If the first argument
2074 * is not NULL then error prints an error message using printf style
2075 * formatting. It then raises the error exception.
2076 */
2077static void
2078exverror(int cond, const char *msg, va_list ap)
2079{
2080 CLEAR_PENDING_INT;
2081 INTOFF;
2082
2083#ifdef DEBUG
2084 if (msg)
2085 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2086 else
2087 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2088#endif
2089 if (msg) {
2090 if (commandname)
2091 out2fmt("%s: ", commandname);
2092 vfprintf(stderr, msg, ap);
2093 out2c('\n');
2094 }
2095 exraise(cond);
2096 /* NOTREACHED */
2097}
2098
2099
2100static void
2101error(const char *msg, ...)
2102{
2103 va_list ap;
2104 va_start(ap, msg);
2105 exverror(EXERROR, msg, ap);
2106 /* NOTREACHED */
2107 va_end(ap);
2108}
2109
2110
2111static void
2112exerror(int cond, const char *msg, ...)
2113{
2114 va_list ap;
2115 va_start(ap, msg);
2116 exverror(cond, msg, ap);
2117 /* NOTREACHED */
2118 va_end(ap);
2119}
2120
2121
2122
2123/*
2124 * Table of error messages.
2125 */
2126
2127struct errname {
2128 short errcode; /* error number */
2129 char action; /* operation which encountered the error */
2130};
2131
2132/*
2133 * Types of operations (passed to the errmsg routine).
2134 */
2135
2136#define E_OPEN 01 /* opening a file */
2137#define E_CREAT 02 /* creating a file */
2138#define E_EXEC 04 /* executing a program */
2139
2140#define ALL (E_OPEN|E_CREAT|E_EXEC)
2141
2142static const struct errname errormsg[] = {
2143 { EINTR, ALL },
2144 { EACCES, ALL },
2145 { EIO, ALL },
2146 { ENOENT, E_OPEN },
2147 { ENOENT, E_CREAT },
2148 { ENOENT, E_EXEC },
2149 { ENOTDIR, E_OPEN },
2150 { ENOTDIR, E_CREAT },
2151 { ENOTDIR, E_EXEC },
2152 { EISDIR, ALL },
2153 { EEXIST, E_CREAT },
2154#ifdef EMFILE
2155 { EMFILE, ALL },
2156#endif
2157 { ENFILE, ALL },
2158 { ENOSPC, ALL },
2159#ifdef EDQUOT
2160 { EDQUOT, ALL },
2161#endif
2162#ifdef ENOSR
2163 { ENOSR, ALL },
2164#endif
2165 { ENXIO, ALL },
2166 { EROFS, ALL },
2167 { ETXTBSY, ALL },
2168#ifdef EAGAIN
2169 { EAGAIN, E_EXEC },
2170#endif
2171 { ENOMEM, ALL },
2172#ifdef ENOLINK
2173 { ENOLINK, ALL },
2174#endif
2175#ifdef EMULTIHOP
2176 { EMULTIHOP, ALL },
2177#endif
2178#ifdef ECOMM
2179 { ECOMM, ALL },
2180#endif
2181#ifdef ESTALE
2182 { ESTALE, ALL },
2183#endif
2184#ifdef ETIMEDOUT
2185 { ETIMEDOUT, ALL },
2186#endif
2187#ifdef ELOOP
2188 { ELOOP, ALL },
2189#endif
2190 { E2BIG, E_EXEC },
2191#ifdef ELIBACC
2192 { ELIBACC, E_EXEC },
2193#endif
2194};
2195
2196#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
2197
2198/*
2199 * Return a string describing an error. The returned string may be a
2200 * pointer to a static buffer that will be overwritten on the next call.
2201 * Action describes the operation that got the error.
2202 */
2203
2204static const char *
2205errmsg(int e, int action)
2206{
2207 struct errname const *ep;
2208 static char buf[12];
2209
2210 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
2211 if (ep->errcode == e && (ep->action & action) != 0)
2212 return strerror(e);
2213 }
2214
2215 snprintf(buf, sizeof buf, "error %d", e);
2216 return buf;
2217}
2218
2219
2220#ifdef ASH_OPTIMIZE_FOR_SIZE
2221static void
2222__inton() {
2223 if (--suppressint == 0 && intpending) {
2224 onint();
2225 }
2226}
2227static void forceinton (void) {
2228 suppressint = 0;
2229 if (intpending)
2230 onint();
2231}
2232#endif
2233
2234/* flags in argument to evaltree */
2235#define EV_EXIT 01 /* exit after evaluating tree */
2236#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2237#define EV_BACKCMD 04 /* command executing within back quotes */
2238
2239static int evalskip; /* set if we are skipping commands */
2240static int skipcount; /* number of levels to skip */
2241static int loopnest; /* current loop nesting level */
2242static int funcnest; /* depth of function calls */
2243
2244
2245static struct strlist *cmdenviron; /* environment for builtin command */
2246static int exitstatus; /* exit status of last command */
2247static int oexitstatus; /* saved exit status */
2248
2249static void evalsubshell (const union node *, int);
2250static void expredir (union node *);
2251static void prehash (union node *);
2252static void eprintlist (struct strlist *);
2253
2254static union node *parsecmd(int);
2255/*
2256 * Called to reset things after an exception.
2257 */
2258
2259/*
2260 * The eval commmand.
2261 */
2262static void evalstring (char *, int);
2263
2264static int
2265evalcmd(argc, argv)
2266 int argc;
2267 char **argv;
2268{
2269 char *p;
2270 char *concat;
2271 char **ap;
2272
2273 if (argc > 1) {
2274 p = argv[1];
2275 if (argc > 2) {
2276 STARTSTACKSTR(concat);
2277 ap = argv + 2;
2278 for (;;) {
2279 while (*p)
2280 STPUTC(*p++, concat);
2281 if ((p = *ap++) == NULL)
2282 break;
2283 STPUTC(' ', concat);
2284 }
2285 STPUTC('\0', concat);
2286 p = grabstackstr(concat);
2287 }
2288 evalstring(p, EV_TESTED);
2289 }
2290 return exitstatus;
2291}
2292
2293/*
2294 * Execute a command or commands contained in a string.
2295 */
2296
2297static void evaltree (union node *, int);
2298static void setinputstring (char *);
2299static void popfile (void);
2300static void setstackmark(struct stackmark *mark);
2301static void popstackmark(struct stackmark *mark);
2302
2303
2304static void
2305evalstring(char *s, int flag)
2306{
2307 union node *n;
2308 struct stackmark smark;
2309
2310 setstackmark(&smark);
2311 setinputstring(s);
2312 while ((n = parsecmd(0)) != NEOF) {
2313 evaltree(n, flag);
2314 popstackmark(&smark);
2315 }
2316 popfile();
2317 popstackmark(&smark);
2318}
2319
2320static struct builtincmd *find_builtin (const char *);
2321static void expandarg (union node *, struct arglist *, int);
2322static void calcsize (const union node *);
2323static union node *copynode (const union node *);
2324
2325/*
2326 * Make a copy of a parse tree.
2327 */
2328
2329static int funcblocksize; /* size of structures in function */
2330static int funcstringsize; /* size of strings in node */
2331static pointer funcblock; /* block to allocate function from */
2332static char *funcstring; /* block to allocate strings from */
2333
2334
2335static inline union node *
2336copyfunc(union node *n)
2337{
2338 if (n == NULL)
2339 return NULL;
2340 funcblocksize = 0;
2341 funcstringsize = 0;
2342 calcsize(n);
2343 funcblock = ckmalloc(funcblocksize + funcstringsize);
2344 funcstring = (char *) funcblock + funcblocksize;
2345 return copynode(n);
2346}
2347
2348/*
2349 * Free a parse tree.
2350 */
2351
2352static void
2353freefunc(union node *n)
2354{
2355 if (n)
2356 ckfree(n);
2357}
2358
2359
2360/*
2361 * Add a new command entry, replacing any existing command entry for
2362 * the same name.
2363 */
2364
2365static inline void
2366addcmdentry(char *name, struct cmdentry *entry)
2367{
2368 struct tblentry *cmdp;
2369
2370 INTOFF;
2371 cmdp = cmdlookup(name, 1);
2372 if (cmdp->cmdtype == CMDFUNCTION) {
2373 freefunc(cmdp->param.func);
2374 }
2375 cmdp->cmdtype = entry->cmdtype;
2376 cmdp->param = entry->u;
2377 INTON;
2378}
2379
2380static inline void
2381evalloop(const union node *n, int flags)
2382{
2383 int status;
2384
2385 loopnest++;
2386 status = 0;
2387 for (;;) {
2388 evaltree(n->nbinary.ch1, EV_TESTED);
2389 if (evalskip) {
2390skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2391 evalskip = 0;
2392 continue;
2393 }
2394 if (evalskip == SKIPBREAK && --skipcount <= 0)
2395 evalskip = 0;
2396 break;
2397 }
2398 if (n->type == NWHILE) {
2399 if (exitstatus != 0)
2400 break;
2401 } else {
2402 if (exitstatus == 0)
2403 break;
2404 }
2405 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2406 status = exitstatus;
2407 if (evalskip)
2408 goto skipping;
2409 }
2410 loopnest--;
2411 exitstatus = status;
2412}
2413
2414static void
2415evalfor(const union node *n, int flags)
2416{
2417 struct arglist arglist;
2418 union node *argp;
2419 struct strlist *sp;
2420 struct stackmark smark;
2421
2422 setstackmark(&smark);
2423 arglist.lastp = &arglist.list;
2424 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2425 oexitstatus = exitstatus;
2426 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2427 if (evalskip)
2428 goto out;
2429 }
2430 *arglist.lastp = NULL;
2431
2432 exitstatus = 0;
2433 loopnest++;
2434 for (sp = arglist.list ; sp ; sp = sp->next) {
2435 setvar(n->nfor.var, sp->text, 0);
2436 evaltree(n->nfor.body, flags & EV_TESTED);
2437 if (evalskip) {
2438 if (evalskip == SKIPCONT && --skipcount <= 0) {
2439 evalskip = 0;
2440 continue;
2441 }
2442 if (evalskip == SKIPBREAK && --skipcount <= 0)
2443 evalskip = 0;
2444 break;
2445 }
2446 }
2447 loopnest--;
2448out:
2449 popstackmark(&smark);
2450}
2451
2452static inline void
2453evalcase(const union node *n, int flags)
2454{
2455 union node *cp;
2456 union node *patp;
2457 struct arglist arglist;
2458 struct stackmark smark;
2459
2460 setstackmark(&smark);
2461 arglist.lastp = &arglist.list;
2462 oexitstatus = exitstatus;
2463 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2464 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2465 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2466 if (casematch(patp, arglist.list->text)) {
2467 if (evalskip == 0) {
2468 evaltree(cp->nclist.body, flags);
2469 }
2470 goto out;
2471 }
2472 }
2473 }
2474out:
2475 popstackmark(&smark);
2476}
2477
2478/*
2479 * Evaluate a pipeline. All the processes in the pipeline are children
2480 * of the process creating the pipeline. (This differs from some versions
2481 * of the shell, which make the last process in a pipeline the parent
2482 * of all the rest.)
2483 */
2484
2485static inline void evalpipe(union node *n)
2486{
2487 struct job *jp;
2488 struct nodelist *lp;
2489 int pipelen;
2490 int prevfd;
2491 int pip[2];
2492
2493 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2494 pipelen = 0;
2495 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2496 pipelen++;
2497 INTOFF;
2498 jp = makejob(n, pipelen);
2499 prevfd = -1;
2500 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2501 prehash(lp->n);
2502 pip[1] = -1;
2503 if (lp->next) {
2504 if (pipe(pip) < 0) {
2505 close(prevfd);
2506 error("Pipe call failed");
2507 }
2508 }
2509 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2510 INTON;
2511 if (prevfd > 0) {
2512 close(0);
2513 dup_as_newfd(prevfd, 0);
2514 close(prevfd);
2515 if (pip[0] == 0) {
2516 pip[0] = -1;
2517 }
2518 }
2519 if (pip[1] >= 0) {
2520 if (pip[0] >= 0) {
2521 close(pip[0]);
2522 }
2523 if (pip[1] != 1) {
2524 close(1);
2525 dup_as_newfd(pip[1], 1);
2526 close(pip[1]);
2527 }
2528 }
2529 evaltree(lp->n, EV_EXIT);
2530 }
2531 if (prevfd >= 0)
2532 close(prevfd);
2533 prevfd = pip[0];
2534 close(pip[1]);
2535 }
2536 INTON;
2537 if (n->npipe.backgnd == 0) {
2538 INTOFF;
2539 exitstatus = waitforjob(jp);
2540 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2541 INTON;
2542 }
2543}
2544
2545static void find_command (const char *, struct cmdentry *, int, const char *);
2546
2547static int
2548isassignment(const char *word) {
2549 if (!is_name(*word)) {
2550 return 0;
2551 }
2552 do {
2553 word++;
2554 } while (is_in_name(*word));
2555 return *word == '=';
2556}
2557
2558
2559static void
2560evalcommand(union node *cmd, int flags)
2561{
2562 struct stackmark smark;
2563 union node *argp;
2564 struct arglist arglist;
2565 struct arglist varlist;
2566 char **argv;
2567 int argc;
2568 char **envp;
2569 struct strlist *sp;
2570 int mode;
2571 struct cmdentry cmdentry;
2572 struct job *jp;
2573 char *volatile savecmdname;
2574 volatile struct shparam saveparam;
2575 struct localvar *volatile savelocalvars;
2576 volatile int e;
2577 char *lastarg;
2578 const char *path;
2579 const struct builtincmd *firstbltin;
2580 struct jmploc *volatile savehandler;
2581 struct jmploc jmploc;
2582#if __GNUC__
2583 /* Avoid longjmp clobbering */
2584 (void) &argv;
2585 (void) &argc;
2586 (void) &lastarg;
2587 (void) &flags;
2588#endif
2589
2590 /* First expand the arguments. */
2591 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2592 setstackmark(&smark);
2593 arglist.lastp = &arglist.list;
2594 varlist.lastp = &varlist.list;
2595 arglist.list = 0;
2596 oexitstatus = exitstatus;
2597 exitstatus = 0;
2598 path = pathval();
2599 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2600 expandarg(argp, &varlist, EXP_VARTILDE);
2601 }
2602 for (
2603 argp = cmd->ncmd.args; argp && !arglist.list;
2604 argp = argp->narg.next
2605 ) {
2606 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2607 }
2608 if (argp) {
2609 struct builtincmd *bcmd;
2610 int pseudovarflag;
2611 bcmd = find_builtin(arglist.list->text);
2612 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
2613 for (; argp; argp = argp->narg.next) {
2614 if (pseudovarflag && isassignment(argp->narg.text)) {
2615 expandarg(argp, &arglist, EXP_VARTILDE);
2616 continue;
2617 }
2618 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2619 }
2620 }
2621 *arglist.lastp = NULL;
2622 *varlist.lastp = NULL;
2623 expredir(cmd->ncmd.redirect);
2624 argc = 0;
2625 for (sp = arglist.list ; sp ; sp = sp->next)
2626 argc++;
2627 argv = stalloc(sizeof (char *) * (argc + 1));
2628
2629 for (sp = arglist.list ; sp ; sp = sp->next) {
2630 TRACE(("evalcommand arg: %s\n", sp->text));
2631 *argv++ = sp->text;
2632 }
2633 *argv = NULL;
2634 lastarg = NULL;
2635 if (iflag && funcnest == 0 && argc > 0)
2636 lastarg = argv[-1];
2637 argv -= argc;
2638
2639 /* Print the command if xflag is set. */
2640 if (xflag) {
2641 out2c('+');
2642 eprintlist(varlist.list);
2643 eprintlist(arglist.list);
2644 out2c('\n');
2645 }
2646
2647 /* Now locate the command. */
2648 if (argc == 0) {
2649 cmdentry.cmdtype = CMDBUILTIN;
2650 firstbltin = cmdentry.u.cmd = BLTINCMD;
2651 } else {
2652 const char *oldpath;
2653 int findflag = DO_ERR;
2654 int oldfindflag;
2655
2656 /*
2657 * Modify the command lookup path, if a PATH= assignment
2658 * is present
2659 */
2660 for (sp = varlist.list ; sp ; sp = sp->next)
2661 if (varequal(sp->text, defpathvar)) {
2662 path = sp->text + 5;
2663 findflag |= DO_BRUTE;
2664 }
2665 oldpath = path;
2666 oldfindflag = findflag;
2667 firstbltin = 0;
2668 for(;;) {
2669 find_command(argv[0], &cmdentry, findflag, path);
2670 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
2671 exitstatus = 127;
2672 goto out;
2673 }
2674 /* implement bltin and command here */
2675 if (cmdentry.cmdtype != CMDBUILTIN) {
2676 break;
2677 }
2678 if (!firstbltin) {
2679 firstbltin = cmdentry.u.cmd;
2680 }
2681 if (cmdentry.u.cmd == BLTINCMD) {
2682 for(;;) {
2683 struct builtincmd *bcmd;
2684
2685 argv++;
2686 if (--argc == 0)
2687 goto found;
2688 if (!(bcmd = find_builtin(*argv))) {
2689 out2fmt("%s: not found\n", *argv);
2690 exitstatus = 127;
2691 goto out;
2692 }
2693 cmdentry.u.cmd = bcmd;
2694 if (bcmd != BLTINCMD)
2695 break;
2696 }
2697 }
2698 if (cmdentry.u.cmd == find_builtin("command")) {
2699 argv++;
2700 if (--argc == 0) {
2701 goto found;
2702 }
2703 if (*argv[0] == '-') {
2704 if (!equal(argv[0], "-p")) {
2705 argv--;
2706 argc++;
2707 break;
2708 }
2709 argv++;
2710 if (--argc == 0) {
2711 goto found;
2712 }
2713 path = defpath;
2714 findflag |= DO_BRUTE;
2715 } else {
2716 path = oldpath;
2717 findflag = oldfindflag;
2718 }
2719 findflag |= DO_NOFUN;
2720 continue;
2721 }
2722found:
2723 break;
2724 }
2725 }
2726
2727 /* Fork off a child process if necessary. */
2728 if (cmd->ncmd.backgnd
2729 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
2730 ) {
2731 jp = makejob(cmd, 1);
2732 mode = cmd->ncmd.backgnd;
2733 if (forkshell(jp, cmd, mode) != 0)
2734 goto parent; /* at end of routine */
2735 flags |= EV_EXIT;
2736 }
2737
2738 /* This is the child process if a fork occurred. */
2739 /* Execute the command. */
2740 if (cmdentry.cmdtype == CMDFUNCTION) {
2741#ifdef DEBUG
2742 trputs("Shell function: "); trargs(argv);
2743#endif
2744 exitstatus = oexitstatus;
2745 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2746 saveparam = shellparam;
2747 shellparam.malloc = 0;
2748 shellparam.nparam = argc - 1;
2749 shellparam.p = argv + 1;
2750 INTOFF;
2751 savelocalvars = localvars;
2752 localvars = NULL;
2753 INTON;
2754 if (setjmp(jmploc.loc)) {
2755 if (exception == EXSHELLPROC) {
2756 freeparam((volatile struct shparam *)
2757 &saveparam);
2758 } else {
2759 saveparam.optind = shellparam.optind;
2760 saveparam.optoff = shellparam.optoff;
2761 freeparam(&shellparam);
2762 shellparam = saveparam;
2763 }
2764 poplocalvars();
2765 localvars = savelocalvars;
2766 handler = savehandler;
2767 longjmp(handler->loc, 1);
2768 }
2769 savehandler = handler;
2770 handler = &jmploc;
2771 for (sp = varlist.list ; sp ; sp = sp->next)
2772 mklocal(sp->text);
2773 funcnest++;
2774 evaltree(cmdentry.u.func, flags & EV_TESTED);
2775 funcnest--;
2776 INTOFF;
2777 poplocalvars();
2778 localvars = savelocalvars;
2779 saveparam.optind = shellparam.optind;
2780 saveparam.optoff = shellparam.optoff;
2781 freeparam(&shellparam);
2782 shellparam = saveparam;
2783 handler = savehandler;
2784 popredir();
2785 INTON;
2786 if (evalskip == SKIPFUNC) {
2787 evalskip = 0;
2788 skipcount = 0;
2789 }
2790 if (flags & EV_EXIT)
2791 exitshell(exitstatus);
2792 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2793#ifdef DEBUG
2794 trputs("builtin command: "); trargs(argv);
2795#endif
2796 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
2797 redirect(cmd->ncmd.redirect, mode);
2798 savecmdname = commandname;
2799 if (IS_BUILTIN_SPECIAL(firstbltin)) {
2800 listsetvar(varlist.list);
2801 } else {
2802 cmdenviron = varlist.list;
2803 }
2804 e = -1;
2805 if (setjmp(jmploc.loc)) {
2806 e = exception;
2807 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2808 goto cmddone;
2809 }
2810 savehandler = handler;
2811 handler = &jmploc;
2812 commandname = argv[0];
2813 argptr = argv + 1;
2814 optptr = NULL; /* initialize nextopt */
2815 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2816 flushall();
2817cmddone:
2818 cmdenviron = NULL;
2819 if (e != EXSHELLPROC) {
2820 commandname = savecmdname;
2821 if (flags & EV_EXIT)
2822 exitshell(exitstatus);
2823 }
2824 handler = savehandler;
2825 if (e != -1) {
2826 if ((e != EXERROR && e != EXEXEC)
2827 || cmdentry.u.cmd == BLTINCMD
2828 || cmdentry.u.cmd == DOTCMD
2829 || cmdentry.u.cmd == EVALCMD
2830 || cmdentry.u.cmd == EXECCMD)
2831 exraise(e);
2832 FORCEINTON;
2833 }
2834 if (cmdentry.u.cmd != EXECCMD)
2835 popredir();
2836 } else {
2837#ifdef DEBUG
2838 trputs("normal command: "); trargs(argv);
2839#endif
2840 redirect(cmd->ncmd.redirect, 0);
2841 clearredir();
2842 for (sp = varlist.list ; sp ; sp = sp->next)
2843 setvareq(sp->text, VEXPORT|VSTACK);
2844 envp = environment();
2845 shellexec(argv, envp, path, cmdentry.u.index);
2846 }
2847 goto out;
2848
2849parent: /* parent process gets here (if we forked) */
2850 if (mode == 0) { /* argument to fork */
2851 INTOFF;
2852 exitstatus = waitforjob(jp);
2853 INTON;
2854 }
2855
2856out:
2857 if (lastarg)
2858 setvar("_", lastarg, 0);
2859 popstackmark(&smark);
2860}
2861
2862/*
2863 * Evaluate a parse tree. The value is left in the global variable
2864 * exitstatus.
2865 */
2866static void
2867evaltree(n, flags)
2868 union node *n;
2869 int flags;
2870{
2871 int checkexit = 0;
2872 if (n == NULL) {
2873 TRACE(("evaltree(NULL) called\n"));
2874 goto out;
2875 }
2876 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2877 switch (n->type) {
2878 case NSEMI:
2879 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2880 if (evalskip)
2881 goto out;
2882 evaltree(n->nbinary.ch2, flags);
2883 break;
2884 case NAND:
2885 evaltree(n->nbinary.ch1, EV_TESTED);
2886 if (evalskip || exitstatus != 0)
2887 goto out;
2888 evaltree(n->nbinary.ch2, flags);
2889 break;
2890 case NOR:
2891 evaltree(n->nbinary.ch1, EV_TESTED);
2892 if (evalskip || exitstatus == 0)
2893 goto out;
2894 evaltree(n->nbinary.ch2, flags);
2895 break;
2896 case NREDIR:
2897 expredir(n->nredir.redirect);
2898 redirect(n->nredir.redirect, REDIR_PUSH);
2899 evaltree(n->nredir.n, flags);
2900 popredir();
2901 break;
2902 case NSUBSHELL:
2903 evalsubshell(n, flags);
2904 break;
2905 case NBACKGND:
2906 evalsubshell(n, flags);
2907 break;
2908 case NIF: {
2909 evaltree(n->nif.test, EV_TESTED);
2910 if (evalskip)
2911 goto out;
2912 if (exitstatus == 0)
2913 evaltree(n->nif.ifpart, flags);
2914 else if (n->nif.elsepart)
2915 evaltree(n->nif.elsepart, flags);
2916 else
2917 exitstatus = 0;
2918 break;
2919 }
2920 case NWHILE:
2921 case NUNTIL:
2922 evalloop(n, flags);
2923 break;
2924 case NFOR:
2925 evalfor(n, flags);
2926 break;
2927 case NCASE:
2928 evalcase(n, flags);
2929 break;
2930 case NDEFUN: {
2931 struct builtincmd *bcmd;
2932 struct cmdentry entry;
2933 if (
2934 (bcmd = find_builtin(n->narg.text)) &&
2935 IS_BUILTIN_SPECIAL(bcmd)
2936 ) {
2937 out2fmt("%s is a special built-in\n", n->narg.text);
2938 exitstatus = 1;
2939 break;
2940 }
2941 entry.cmdtype = CMDFUNCTION;
2942 entry.u.func = copyfunc(n->narg.next);
2943 addcmdentry(n->narg.text, &entry);
2944 exitstatus = 0;
2945 break;
2946 }
2947 case NNOT:
2948 evaltree(n->nnot.com, EV_TESTED);
2949 exitstatus = !exitstatus;
2950 break;
2951
2952 case NPIPE:
2953 evalpipe(n);
2954 checkexit = 1;
2955 break;
2956 case NCMD:
2957 evalcommand(n, flags);
2958 checkexit = 1;
2959 break;
2960#ifdef DEBUG
2961 default:
2962 printf("Node type = %d\n", n->type);
2963 break;
2964#endif
2965 }
2966out:
2967 if (pendingsigs)
2968 dotrap();
2969 if (
2970 flags & EV_EXIT ||
2971 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2972 )
2973 exitshell(exitstatus);
2974}
2975
2976/*
2977 * Kick off a subshell to evaluate a tree.
2978 */
2979
2980static void
2981evalsubshell(const union node *n, int flags)
2982{
2983 struct job *jp;
2984 int backgnd = (n->type == NBACKGND);
2985
2986 expredir(n->nredir.redirect);
2987 jp = makejob(n, 1);
2988 if (forkshell(jp, n, backgnd) == 0) {
2989 if (backgnd)
2990 flags &=~ EV_TESTED;
2991 redirect(n->nredir.redirect, 0);
2992 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2993 }
2994 if (! backgnd) {
2995 INTOFF;
2996 exitstatus = waitforjob(jp);
2997 INTON;
2998 }
2999}
3000
3001/*
3002 * Compute the names of the files in a redirection list.
3003 */
3004
3005static void fixredir(union node *n, const char *text, int err);
3006
3007static void
3008expredir(union node *n)
3009{
3010 union node *redir;
3011
3012 for (redir = n ; redir ; redir = redir->nfile.next) {
3013 struct arglist fn;
3014 fn.lastp = &fn.list;
3015 oexitstatus = exitstatus;
3016 switch (redir->type) {
3017 case NFROMTO:
3018 case NFROM:
3019 case NTO:
3020 case NAPPEND:
3021 case NTOOV:
3022 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3023 redir->nfile.expfname = fn.list->text;
3024 break;
3025 case NFROMFD:
3026 case NTOFD:
3027 if (redir->ndup.vname) {
3028 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3029 fixredir(redir, fn.list->text, 1);
3030 }
3031 break;
3032 }
3033 }
3034}
3035
3036
3037/*
3038 * Execute a command inside back quotes. If it's a builtin command, we
3039 * want to save its output in a block obtained from malloc. Otherwise
3040 * we fork off a subprocess and get the output of the command via a pipe.
3041 * Should be called with interrupts off.
3042 */
3043
3044static void
3045evalbackcmd(union node *n, struct backcmd *result)
3046{
3047 int pip[2];
3048 struct job *jp;
3049 struct stackmark smark; /* unnecessary */
3050
3051 setstackmark(&smark);
3052 result->fd = -1;
3053 result->buf = NULL;
3054 result->nleft = 0;
3055 result->jp = NULL;
3056 if (n == NULL) {
3057 exitstatus = 0;
3058 goto out;
3059 }
3060 exitstatus = 0;
3061 if (pipe(pip) < 0)
3062 error("Pipe call failed");
3063 jp = makejob(n, 1);
3064 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3065 FORCEINTON;
3066 close(pip[0]);
3067 if (pip[1] != 1) {
3068 close(1);
3069 dup_as_newfd(pip[1], 1);
3070 close(pip[1]);
3071 }
3072 eflag = 0;
3073 evaltree(n, EV_EXIT);
3074 }
3075 close(pip[1]);
3076 result->fd = pip[0];
3077 result->jp = jp;
3078out:
3079 popstackmark(&smark);
3080 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3081 result->fd, result->buf, result->nleft, result->jp));
3082}
3083
3084
3085/*
3086 * Execute a simple command.
3087 */
3088
3089/*
3090 * Search for a command. This is called before we fork so that the
3091 * location of the command will be available in the parent as well as
3092 * the child. The check for "goodname" is an overly conservative
3093 * check that the name will not be subject to expansion.
3094 */
3095
3096static void
3097prehash(n)
3098 union node *n;
3099{
3100 struct cmdentry entry;
3101
3102 if (n->type == NCMD && n->ncmd.args)
3103 if (goodname(n->ncmd.args->narg.text))
3104 find_command(n->ncmd.args->narg.text, &entry, 0,
3105 pathval());
3106}
3107
3108
3109/*
3110 * Builtin commands. Builtin commands whose functions are closely
3111 * tied to evaluation are implemented here.
3112 */
3113
3114/*
3115 * No command given, or a bltin command with no arguments. Set the
3116 * specified variables.
3117 */
3118
3119int
3120bltincmd(argc, argv)
3121 int argc;
3122 char **argv;
3123{
3124 /*
3125 * Preserve exitstatus of a previous possible redirection
3126 * as POSIX mandates
3127 */
3128 return exitstatus;
3129}
3130
3131
3132/*
3133 * Handle break and continue commands. Break, continue, and return are
3134 * all handled by setting the evalskip flag. The evaluation routines
3135 * above all check this flag, and if it is set they start skipping
3136 * commands rather than executing them. The variable skipcount is
3137 * the number of loops to break/continue, or the number of function
3138 * levels to return. (The latter is always 1.) It should probably
3139 * be an error to break out of more loops than exist, but it isn't
3140 * in the standard shell so we don't make it one here.
3141 */
3142
3143static int
3144breakcmd(argc, argv)
3145 int argc;
3146 char **argv;
3147{
3148 int n = argc > 1 ? number(argv[1]) : 1;
3149
3150 if (n > loopnest)
3151 n = loopnest;
3152 if (n > 0) {
3153 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3154 skipcount = n;
3155 }
3156 return 0;
3157}
3158
3159
3160/*
3161 * The return command.
3162 */
3163
3164static int
3165returncmd(argc, argv)
3166 int argc;
3167 char **argv;
3168{
3169 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3170
3171 if (funcnest) {
3172 evalskip = SKIPFUNC;
3173 skipcount = 1;
3174 return ret;
3175 }
3176 else {
3177 /* Do what ksh does; skip the rest of the file */
3178 evalskip = SKIPFILE;
3179 skipcount = 1;
3180 return ret;
3181 }
3182}
3183
3184
3185#ifndef BB_TRUE_FALSE
3186static int
3187false_main(argc, argv)
3188 int argc;
3189 char **argv;
3190{
3191 return 1;
3192}
3193
3194
3195static int
3196true_main(argc, argv)
3197 int argc;
3198 char **argv;
3199{
3200 return 0;
3201}
3202#endif
3203
3204/*
3205 * Controls whether the shell is interactive or not.
3206 */
3207
3208static void setsignal(int signo);
3209static void chkmail(int silent);
3210
3211
3212static void
3213setinteractive(int on)
3214{
3215 static int is_interactive;
3216 static int do_banner=0;
3217
3218 if (on == is_interactive)
3219 return;
3220 setsignal(SIGINT);
3221 setsignal(SIGQUIT);
3222 setsignal(SIGTERM);
3223 chkmail(1);
3224 is_interactive = on;
3225 if (do_banner==0 && is_interactive) {
3226 /* Looks like they want an interactive shell */
3227#ifndef BB_FEATURE_SH_EXTRA_QUIET
3228 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3229 printf( "Enter 'help' for a list of built-in commands.\n\n");
3230#endif
3231 do_banner=1;
3232 }
3233}
3234
3235static void
3236optschanged(void)
3237{
3238 setinteractive(iflag);
3239 setjobctl(mflag);
3240}
3241
3242
3243static int
3244execcmd(argc, argv)
3245 int argc;
3246 char **argv;
3247{
3248 if (argc > 1) {
3249 struct strlist *sp;
3250
3251 iflag = 0; /* exit on error */
3252 mflag = 0;
3253 optschanged();
3254 for (sp = cmdenviron; sp ; sp = sp->next)
3255 setvareq(sp->text, VEXPORT|VSTACK);
3256 shellexec(argv + 1, environment(), pathval(), 0);
3257 }
3258 return 0;
3259}
3260
3261static void
3262eprintlist(struct strlist *sp)
3263{
3264 for (; sp; sp = sp->next) {
3265 out2fmt(" %s",sp->text);
3266 }
3267}
3268
3269/*
3270 * Exec a program. Never returns. If you change this routine, you may
3271 * have to change the find_command routine as well.
3272 */
3273
3274static const char *pathopt; /* set by padvance */
3275
3276static void
3277shellexec(argv, envp, path, idx)
3278 char **argv, **envp;
3279 const char *path;
3280 int idx;
3281{
3282 char *cmdname;
3283 int e;
3284
3285 if (strchr(argv[0], '/') != NULL) {
3286 tryexec(argv[0], argv, envp);
3287 e = errno;
3288 } else {
3289 e = ENOENT;
3290 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3291 if (--idx < 0 && pathopt == NULL) {
3292 tryexec(cmdname, argv, envp);
3293 if (errno != ENOENT && errno != ENOTDIR)
3294 e = errno;
3295 }
3296 stunalloc(cmdname);
3297 }
3298 }
3299
3300 /* Map to POSIX errors */
3301 switch (e) {
3302 case EACCES:
3303 exerrno = 126;
3304 break;
3305 case ENOENT:
3306 exerrno = 127;
3307 break;
3308 default:
3309 exerrno = 2;
3310 break;
3311 }
3312 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3313 /* NOTREACHED */
3314}
3315
3316/*
3317 * Clear traps on a fork.
3318 */
3319static void
3320clear_traps(void) {
3321 char **tp;
3322
3323 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3324 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3325 INTOFF;
3326 ckfree(*tp);
3327 *tp = NULL;
3328 if (tp != &trap[0])
3329 setsignal(tp - trap);
3330 INTON;
3331 }
3332 }
3333}
3334
3335
3336static void
3337initshellproc(void) {
3338
3339#ifdef ASH_ALIAS
3340 /* from alias.c: */
3341 {
3342 rmaliases();
3343 }
3344#endif
3345 /* from eval.c: */
3346 {
3347 exitstatus = 0;
3348 }
3349
3350 /* from exec.c: */
3351 {
3352 deletefuncs();
3353 }
3354
3355 /* from jobs.c: */
3356 {
3357 backgndpid = -1;
3358#ifdef JOBS
3359 jobctl = 0;
3360#endif
3361 }
3362
3363 /* from options.c: */
3364 {
3365 int i;
3366
3367 for (i = 0; i < NOPTS; i++)
3368 optent_val(i) = 0;
3369 optschanged();
3370
3371 }
3372
3373 /* from redir.c: */
3374 {
3375 clearredir();
3376 }
3377
3378 /* from trap.c: */
3379 {
3380 char *sm;
3381
3382 clear_traps();
3383 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3384 if (*sm == S_IGN)
3385 *sm = S_HARD_IGN;
3386 }
3387 }
3388
3389 /* from var.c: */
3390 {
3391 shprocvar();
3392 }
3393}
3394
3395static int preadbuffer(void);
3396static void pushfile (void);
3397
3398/*
3399 * Read a character from the script, returning PEOF on end of file.
3400 * Nul characters in the input are silently discarded.
3401 */
3402
3403#ifndef ASH_OPTIMIZE_FOR_SIZE
3404#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3405static int
3406pgetc(void)
3407{
3408 return pgetc_macro();
3409}
3410#else
3411static int
3412pgetc_macro(void)
3413{
3414 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3415}
3416
3417static inline int
3418pgetc(void)
3419{
3420 return pgetc_macro();
3421}
3422#endif
3423
3424
3425/*
3426 * Undo the last call to pgetc. Only one character may be pushed back.
3427 * PEOF may be pushed back.
3428 */
3429
3430static void pungetc(void)
3431{
3432 parsenleft++;
3433 parsenextc--;
3434}
3435
3436
3437static void
3438popfile(void) {
3439 struct parsefile *pf = parsefile;
3440
3441 INTOFF;
3442 if (pf->fd >= 0)
3443 close(pf->fd);
3444 if (pf->buf)
3445 ckfree(pf->buf);
3446 while (pf->strpush)
3447 popstring();
3448 parsefile = pf->prev;
3449 ckfree(pf);
3450 parsenleft = parsefile->nleft;
3451 parselleft = parsefile->lleft;
3452 parsenextc = parsefile->nextc;
3453 plinno = parsefile->linno;
3454 INTON;
3455}
3456
3457
3458/*
3459 * Return to top level.
3460 */
3461
3462static void
3463popallfiles(void) {
3464 while (parsefile != &basepf)
3465 popfile();
3466}
3467
3468/*
3469 * Close the file(s) that the shell is reading commands from. Called
3470 * after a fork is done.
3471 */
3472
3473static void closescript(void)
3474{
3475 popallfiles();
3476 if (parsefile->fd > 0) {
3477 close(parsefile->fd);
3478 parsefile->fd = 0;
3479 }
3480}
3481
3482
3483/*
3484 * Like setinputfile, but takes an open file descriptor. Call this with
3485 * interrupts off.
3486 */
3487
3488static void setinputfd(int fd, int push)
3489{
3490 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3491 if (push) {
3492 pushfile();
3493 parsefile->buf = 0;
3494 } else {
3495 closescript();
3496 while (parsefile->strpush)
3497 popstring();
3498 }
3499 parsefile->fd = fd;
3500 if (parsefile->buf == NULL)
3501 parsefile->buf = ckmalloc(BUFSIZ);
3502 parselleft = parsenleft = 0;
3503 plinno = 1;
3504}
3505
3506
3507/*
3508 * Set the input to take input from a file. If push is set, push the
3509 * old input onto the stack first.
3510 */
3511
3512static void
3513setinputfile(const char *fname, int push)
3514{
3515 int fd;
3516 int myfileno2;
3517
3518 INTOFF;
3519 if ((fd = open(fname, O_RDONLY)) < 0)
3520 error("Can't open %s", fname);
3521 if (fd < 10) {
3522 myfileno2 = dup_as_newfd(fd, 10);
3523 close(fd);
3524 if (myfileno2 < 0)
3525 error("Out of file descriptors");
3526 fd = myfileno2;
3527 }
3528 setinputfd(fd, push);
3529 INTON;
3530}
3531
3532
3533static void
3534tryexec(char *cmd, char **argv, char **envp)
3535{
3536 int e;
3537
3538#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3539 char *name = cmd;
3540 char** argv_l=argv;
3541 int argc_l;
3542#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3543 name = get_last_path_component(name);
3544#endif
3545 argv_l=envp;
3546 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3547 putenv(*argv_l);
3548 argv_l=argv;
3549 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3550 optind = 1;
3551 run_applet_by_name(name, argc_l, argv);
3552#endif
3553 execve(cmd, argv, envp);
3554 e = errno;
3555 if (e == ENOEXEC) {
3556 INTOFF;
3557 initshellproc();
3558 setinputfile(cmd, 0);
3559 commandname = arg0 = savestr(argv[0]);
3560 setparam(argv + 1);
3561 exraise(EXSHELLPROC);
3562 }
3563 errno = e;
3564}
3565
3566static char *commandtext (const union node *);
3567
3568/*
3569 * Do a path search. The variable path (passed by reference) should be
3570 * set to the start of the path before the first call; padvance will update
3571 * this value as it proceeds. Successive calls to padvance will return
3572 * the possible path expansions in sequence. If an option (indicated by
3573 * a percent sign) appears in the path entry then the global variable
3574 * pathopt will be set to point to it; otherwise pathopt will be set to
3575 * NULL.
3576 */
3577
3578static const char *pathopt;
3579
3580static void growstackblock(void);
3581
3582
3583static char *
3584padvance(const char **path, const char *name)
3585{
3586 const char *p;
3587 char *q;
3588 const char *start;
3589 int len;
3590
3591 if (*path == NULL)
3592 return NULL;
3593 start = *path;
3594 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3595 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3596 while (stackblocksize() < len)
3597 growstackblock();
3598 q = stackblock();
3599 if (p != start) {
3600 memcpy(q, start, p - start);
3601 q += p - start;
3602 *q++ = '/';
3603 }
3604 strcpy(q, name);
3605 pathopt = NULL;
3606 if (*p == '%') {
3607 pathopt = ++p;
3608 while (*p && *p != ':') p++;
3609 }
3610 if (*p == ':')
3611 *path = p + 1;
3612 else
3613 *path = NULL;
3614 return stalloc(len);
3615}
3616
3617/*
3618 * Wrapper around strcmp for qsort/bsearch/...
3619 */
3620static int
3621pstrcmp(const void *a, const void *b)
3622{
3623 return strcmp((const char *) a, (*(const char *const *) b) + 1);
3624}
3625
3626/*
3627 * Find a keyword is in a sorted array.
3628 */
3629
3630static const char *const *
3631findkwd(const char *s)
3632{
3633 return bsearch(s, tokname_array + KWDOFFSET,
3634 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3635 sizeof(const char *), pstrcmp);
3636}
3637
3638
3639/*** Command hashing code ***/
3640
3641
3642static int
3643hashcmd(argc, argv)
3644 int argc;
3645 char **argv;
3646{
3647 struct tblentry **pp;
3648 struct tblentry *cmdp;
3649 int c;
3650 int verbose;
3651 struct cmdentry entry;
3652 char *name;
3653#ifdef ASH_ALIAS
3654 const struct alias *ap;
3655#endif
3656
3657 verbose = 0;
3658 while ((c = nextopt("rvV")) != '\0') {
3659 if (c == 'r') {
3660 clearcmdentry(0);
3661 return 0;
3662 } else if (c == 'v' || c == 'V') {
3663 verbose = c;
3664 }
3665 }
3666 if (*argptr == NULL) {
3667 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3668 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3669 if (cmdp->cmdtype != CMDBUILTIN) {
3670 printentry(cmdp, verbose);
3671 }
3672 }
3673 }
3674 return 0;
3675 }
3676 c = 0;
3677 while ((name = *argptr++) != NULL) {
3678 if ((cmdp = cmdlookup(name, 0)) != NULL
3679 && (cmdp->cmdtype == CMDNORMAL
3680 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3681 delete_cmd_entry();
3682#ifdef ASH_ALIAS
3683 /* Then look at the aliases */
3684 if ((ap = lookupalias(name, 0)) != NULL) {
3685 if (verbose=='v')
3686 printf("%s is an alias for %s\n", name, ap->val);
3687 else
3688 printalias(ap);
3689 continue;
3690 }
3691#endif
3692 /* First look at the keywords */
3693 if (findkwd(name)!=0) {
3694 if (verbose=='v')
3695 printf("%s is a shell keyword\n", name);
3696 else
3697 printf(snlfmt, name);
3698 continue;
3699 }
3700
3701 find_command(name, &entry, DO_ERR, pathval());
3702 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3703 else if (verbose) {
3704 cmdp = cmdlookup(name, 0);
3705 if (cmdp) printentry(cmdp, verbose=='v');
3706 flushall();
3707 }
3708 }
3709 return c;
3710}
3711
3712static void
3713printentry(cmdp, verbose)
3714 struct tblentry *cmdp;
3715 int verbose;
3716 {
3717 int idx;
3718 const char *path;
3719 char *name;
3720
3721 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
3722 if (cmdp->cmdtype == CMDNORMAL) {
3723 idx = cmdp->param.index;
3724 path = pathval();
3725 do {
3726 name = padvance(&path, cmdp->cmdname);
3727 stunalloc(name);
3728 } while (--idx >= 0);
3729 if(verbose)
3730 out1str(name);
3731 } else if (cmdp->cmdtype == CMDBUILTIN) {
3732 if(verbose)
3733 out1str("a shell builtin");
3734 } else if (cmdp->cmdtype == CMDFUNCTION) {
3735 if (verbose) {
3736 INTOFF;
3737 out1str("a function\n");
3738 name = commandtext(cmdp->param.func);
3739 printf("%s() {\n %s\n}", cmdp->cmdname, name);
3740 ckfree(name);
3741 INTON;
3742 }
3743#ifdef DEBUG
3744 } else {
3745 error("internal error: cmdtype %d", cmdp->cmdtype);
3746#endif
3747 }
3748 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
3749}
3750
3751
3752
3753/*** List the available builtins ***/
3754
3755
3756static int helpcmd(int argc, char** argv)
3757{
3758 int col, i;
3759
3760 printf("\nBuilt-in commands:\n-------------------\n");
3761 for (col=0, i=0; i < NUMBUILTINS; i++) {
3762 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3763 builtincmds[i].name+1);
3764 if (col > 60) {
3765 printf("\n");
3766 col = 0;
3767 }
3768 }
3769#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3770 {
3771 extern const struct BB_applet applets[];
3772 extern const size_t NUM_APPLETS;
3773
3774 for (i=0; i < NUM_APPLETS; i++) {
3775
3776 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3777 applets[i].name);
3778 if (col > 60) {
3779 printf("\n");
3780 col = 0;
3781 }
3782 }
3783 }
3784#endif
3785 printf("\n\n");
3786 return EXIT_SUCCESS;
3787}
3788
3789/*
3790 * Resolve a command name. If you change this routine, you may have to
3791 * change the shellexec routine as well.
3792 */
3793
3794static int prefix (const char *, const char *);
3795
3796static void
3797find_command(const char *name, struct cmdentry *entry, int act, const char *path)
3798{
3799 struct tblentry *cmdp;
3800 int idx;
3801 int prev;
3802 char *fullname;
3803 struct stat statb;
3804 int e;
3805 int bltin;
3806 int firstchange;
3807 int updatetbl;
3808 int regular;
3809 struct builtincmd *bcmd;
3810
3811 /* If name contains a slash, don't use the hash table */
3812 if (strchr(name, '/') != NULL) {
3813 if (act & DO_ABS) {
3814 while (stat(name, &statb) < 0) {
3815 if (errno != ENOENT && errno != ENOTDIR)
3816 e = errno;
3817 entry->cmdtype = CMDUNKNOWN;
3818 entry->u.index = -1;
3819 return;
3820 }
3821 entry->cmdtype = CMDNORMAL;
3822 entry->u.index = -1;
3823 return;
3824 }
3825 entry->cmdtype = CMDNORMAL;
3826 entry->u.index = 0;
3827 return;
3828 }
3829
3830 updatetbl = 1;
3831 if (act & DO_BRUTE) {
3832 firstchange = path_change(path, &bltin);
3833 } else {
3834 bltin = builtinloc;
3835 firstchange = 9999;
3836 }
3837
3838 /* If name is in the table, and not invalidated by cd, we're done */
3839 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3840 if (cmdp->cmdtype == CMDFUNCTION) {
3841 if (act & DO_NOFUN) {
3842 updatetbl = 0;
3843 } else {
3844 goto success;
3845 }
3846 } else if (act & DO_BRUTE) {
3847 if ((cmdp->cmdtype == CMDNORMAL &&
3848 cmdp->param.index >= firstchange) ||
3849 (cmdp->cmdtype == CMDBUILTIN &&
3850 ((builtinloc < 0 && bltin >= 0) ?
3851 bltin : builtinloc) >= firstchange)) {
3852 /* need to recompute the entry */
3853 } else {
3854 goto success;
3855 }
3856 } else {
3857 goto success;
3858 }
3859 }
3860
3861 bcmd = find_builtin(name);
3862 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
3863
3864 if (regular) {
3865 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
3866 goto success;
3867 }
3868 } else if (act & DO_BRUTE) {
3869 if (firstchange == 0) {
3870 updatetbl = 0;
3871 }
3872 }
3873
3874 /* If %builtin not in path, check for builtin next */
3875 if (regular || (bltin < 0 && bcmd)) {
3876builtin:
3877 if (!updatetbl) {
3878 entry->cmdtype = CMDBUILTIN;
3879 entry->u.cmd = bcmd;
3880 return;
3881 }
3882 INTOFF;
3883 cmdp = cmdlookup(name, 1);
3884 cmdp->cmdtype = CMDBUILTIN;
3885 cmdp->param.cmd = bcmd;
3886 INTON;
3887 goto success;
3888 }
3889
3890 /* We have to search path. */
3891 prev = -1; /* where to start */
3892 if (cmdp && cmdp->rehash) { /* doing a rehash */
3893 if (cmdp->cmdtype == CMDBUILTIN)
3894 prev = builtinloc;
3895 else
3896 prev = cmdp->param.index;
3897 }
3898
3899 e = ENOENT;
3900 idx = -1;
3901loop:
3902 while ((fullname = padvance(&path, name)) != NULL) {
3903 stunalloc(fullname);
3904 idx++;
3905 if (idx >= firstchange) {
3906 updatetbl = 0;
3907 }
3908 if (pathopt) {
3909 if (prefix("builtin", pathopt)) {
3910 if ((bcmd = find_builtin(name))) {
3911 goto builtin;
3912 }
3913 continue;
3914 } else if (!(act & DO_NOFUN) &&
3915 prefix("func", pathopt)) {
3916 /* handled below */
3917 } else {
3918 continue; /* ignore unimplemented options */
3919 }
3920 }
3921 /* if rehash, don't redo absolute path names */
3922 if (fullname[0] == '/' && idx <= prev &&
3923 idx < firstchange) {
3924 if (idx < prev)
3925 continue;
3926 TRACE(("searchexec \"%s\": no change\n", name));
3927 goto success;
3928 }
3929 while (stat(fullname, &statb) < 0) {
3930 if (errno != ENOENT && errno != ENOTDIR)
3931 e = errno;
3932 goto loop;
3933 }
3934 e = EACCES; /* if we fail, this will be the error */
3935 if (!S_ISREG(statb.st_mode))
3936 continue;
3937 if (pathopt) { /* this is a %func directory */
3938 stalloc(strlen(fullname) + 1);
3939 readcmdfile(fullname);
3940 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3941 error("%s not defined in %s", name, fullname);
3942 stunalloc(fullname);
3943 goto success;
3944 }
3945 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3946 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3947 be a function and we're being called with DO_NOFUN */
3948 if (!updatetbl) {
3949 entry->cmdtype = CMDNORMAL;
3950 entry->u.index = idx;
3951 return;
3952 }
3953 INTOFF;
3954 cmdp = cmdlookup(name, 1);
3955 cmdp->cmdtype = CMDNORMAL;
3956 cmdp->param.index = idx;
3957 INTON;
3958 goto success;
3959 }
3960
3961 /* We failed. If there was an entry for this command, delete it */
3962 if (cmdp && updatetbl)
3963 delete_cmd_entry();
3964 if (act & DO_ERR)
3965 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
3966 entry->cmdtype = CMDUNKNOWN;
3967 return;
3968
3969success:
3970 cmdp->rehash = 0;
3971 entry->cmdtype = cmdp->cmdtype;
3972 entry->u = cmdp->param;
3973}
3974
3975
3976
3977/*
3978 * Search the table of builtin commands.
3979 */
3980
3981static int
3982bstrcmp(const void *name, const void *b)
3983{
3984 return strcmp((const char *)name, (*(const char *const *) b)+1);
3985}
3986
3987static struct builtincmd *
3988find_builtin(const char *name)
3989{
3990 struct builtincmd *bp;
3991
3992 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
3993 bstrcmp
3994 );
3995 return bp;
3996}
3997
3998
3999/*
4000 * Called when a cd is done. Marks all commands so the next time they
4001 * are executed they will be rehashed.
4002 */
4003
4004static void
4005hashcd(void) {
4006 struct tblentry **pp;
4007 struct tblentry *cmdp;
4008
4009 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4010 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4011 if (cmdp->cmdtype == CMDNORMAL
4012 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4013 cmdp->rehash = 1;
4014 }
4015 }
4016}
4017
4018
4019
4020/*
4021 * Called before PATH is changed. The argument is the new value of PATH;
4022 * pathval() still returns the old value at this point. Called with
4023 * interrupts off.
4024 */
4025
4026static void
4027changepath(const char *newval)
4028{
4029 int firstchange;
4030 int bltin;
4031
4032 firstchange = path_change(newval, &bltin);
4033 if (builtinloc < 0 && bltin >= 0)
4034 builtinloc = bltin; /* zap builtins */
4035 clearcmdentry(firstchange);
4036 builtinloc = bltin;
4037}
4038
4039
4040/*
4041 * Clear out command entries. The argument specifies the first entry in
4042 * PATH which has changed.
4043 */
4044
4045static void
4046clearcmdentry(firstchange)
4047 int firstchange;
4048{
4049 struct tblentry **tblp;
4050 struct tblentry **pp;
4051 struct tblentry *cmdp;
4052
4053 INTOFF;
4054 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4055 pp = tblp;
4056 while ((cmdp = *pp) != NULL) {
4057 if ((cmdp->cmdtype == CMDNORMAL &&
4058 cmdp->param.index >= firstchange)
4059 || (cmdp->cmdtype == CMDBUILTIN &&
4060 builtinloc >= firstchange)) {
4061 *pp = cmdp->next;
4062 ckfree(cmdp);
4063 } else {
4064 pp = &cmdp->next;
4065 }
4066 }
4067 }
4068 INTON;
4069}
4070
4071
4072/*
4073 * Delete all functions.
4074 */
4075
4076static void
4077deletefuncs(void) {
4078 struct tblentry **tblp;
4079 struct tblentry **pp;
4080 struct tblentry *cmdp;
4081
4082 INTOFF;
4083 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4084 pp = tblp;
4085 while ((cmdp = *pp) != NULL) {
4086 if (cmdp->cmdtype == CMDFUNCTION) {
4087 *pp = cmdp->next;
4088 freefunc(cmdp->param.func);
4089 ckfree(cmdp);
4090 } else {
4091 pp = &cmdp->next;
4092 }
4093 }
4094 }
4095 INTON;
4096}
4097
4098
4099
4100/*
4101 * Locate a command in the command hash table. If "add" is nonzero,
4102 * add the command to the table if it is not already present. The
4103 * variable "lastcmdentry" is set to point to the address of the link
4104 * pointing to the entry, so that delete_cmd_entry can delete the
4105 * entry.
4106 */
4107
4108static struct tblentry **lastcmdentry;
4109
4110static struct tblentry *
4111cmdlookup(const char *name, int add)
4112{
4113 int hashval;
4114 const char *p;
4115 struct tblentry *cmdp;
4116 struct tblentry **pp;
4117
4118 p = name;
4119 hashval = *p << 4;
4120 while (*p)
4121 hashval += *p++;
4122 hashval &= 0x7FFF;
4123 pp = &cmdtable[hashval % CMDTABLESIZE];
4124 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4125 if (equal(cmdp->cmdname, name))
4126 break;
4127 pp = &cmdp->next;
4128 }
4129 if (add && cmdp == NULL) {
4130 INTOFF;
4131 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4132 + strlen(name) + 1);
4133 cmdp->next = NULL;
4134 cmdp->cmdtype = CMDUNKNOWN;
4135 cmdp->rehash = 0;
4136 strcpy(cmdp->cmdname, name);
4137 INTON;
4138 }
4139 lastcmdentry = pp;
4140 return cmdp;
4141}
4142
4143/*
4144 * Delete the command entry returned on the last lookup.
4145 */
4146
4147static void
4148delete_cmd_entry() {
4149 struct tblentry *cmdp;
4150
4151 INTOFF;
4152 cmdp = *lastcmdentry;
4153 *lastcmdentry = cmdp->next;
4154 ckfree(cmdp);
4155 INTON;
4156}
4157
4158
4159
4160
4161
4162static const unsigned char nodesize[26] = {
4163 ALIGN(sizeof (struct nbinary)),
4164 ALIGN(sizeof (struct ncmd)),
4165 ALIGN(sizeof (struct npipe)),
4166 ALIGN(sizeof (struct nredir)),
4167 ALIGN(sizeof (struct nredir)),
4168 ALIGN(sizeof (struct nredir)),
4169 ALIGN(sizeof (struct nbinary)),
4170 ALIGN(sizeof (struct nbinary)),
4171 ALIGN(sizeof (struct nif)),
4172 ALIGN(sizeof (struct nbinary)),
4173 ALIGN(sizeof (struct nbinary)),
4174 ALIGN(sizeof (struct nfor)),
4175 ALIGN(sizeof (struct ncase)),
4176 ALIGN(sizeof (struct nclist)),
4177 ALIGN(sizeof (struct narg)),
4178 ALIGN(sizeof (struct narg)),
4179 ALIGN(sizeof (struct nfile)),
4180 ALIGN(sizeof (struct nfile)),
4181 ALIGN(sizeof (struct nfile)),
4182 ALIGN(sizeof (struct nfile)),
4183 ALIGN(sizeof (struct nfile)),
4184 ALIGN(sizeof (struct ndup)),
4185 ALIGN(sizeof (struct ndup)),
4186 ALIGN(sizeof (struct nhere)),
4187 ALIGN(sizeof (struct nhere)),
4188 ALIGN(sizeof (struct nnot)),
4189};
4190
4191
4192
4193/*
4194 * Delete a function if it exists.
4195 */
4196
4197static void
4198unsetfunc(char *name)
4199{
4200 struct tblentry *cmdp;
4201
4202 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4203 freefunc(cmdp->param.func);
4204 delete_cmd_entry();
4205 }
4206}
4207
4208
4209/*
4210 * Locate and print what a word is...
4211 */
4212
4213static int
4214typecmd(int argc, char **argv)
4215{
4216 int i;
4217 int err = 0;
4218 char *argv_a[2];
4219
4220 argv_a[1] = 0;
4221
4222 for (i = 1; i < argc; i++) {
4223 argv_a[0] = argv[i];
4224 argptr = argv_a;
4225 optptr = "v";
4226 err |= hashcmd(argc, argv);
4227 }
4228 return err;
4229}
4230
4231#ifdef ASH_CMDCMD
4232static int
4233commandcmd(argc, argv)
4234 int argc;
4235 char **argv;
4236{
4237 int c;
4238 int default_path = 0;
4239 int verify_only = 0;
4240 int verbose_verify_only = 0;
4241
4242 while ((c = nextopt("pvV")) != '\0')
4243 switch (c) {
4244 case 'p':
4245 default_path = 1;
4246 break;
4247 case 'v':
4248 verify_only = 1;
4249 break;
4250 case 'V':
4251 verbose_verify_only = 1;
4252 break;
4253 }
4254
4255 if (default_path + verify_only + verbose_verify_only > 1 ||
4256 !*argptr) {
4257 out2str(
4258 "command [-p] command [arg ...]\n"
4259 "command {-v|-V} command\n");
4260 return EX_USAGE;
4261 }
4262
4263 if (verify_only || verbose_verify_only) {
4264 char *argv_a[2];
4265
4266 argv_a[1] = 0;
4267 argv_a[0] = *argptr;
4268 argptr = argv_a;
4269 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4270 return hashcmd(argc, argv);
4271 }
4272
4273 return 0;
4274}
4275#endif
4276
4277static int
4278path_change(newval, bltin)
4279 const char *newval;
4280 int *bltin;
4281{
4282 const char *old, *new;
4283 int idx;
4284 int firstchange;
4285
4286 old = pathval();
4287 new = newval;
4288 firstchange = 9999; /* assume no change */
4289 idx = 0;
4290 *bltin = -1;
4291 for (;;) {
4292 if (*old != *new) {
4293 firstchange = idx;
4294 if ((*old == '\0' && *new == ':')
4295 || (*old == ':' && *new == '\0'))
4296 firstchange++;
4297 old = new; /* ignore subsequent differences */
4298 }
4299 if (*new == '\0')
4300 break;
4301 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4302 *bltin = idx;
4303 if (*new == ':') {
4304 idx++;
4305 }
4306 new++, old++;
4307 }
4308 if (builtinloc >= 0 && *bltin < 0)
4309 firstchange = 0;
4310 return firstchange;
4311}
4312/*
4313 * Routines to expand arguments to commands. We have to deal with
4314 * backquotes, shell variables, and file metacharacters.
4315 */
4316/*
4317 * _rmescape() flags
4318 */
4319#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4320#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4321
4322/*
4323 * Structure specifying which parts of the string should be searched
4324 * for IFS characters.
4325 */
4326
4327struct ifsregion {
4328 struct ifsregion *next; /* next region in list */
4329 int begoff; /* offset of start of region */
4330 int endoff; /* offset of end of region */
4331 int nulonly; /* search for nul bytes only */
4332};
4333
4334
4335static char *expdest; /* output of current string */
4336static struct nodelist *argbackq; /* list of back quote expressions */
4337static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4338static struct ifsregion *ifslastp; /* last struct in list */
4339static struct arglist exparg; /* holds expanded arg list */
4340
4341static void argstr (char *, int);
4342static char *exptilde (char *, int);
4343static void expbackq (union node *, int, int);
4344static int subevalvar (char *, char *, int, int, int, int, int);
4345static int varisset (char *, int);
4346static void strtodest (const char *, int, int);
4347static void varvalue (char *, int, int);
4348static void recordregion (int, int, int);
4349static void removerecordregions (int);
4350static void ifsbreakup (char *, struct arglist *);
4351static void ifsfree (void);
4352static void expandmeta (struct strlist *, int);
4353#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4354#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4355#if !defined(GLOB_BROKEN)
4356static void addglob (const glob_t *);
4357#endif
4358#endif
4359#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4360static void expmeta (char *, char *);
4361#endif
4362#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4363static struct strlist *expsort (struct strlist *);
4364static struct strlist *msort (struct strlist *, int);
4365#endif
4366static int patmatch (char *, char *, int);
4367#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4368static int patmatch2 (char *, char *, int);
4369#else
4370static int pmatch (char *, char *, int);
4371#define patmatch2 patmatch
4372#endif
4373static char *cvtnum (int, char *);
4374
4375/*
4376 * Expand shell variables and backquotes inside a here document.
4377 */
4378
4379/* arg: the document, fd: where to write the expanded version */
4380static inline void
4381expandhere(union node *arg, int fd)
4382{
4383 herefd = fd;
4384 expandarg(arg, (struct arglist *)NULL, 0);
4385 xwrite(fd, stackblock(), expdest - stackblock());
4386}
4387
4388
4389/*
4390 * Perform variable substitution and command substitution on an argument,
4391 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4392 * perform splitting and file name expansion. When arglist is NULL, perform
4393 * here document expansion.
4394 */
4395
4396static void
4397expandarg(arg, arglist, flag)
4398 union node *arg;
4399 struct arglist *arglist;
4400 int flag;
4401{
4402 struct strlist *sp;
4403 char *p;
4404
4405 argbackq = arg->narg.backquote;
4406 STARTSTACKSTR(expdest);
4407 ifsfirst.next = NULL;
4408 ifslastp = NULL;
4409 argstr(arg->narg.text, flag);
4410 if (arglist == NULL) {
4411 return; /* here document expanded */
4412 }
4413 STPUTC('\0', expdest);
4414 p = grabstackstr(expdest);
4415 exparg.lastp = &exparg.list;
4416 /*
4417 * TODO - EXP_REDIR
4418 */
4419 if (flag & EXP_FULL) {
4420 ifsbreakup(p, &exparg);
4421 *exparg.lastp = NULL;
4422 exparg.lastp = &exparg.list;
4423 expandmeta(exparg.list, flag);
4424 } else {
4425 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4426 rmescapes(p);
4427 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4428 sp->text = p;
4429 *exparg.lastp = sp;
4430 exparg.lastp = &sp->next;
4431 }
4432 ifsfree();
4433 *exparg.lastp = NULL;
4434 if (exparg.list) {
4435 *arglist->lastp = exparg.list;
4436 arglist->lastp = exparg.lastp;
4437 }
4438}
4439
4440
4441/*
4442 * Expand a variable, and return a pointer to the next character in the
4443 * input string.
4444 */
4445
4446static inline char * evalvar(char *p, int flag)
4447{
4448 int subtype;
4449 int varflags;
4450 char *var;
4451 const char *val;
4452 int patloc;
4453 int c;
4454 int set;
4455 int special;
4456 int startloc;
4457 int varlen;
4458 int easy;
4459 int quotes = flag & (EXP_FULL | EXP_CASE);
4460
4461 varflags = *p++;
4462 subtype = varflags & VSTYPE;
4463 var = p;
4464 special = 0;
4465 if (! is_name(*p))
4466 special = 1;
4467 p = strchr(p, '=') + 1;
4468again: /* jump here after setting a variable with ${var=text} */
4469 if (special) {
4470 set = varisset(var, varflags & VSNUL);
4471 val = NULL;
4472 } else {
4473 val = lookupvar(var);
4474 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4475 val = NULL;
4476 set = 0;
4477 } else
4478 set = 1;
4479 }
4480 varlen = 0;
4481 startloc = expdest - stackblock();
4482 if (set && subtype != VSPLUS) {
4483 /* insert the value of the variable */
4484 if (special) {
4485 varvalue(var, varflags & VSQUOTE, flag);
4486 if (subtype == VSLENGTH) {
4487 varlen = expdest - stackblock() - startloc;
4488 STADJUST(-varlen, expdest);
4489 }
4490 } else {
4491 if (subtype == VSLENGTH) {
4492 varlen = strlen(val);
4493 } else {
4494 strtodest(
4495 val,
4496 varflags & VSQUOTE ?
4497 DQSYNTAX : BASESYNTAX,
4498 quotes
4499 );
4500 }
4501 }
4502 }
4503
4504 if (subtype == VSPLUS)
4505 set = ! set;
4506
4507 easy = ((varflags & VSQUOTE) == 0 ||
4508 (*var == '@' && shellparam.nparam != 1));
4509
4510
4511 switch (subtype) {
4512 case VSLENGTH:
4513 expdest = cvtnum(varlen, expdest);
4514 goto record;
4515
4516 case VSNORMAL:
4517 if (!easy)
4518 break;
4519record:
4520 recordregion(startloc, expdest - stackblock(),
4521 varflags & VSQUOTE);
4522 break;
4523
4524 case VSPLUS:
4525 case VSMINUS:
4526 if (!set) {
4527 argstr(p, flag);
4528 break;
4529 }
4530 if (easy)
4531 goto record;
4532 break;
4533
4534 case VSTRIMLEFT:
4535 case VSTRIMLEFTMAX:
4536 case VSTRIMRIGHT:
4537 case VSTRIMRIGHTMAX:
4538 if (!set)
4539 break;
4540 /*
4541 * Terminate the string and start recording the pattern
4542 * right after it
4543 */
4544 STPUTC('\0', expdest);
4545 patloc = expdest - stackblock();
4546 if (subevalvar(p, NULL, patloc, subtype,
4547 startloc, varflags, quotes) == 0) {
4548 int amount = (expdest - stackblock() - patloc) + 1;
4549 STADJUST(-amount, expdest);
4550 }
4551 /* Remove any recorded regions beyond start of variable */
4552 removerecordregions(startloc);
4553 goto record;
4554
4555 case VSASSIGN:
4556 case VSQUESTION:
4557 if (!set) {
4558 if (subevalvar(p, var, 0, subtype, startloc,
4559 varflags, quotes)) {
4560 varflags &= ~VSNUL;
4561 /*
4562 * Remove any recorded regions beyond
4563 * start of variable
4564 */
4565 removerecordregions(startloc);
4566 goto again;
4567 }
4568 break;
4569 }
4570 if (easy)
4571 goto record;
4572 break;
4573
4574#ifdef DEBUG
4575 default:
4576 abort();
4577#endif
4578 }
4579
4580 if (subtype != VSNORMAL) { /* skip to end of alternative */
4581 int nesting = 1;
4582 for (;;) {
4583 if ((c = *p++) == CTLESC)
4584 p++;
4585 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4586 if (set)
4587 argbackq = argbackq->next;
4588 } else if (c == CTLVAR) {
4589 if ((*p++ & VSTYPE) != VSNORMAL)
4590 nesting++;
4591 } else if (c == CTLENDVAR) {
4592 if (--nesting == 0)
4593 break;
4594 }
4595 }
4596 }
4597 return p;
4598}
4599
4600
4601/*
4602 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4603 * characters to allow for further processing. Otherwise treat
4604 * $@ like $* since no splitting will be performed.
4605 */
4606
4607static void
4608argstr(p, flag)
4609 char *p;
4610 int flag;
4611{
4612 char c;
4613 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4614 int firsteq = 1;
4615
4616 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4617 p = exptilde(p, flag);
4618 for (;;) {
4619 switch (c = *p++) {
4620 case '\0':
4621 case CTLENDVAR: /* ??? */
4622 goto breakloop;
4623 case CTLQUOTEMARK:
4624 /* "$@" syntax adherence hack */
4625 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4626 break;
4627 if ((flag & EXP_FULL) != 0)
4628 STPUTC(c, expdest);
4629 break;
4630 case CTLESC:
4631 if (quotes)
4632 STPUTC(c, expdest);
4633 c = *p++;
4634 STPUTC(c, expdest);
4635 break;
4636 case CTLVAR:
4637 p = evalvar(p, flag);
4638 break;
4639 case CTLBACKQ:
4640 case CTLBACKQ|CTLQUOTE:
4641 expbackq(argbackq->n, c & CTLQUOTE, flag);
4642 argbackq = argbackq->next;
4643 break;
4644#ifdef ASH_MATH_SUPPORT
4645 case CTLENDARI:
4646 expari(flag);
4647 break;
4648#endif
4649 case ':':
4650 case '=':
4651 /*
4652 * sort of a hack - expand tildes in variable
4653 * assignments (after the first '=' and after ':'s).
4654 */
4655 STPUTC(c, expdest);
4656 if (flag & EXP_VARTILDE && *p == '~') {
4657 if (c == '=') {
4658 if (firsteq)
4659 firsteq = 0;
4660 else
4661 break;
4662 }
4663 p = exptilde(p, flag);
4664 }
4665 break;
4666 default:
4667 STPUTC(c, expdest);
4668 }
4669 }
4670breakloop:;
4671 return;
4672}
4673
4674static char *
4675exptilde(p, flag)
4676 char *p;
4677 int flag;
4678{
4679 char c, *startp = p;
4680 struct passwd *pw;
4681 const char *home;
4682 int quotes = flag & (EXP_FULL | EXP_CASE);
4683
4684 while ((c = *p) != '\0') {
4685 switch(c) {
4686 case CTLESC:
4687 return (startp);
4688 case CTLQUOTEMARK:
4689 return (startp);
4690 case ':':
4691 if (flag & EXP_VARTILDE)
4692 goto done;
4693 break;
4694 case '/':
4695 goto done;
4696 }
4697 p++;
4698 }
4699done:
4700 *p = '\0';
4701 if (*(startp+1) == '\0') {
4702 if ((home = lookupvar("HOME")) == NULL)
4703 goto lose;
4704 } else {
4705 if ((pw = getpwnam(startp+1)) == NULL)
4706 goto lose;
4707 home = pw->pw_dir;
4708 }
4709 if (*home == '\0')
4710 goto lose;
4711 *p = c;
4712 strtodest(home, SQSYNTAX, quotes);
4713 return (p);
4714lose:
4715 *p = c;
4716 return (startp);
4717}
4718
4719
4720static void
4721removerecordregions(int endoff)
4722{
4723 if (ifslastp == NULL)
4724 return;
4725
4726 if (ifsfirst.endoff > endoff) {
4727 while (ifsfirst.next != NULL) {
4728 struct ifsregion *ifsp;
4729 INTOFF;
4730 ifsp = ifsfirst.next->next;
4731 ckfree(ifsfirst.next);
4732 ifsfirst.next = ifsp;
4733 INTON;
4734 }
4735 if (ifsfirst.begoff > endoff)
4736 ifslastp = NULL;
4737 else {
4738 ifslastp = &ifsfirst;
4739 ifsfirst.endoff = endoff;
4740 }
4741 return;
4742 }
4743
4744 ifslastp = &ifsfirst;
4745 while (ifslastp->next && ifslastp->next->begoff < endoff)
4746 ifslastp=ifslastp->next;
4747 while (ifslastp->next != NULL) {
4748 struct ifsregion *ifsp;
4749 INTOFF;
4750 ifsp = ifslastp->next->next;
4751 ckfree(ifslastp->next);
4752 ifslastp->next = ifsp;
4753 INTON;
4754 }
4755 if (ifslastp->endoff > endoff)
4756 ifslastp->endoff = endoff;
4757}
4758
4759
4760#ifdef ASH_MATH_SUPPORT
4761/*
4762 * Expand arithmetic expression. Backup to start of expression,
4763 * evaluate, place result in (backed up) result, adjust string position.
4764 */
4765static void
4766expari(int flag)
4767{
4768 char *p, *start;
4769 int errcode;
4770 int result;
4771 int begoff;
4772 int quotes = flag & (EXP_FULL | EXP_CASE);
4773 int quoted;
4774
4775 /* ifsfree(); */
4776
4777 /*
4778 * This routine is slightly over-complicated for
4779 * efficiency. First we make sure there is
4780 * enough space for the result, which may be bigger
4781 * than the expression if we add exponentation. Next we
4782 * scan backwards looking for the start of arithmetic. If the
4783 * next previous character is a CTLESC character, then we
4784 * have to rescan starting from the beginning since CTLESC
4785 * characters have to be processed left to right.
4786 */
4787 CHECKSTRSPACE(10, expdest);
4788 USTPUTC('\0', expdest);
4789 start = stackblock();
4790 p = expdest - 1;
4791 while (*p != CTLARI && p >= start)
4792 --p;
4793 if (*p != CTLARI)
4794 error("missing CTLARI (shouldn't happen)");
4795 if (p > start && *(p-1) == CTLESC)
4796 for (p = start; *p != CTLARI; p++)
4797 if (*p == CTLESC)
4798 p++;
4799
4800 if (p[1] == '"')
4801 quoted=1;
4802 else
4803 quoted=0;
4804 begoff = p - start;
4805 removerecordregions(begoff);
4806 if (quotes)
4807 rmescapes(p+2);
4808 result = arith(p+2, &errcode);
4809 if (errcode < 0) {
4810 if(errcode == -2)
4811 error("divide by zero");
4812 else
4813 error("syntax error: \"%s\"\n", p+2);
4814 }
4815 snprintf(p, 12, "%d", result);
4816
4817 while (*p++)
4818 ;
4819
4820 if (quoted == 0)
4821 recordregion(begoff, p - 1 - start, 0);
4822 result = expdest - p + 1;
4823 STADJUST(-result, expdest);
4824}
4825#endif
4826
4827/*
4828 * Expand stuff in backwards quotes.
4829 */
4830
4831static void
4832expbackq(cmd, quoted, flag)
4833 union node *cmd;
4834 int quoted;
4835 int flag;
4836{
4837 volatile struct backcmd in;
4838 int i;
4839 char buf[128];
4840 char *p;
4841 char *dest = expdest;
4842 volatile struct ifsregion saveifs;
4843 struct ifsregion *volatile savelastp;
4844 struct nodelist *volatile saveargbackq;
4845 char lastc;
4846 int startloc = dest - stackblock();
4847 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
4848 volatile int saveherefd;
4849 int quotes = flag & (EXP_FULL | EXP_CASE);
4850 struct jmploc jmploc;
4851 struct jmploc *volatile savehandler;
4852 int ex;
4853
4854#if __GNUC__
4855 /* Avoid longjmp clobbering */
4856 (void) &dest;
4857 (void) &syntax;
4858#endif
4859
4860 in.fd = -1;
4861 in.buf = 0;
4862 in.jp = 0;
4863
4864 INTOFF;
4865 saveifs = ifsfirst;
4866 savelastp = ifslastp;
4867 saveargbackq = argbackq;
4868 saveherefd = herefd;
4869 herefd = -1;
4870 if ((ex = setjmp(jmploc.loc))) {
4871 goto err1;
4872 }
4873 savehandler = handler;
4874 handler = &jmploc;
4875 INTON;
4876 p = grabstackstr(dest);
4877 evalbackcmd(cmd, (struct backcmd *) &in);
4878 ungrabstackstr(p, dest);
4879err1:
4880 INTOFF;
4881 ifsfirst = saveifs;
4882 ifslastp = savelastp;
4883 argbackq = saveargbackq;
4884 herefd = saveherefd;
4885 if (ex) {
4886 goto err2;
4887 }
4888
4889 p = in.buf;
4890 lastc = '\0';
4891 for (;;) {
4892 if (--in.nleft < 0) {
4893 if (in.fd < 0)
4894 break;
4895 i = safe_read(in.fd, buf, sizeof buf);
4896 TRACE(("expbackq: read returns %d\n", i));
4897 if (i <= 0)
4898 break;
4899 p = buf;
4900 in.nleft = i - 1;
4901 }
4902 lastc = *p++;
4903 if (lastc != '\0') {
4904 if (quotes && SIT(lastc, syntax) == CCTL)
4905 STPUTC(CTLESC, dest);
4906 STPUTC(lastc, dest);
4907 }
4908 }
4909
4910 /* Eat all trailing newlines */
4911 for (; dest > stackblock() && dest[-1] == '\n';)
4912 STUNPUTC(dest);
4913
4914err2:
4915 if (in.fd >= 0)
4916 close(in.fd);
4917 if (in.buf)
4918 ckfree(in.buf);
4919 if (in.jp)
4920 exitstatus = waitforjob(in.jp);
4921 handler = savehandler;
4922 if (ex) {
4923 longjmp(handler->loc, 1);
4924 }
4925 if (quoted == 0)
4926 recordregion(startloc, dest - stackblock(), 0);
4927 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4928 (dest - stackblock()) - startloc,
4929 (dest - stackblock()) - startloc,
4930 stackblock() + startloc));
4931 expdest = dest;
4932 INTON;
4933}
4934
4935static int
4936subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4937 char *p;
4938 char *str;
4939 int strloc;
4940 int subtype;
4941 int startloc;
4942 int varflags;
4943 int quotes;
4944{
4945 char *startp;
4946 char *loc = NULL;
4947 char *q;
4948 int c = 0;
4949 int saveherefd = herefd;
4950 struct nodelist *saveargbackq = argbackq;
4951 int amount;
4952
4953 herefd = -1;
4954 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4955 STACKSTRNUL(expdest);
4956 herefd = saveherefd;
4957 argbackq = saveargbackq;
4958 startp = stackblock() + startloc;
4959 if (str == NULL)
4960 str = stackblock() + strloc;
4961
4962 switch (subtype) {
4963 case VSASSIGN:
4964 setvar(str, startp, 0);
4965 amount = startp - expdest;
4966 STADJUST(amount, expdest);
4967 varflags &= ~VSNUL;
4968 if (c != 0)
4969 *loc = c;
4970 return 1;
4971
4972 case VSQUESTION:
4973 if (*p != CTLENDVAR) {
4974 out2fmt(snlfmt, startp);
4975 error((char *)NULL);
4976 }
4977 error("%.*s: parameter %snot set", p - str - 1,
4978 str, (varflags & VSNUL) ? "null or "
4979 : nullstr);
4980 /* NOTREACHED */
4981
4982 case VSTRIMLEFT:
4983 for (loc = startp; loc < str; loc++) {
4984 c = *loc;
4985 *loc = '\0';
4986 if (patmatch2(str, startp, quotes))
4987 goto recordleft;
4988 *loc = c;
4989 if (quotes && *loc == CTLESC)
4990 loc++;
4991 }
4992 return 0;
4993
4994 case VSTRIMLEFTMAX:
4995 for (loc = str - 1; loc >= startp;) {
4996 c = *loc;
4997 *loc = '\0';
4998 if (patmatch2(str, startp, quotes))
4999 goto recordleft;
5000 *loc = c;
5001 loc--;
5002 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5003 for (q = startp; q < loc; q++)
5004 if (*q == CTLESC)
5005 q++;
5006 if (q > loc)
5007 loc--;
5008 }
5009 }
5010 return 0;
5011
5012 case VSTRIMRIGHT:
5013 for (loc = str - 1; loc >= startp;) {
5014 if (patmatch2(str, loc, quotes))
5015 goto recordright;
5016 loc--;
5017 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5018 for (q = startp; q < loc; q++)
5019 if (*q == CTLESC)
5020 q++;
5021 if (q > loc)
5022 loc--;
5023 }
5024 }
5025 return 0;
5026
5027 case VSTRIMRIGHTMAX:
5028 for (loc = startp; loc < str - 1; loc++) {
5029 if (patmatch2(str, loc, quotes))
5030 goto recordright;
5031 if (quotes && *loc == CTLESC)
5032 loc++;
5033 }
5034 return 0;
5035
5036#ifdef DEBUG
5037 default:
5038 abort();
5039#endif
5040 }
5041
5042recordleft:
5043 *loc = c;
5044 amount = ((str - 1) - (loc - startp)) - expdest;
5045 STADJUST(amount, expdest);
5046 while (loc != str - 1)
5047 *startp++ = *loc++;
5048 return 1;
5049
5050recordright:
5051 amount = loc - expdest;
5052 STADJUST(amount, expdest);
5053 STPUTC('\0', expdest);
5054 STADJUST(-1, expdest);
5055 return 1;
5056}
5057
5058
5059/*
5060 * Test whether a specialized variable is set.
5061 */
5062
5063static int
5064varisset(name, nulok)
5065 char *name;
5066 int nulok;
5067{
5068 if (*name == '!')
5069 return backgndpid != -1;
5070 else if (*name == '@' || *name == '*') {
5071 if (*shellparam.p == NULL)
5072 return 0;
5073
5074 if (nulok) {
5075 char **av;
5076
5077 for (av = shellparam.p; *av; av++)
5078 if (**av != '\0')
5079 return 1;
5080 return 0;
5081 }
5082 } else if (is_digit(*name)) {
5083 char *ap;
5084 int num = atoi(name);
5085
5086 if (num > shellparam.nparam)
5087 return 0;
5088
5089 if (num == 0)
5090 ap = arg0;
5091 else
5092 ap = shellparam.p[num - 1];
5093
5094 if (nulok && (ap == NULL || *ap == '\0'))
5095 return 0;
5096 }
5097 return 1;
5098}
5099
5100/*
5101 * Put a string on the stack.
5102 */
5103
5104static void
5105strtodest(const char *p, int syntax, int quotes)
5106{
5107 while (*p) {
5108 if (quotes && SIT(*p,syntax) == CCTL)
5109 STPUTC(CTLESC, expdest);
5110 STPUTC(*p++, expdest);
5111 }
5112}
5113
5114/*
5115 * Add the value of a specialized variable to the stack string.
5116 */
5117
5118static void
5119varvalue(char *name, int quoted, int flags)
5120{
5121 int num;
5122 char *p;
5123 int i;
5124 int sep;
5125 int sepq = 0;
5126 char **ap;
5127 int syntax;
5128 int allow_split = flags & EXP_FULL;
5129 int quotes = flags & (EXP_FULL | EXP_CASE);
5130
5131 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5132 switch (*name) {
5133 case '$':
5134 num = rootpid;
5135 goto numvar;
5136 case '?':
5137 num = oexitstatus;
5138 goto numvar;
5139 case '#':
5140 num = shellparam.nparam;
5141 goto numvar;
5142 case '!':
5143 num = backgndpid;
5144numvar:
5145 expdest = cvtnum(num, expdest);
5146 break;
5147 case '-':
5148 for (i = 0 ; i < NOPTS ; i++) {
5149 if (optent_val(i))
5150 STPUTC(optent_letter(optlist[i]), expdest);
5151 }
5152 break;
5153 case '@':
5154 if (allow_split && quoted) {
5155 sep = 1 << CHAR_BIT;
5156 goto param;
5157 }
5158 /* fall through */
5159 case '*':
5160 sep = ifsset() ? ifsval()[0] : ' ';
5161 if (quotes) {
5162 sepq = SIT(sep,syntax) == CCTL;
5163 }
5164param:
5165 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5166 strtodest(p, syntax, quotes);
5167 if (*ap && sep) {
5168 if (sepq)
5169 STPUTC(CTLESC, expdest);
5170 STPUTC(sep, expdest);
5171 }
5172 }
5173 break;
5174 case '0':
5175 strtodest(arg0, syntax, quotes);
5176 break;
5177 default:
5178 num = atoi(name);
5179 if (num > 0 && num <= shellparam.nparam) {
5180 strtodest(shellparam.p[num - 1], syntax, quotes);
5181 }
5182 break;
5183 }
5184}
5185
5186
5187/*
5188 * Record the fact that we have to scan this region of the
5189 * string for IFS characters.
5190 */
5191
5192static void
5193recordregion(start, end, nulonly)
5194 int start;
5195 int end;
5196 int nulonly;
5197{
5198 struct ifsregion *ifsp;
5199
5200 if (ifslastp == NULL) {
5201 ifsp = &ifsfirst;
5202 } else {
5203 INTOFF;
5204 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5205 ifsp->next = NULL;
5206 ifslastp->next = ifsp;
5207 INTON;
5208 }
5209 ifslastp = ifsp;
5210 ifslastp->begoff = start;
5211 ifslastp->endoff = end;
5212 ifslastp->nulonly = nulonly;
5213}
5214
5215
5216
5217/*
5218 * Break the argument string into pieces based upon IFS and add the
5219 * strings to the argument list. The regions of the string to be
5220 * searched for IFS characters have been stored by recordregion.
5221 */
5222static void
5223ifsbreakup(string, arglist)
5224 char *string;
5225 struct arglist *arglist;
5226 {
5227 struct ifsregion *ifsp;
5228 struct strlist *sp;
5229 char *start;
5230 char *p;
5231 char *q;
5232 const char *ifs, *realifs;
5233 int ifsspc;
5234 int nulonly;
5235
5236
5237 start = string;
5238 ifsspc = 0;
5239 nulonly = 0;
5240 realifs = ifsset() ? ifsval() : defifs;
5241 if (ifslastp != NULL) {
5242 ifsp = &ifsfirst;
5243 do {
5244 p = string + ifsp->begoff;
5245 nulonly = ifsp->nulonly;
5246 ifs = nulonly ? nullstr : realifs;
5247 ifsspc = 0;
5248 while (p < string + ifsp->endoff) {
5249 q = p;
5250 if (*p == CTLESC)
5251 p++;
5252 if (strchr(ifs, *p)) {
5253 if (!nulonly)
5254 ifsspc = (strchr(defifs, *p) != NULL);
5255 /* Ignore IFS whitespace at start */
5256 if (q == start && ifsspc) {
5257 p++;
5258 start = p;
5259 continue;
5260 }
5261 *q = '\0';
5262 sp = (struct strlist *)stalloc(sizeof *sp);
5263 sp->text = start;
5264 *arglist->lastp = sp;
5265 arglist->lastp = &sp->next;
5266 p++;
5267 if (!nulonly) {
5268 for (;;) {
5269 if (p >= string + ifsp->endoff) {
5270 break;
5271 }
5272 q = p;
5273 if (*p == CTLESC)
5274 p++;
5275 if (strchr(ifs, *p) == NULL ) {
5276 p = q;
5277 break;
5278 } else if (strchr(defifs, *p) == NULL) {
5279 if (ifsspc) {
5280 p++;
5281 ifsspc = 0;
5282 } else {
5283 p = q;
5284 break;
5285 }
5286 } else
5287 p++;
5288 }
5289 }
5290 start = p;
5291 } else
5292 p++;
5293 }
5294 } while ((ifsp = ifsp->next) != NULL);
5295 if (!(*start || (!ifsspc && start > string && nulonly))) {
5296 return;
5297 }
5298 }
5299
5300 sp = (struct strlist *)stalloc(sizeof *sp);
5301 sp->text = start;
5302 *arglist->lastp = sp;
5303 arglist->lastp = &sp->next;
5304}
5305
5306static void
5307ifsfree()
5308{
5309 while (ifsfirst.next != NULL) {
5310 struct ifsregion *ifsp;
5311 INTOFF;
5312 ifsp = ifsfirst.next->next;
5313 ckfree(ifsfirst.next);
5314 ifsfirst.next = ifsp;
5315 INTON;
5316 }
5317 ifslastp = NULL;
5318 ifsfirst.next = NULL;
5319}
5320
5321/*
5322 * Add a file name to the list.
5323 */
5324
5325static void
5326addfname(const char *name)
5327{
5328 char *p;
5329 struct strlist *sp;
5330
5331 p = sstrdup(name);
5332 sp = (struct strlist *)stalloc(sizeof *sp);
5333 sp->text = p;
5334 *exparg.lastp = sp;
5335 exparg.lastp = &sp->next;
5336}
5337
5338/*
5339 * Expand shell metacharacters. At this point, the only control characters
5340 * should be escapes. The results are stored in the list exparg.
5341 */
5342
5343#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
5344static void
5345expandmeta(str, flag)
5346 struct strlist *str;
5347 int flag;
5348{
5349 const char *p;
5350 glob_t pglob;
5351 /* TODO - EXP_REDIR */
5352
5353 while (str) {
5354 if (fflag)
5355 goto nometa;
5356 p = preglob(str->text);
5357 INTOFF;
5358 switch (glob(p, 0, 0, &pglob)) {
5359 case 0:
5360 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
5361 goto nometa2;
5362 addglob(&pglob);
5363 globfree(&pglob);
5364 INTON;
5365 break;
5366 case GLOB_NOMATCH:
5367nometa2:
5368 globfree(&pglob);
5369 INTON;
5370nometa:
5371 *exparg.lastp = str;
5372 rmescapes(str->text);
5373 exparg.lastp = &str->next;
5374 break;
5375 default: /* GLOB_NOSPACE */
5376 error("Out of space");
5377 }
5378 str = str->next;
5379 }
5380}
5381
5382
5383/*
5384 * Add the result of glob(3) to the list.
5385 */
5386
5387static void
5388addglob(pglob)
5389 const glob_t *pglob;
5390{
5391 char **p = pglob->gl_pathv;
5392
5393 do {
5394 addfname(*p);
5395 } while (*++p);
5396}
5397
5398
5399#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
5400static char *expdir;
5401
5402
5403static void
5404expandmeta(str, flag)
5405 struct strlist *str;
5406 int flag;
5407{
5408 char *p;
5409 struct strlist **savelastp;
5410 struct strlist *sp;
5411 char c;
5412 /* TODO - EXP_REDIR */
5413
5414 while (str) {
5415 if (fflag)
5416 goto nometa;
5417 p = str->text;
5418 for (;;) { /* fast check for meta chars */
5419 if ((c = *p++) == '\0')
5420 goto nometa;
5421 if (c == '*' || c == '?' || c == '[' || c == '!')
5422 break;
5423 }
5424 savelastp = exparg.lastp;
5425 INTOFF;
5426 if (expdir == NULL) {
5427 int i = strlen(str->text);
5428 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5429 }
5430
5431 expmeta(expdir, str->text);
5432 ckfree(expdir);
5433 expdir = NULL;
5434 INTON;
5435 if (exparg.lastp == savelastp) {
5436 /*
5437 * no matches
5438 */
5439nometa:
5440 *exparg.lastp = str;
5441 rmescapes(str->text);
5442 exparg.lastp = &str->next;
5443 } else {
5444 *exparg.lastp = NULL;
5445 *savelastp = sp = expsort(*savelastp);
5446 while (sp->next != NULL)
5447 sp = sp->next;
5448 exparg.lastp = &sp->next;
5449 }
5450 str = str->next;
5451 }
5452}
5453
5454
5455/*
5456 * Do metacharacter (i.e. *, ?, [...]) expansion.
5457 */
5458
5459static void
5460expmeta(enddir, name)
5461 char *enddir;
5462 char *name;
5463 {
5464 char *p;
5465 const char *cp;
5466 char *q;
5467 char *start;
5468 char *endname;
5469 int metaflag;
5470 struct stat statb;
5471 DIR *dirp;
5472 struct dirent *dp;
5473 int atend;
5474 int matchdot;
5475
5476 metaflag = 0;
5477 start = name;
5478 for (p = name ; ; p++) {
5479 if (*p == '*' || *p == '?')
5480 metaflag = 1;
5481 else if (*p == '[') {
5482 q = p + 1;
5483 if (*q == '!')
5484 q++;
5485 for (;;) {
5486 while (*q == CTLQUOTEMARK)
5487 q++;
5488 if (*q == CTLESC)
5489 q++;
5490 if (*q == '/' || *q == '\0')
5491 break;
5492 if (*++q == ']') {
5493 metaflag = 1;
5494 break;
5495 }
5496 }
5497 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
5498 metaflag = 1;
5499 } else if (*p == '\0')
5500 break;
5501 else if (*p == CTLQUOTEMARK)
5502 continue;
5503 else if (*p == CTLESC)
5504 p++;
5505 if (*p == '/') {
5506 if (metaflag)
5507 break;
5508 start = p + 1;
5509 }
5510 }
5511 if (metaflag == 0) { /* we've reached the end of the file name */
5512 if (enddir != expdir)
5513 metaflag++;
5514 for (p = name ; ; p++) {
5515 if (*p == CTLQUOTEMARK)
5516 continue;
5517 if (*p == CTLESC)
5518 p++;
5519 *enddir++ = *p;
5520 if (*p == '\0')
5521 break;
5522 }
5523 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5524 addfname(expdir);
5525 return;
5526 }
5527 endname = p;
5528 if (start != name) {
5529 p = name;
5530 while (p < start) {
5531 while (*p == CTLQUOTEMARK)
5532 p++;
5533 if (*p == CTLESC)
5534 p++;
5535 *enddir++ = *p++;
5536 }
5537 }
5538 if (enddir == expdir) {
5539 cp = ".";
5540 } else if (enddir == expdir + 1 && *expdir == '/') {
5541 cp = "/";
5542 } else {
5543 cp = expdir;
5544 enddir[-1] = '\0';
5545 }
5546 if ((dirp = opendir(cp)) == NULL)
5547 return;
5548 if (enddir != expdir)
5549 enddir[-1] = '/';
5550 if (*endname == 0) {
5551 atend = 1;
5552 } else {
5553 atend = 0;
5554 *endname++ = '\0';
5555 }
5556 matchdot = 0;
5557 p = start;
5558 while (*p == CTLQUOTEMARK)
5559 p++;
5560 if (*p == CTLESC)
5561 p++;
5562 if (*p == '.')
5563 matchdot++;
5564 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5565 if (dp->d_name[0] == '.' && ! matchdot)
5566 continue;
5567 if (patmatch(start, dp->d_name, 0)) {
5568 if (atend) {
5569 strcpy(enddir, dp->d_name);
5570 addfname(expdir);
5571 } else {
5572 for (p = enddir, cp = dp->d_name;
5573 (*p++ = *cp++) != '\0';)
5574 continue;
5575 p[-1] = '/';
5576 expmeta(p, endname);
5577 }
5578 }
5579 }
5580 closedir(dirp);
5581 if (! atend)
5582 endname[-1] = '/';
5583}
5584#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
5585
5586
5587
5588#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5589/*
5590 * Sort the results of file name expansion. It calculates the number of
5591 * strings to sort and then calls msort (short for merge sort) to do the
5592 * work.
5593 */
5594
5595static struct strlist *
5596expsort(str)
5597 struct strlist *str;
5598 {
5599 int len;
5600 struct strlist *sp;
5601
5602 len = 0;
5603 for (sp = str ; sp ; sp = sp->next)
5604 len++;
5605 return msort(str, len);
5606}
5607
5608
5609static struct strlist *
5610msort(list, len)
5611 struct strlist *list;
5612 int len;
5613{
5614 struct strlist *p, *q = NULL;
5615 struct strlist **lpp;
5616 int half;
5617 int n;
5618
5619 if (len <= 1)
5620 return list;
5621 half = len >> 1;
5622 p = list;
5623 for (n = half ; --n >= 0 ; ) {
5624 q = p;
5625 p = p->next;
5626 }
5627 q->next = NULL; /* terminate first half of list */
5628 q = msort(list, half); /* sort first half of list */
5629 p = msort(p, len - half); /* sort second half */
5630 lpp = &list;
5631 for (;;) {
5632 if (strcmp(p->text, q->text) < 0) {
5633 *lpp = p;
5634 lpp = &p->next;
5635 if ((p = *lpp) == NULL) {
5636 *lpp = q;
5637 break;
5638 }
5639 } else {
5640 *lpp = q;
5641 lpp = &q->next;
5642 if ((q = *lpp) == NULL) {
5643 *lpp = p;
5644 break;
5645 }
5646 }
5647 }
5648 return list;
5649}
5650#endif
5651
5652
5653
5654/*
5655 * Returns true if the pattern matches the string.
5656 */
5657
5658#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
5659/* squoted: string might have quote chars */
5660static int
5661patmatch(char *pattern, char *string, int squoted)
5662{
5663 const char *p;
5664 char *q;
5665
5666 p = preglob(pattern);
5667 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5668
5669 return !fnmatch(p, q, 0);
5670}
5671
5672
5673static int
5674patmatch2(char *pattern, char *string, int squoted)
5675{
5676 char *p;
5677 int res;
5678
5679 sstrnleft--;
5680 p = grabstackstr(expdest);
5681 res = patmatch(pattern, string, squoted);
5682 ungrabstackstr(p, expdest);
5683 return res;
5684}
5685#else
5686static int
5687patmatch(char *pattern, char *string, int squoted) {
5688 return pmatch(pattern, string, squoted);
5689}
5690
5691
5692static int
5693pmatch(char *pattern, char *string, int squoted)
5694{
5695 char *p, *q;
5696 char c;
5697
5698 p = pattern;
5699 q = string;
5700 for (;;) {
5701 switch (c = *p++) {
5702 case '\0':
5703 goto breakloop;
5704 case CTLESC:
5705 if (squoted && *q == CTLESC)
5706 q++;
5707 if (*q++ != *p++)
5708 return 0;
5709 break;
5710 case CTLQUOTEMARK:
5711 continue;
5712 case '?':
5713 if (squoted && *q == CTLESC)
5714 q++;
5715 if (*q++ == '\0')
5716 return 0;
5717 break;
5718 case '*':
5719 c = *p;
5720 while (c == CTLQUOTEMARK || c == '*')
5721 c = *++p;
5722 if (c != CTLESC && c != CTLQUOTEMARK &&
5723 c != '?' && c != '*' && c != '[') {
5724 while (*q != c) {
5725 if (squoted && *q == CTLESC &&
5726 q[1] == c)
5727 break;
5728 if (*q == '\0')
5729 return 0;
5730 if (squoted && *q == CTLESC)
5731 q++;
5732 q++;
5733 }
5734 }
5735 do {
5736 if (pmatch(p, q, squoted))
5737 return 1;
5738 if (squoted && *q == CTLESC)
5739 q++;
5740 } while (*q++ != '\0');
5741 return 0;
5742 case '[': {
5743 char *endp;
5744 int invert, found;
5745 char chr;
5746
5747 endp = p;
5748 if (*endp == '!')
5749 endp++;
5750 for (;;) {
5751 while (*endp == CTLQUOTEMARK)
5752 endp++;
5753 if (*endp == '\0')
5754 goto dft; /* no matching ] */
5755 if (*endp == CTLESC)
5756 endp++;
5757 if (*++endp == ']')
5758 break;
5759 }
5760 invert = 0;
5761 if (*p == '!') {
5762 invert++;
5763 p++;
5764 }
5765 found = 0;
5766 chr = *q++;
5767 if (squoted && chr == CTLESC)
5768 chr = *q++;
5769 if (chr == '\0')
5770 return 0;
5771 c = *p++;
5772 do {
5773 if (c == CTLQUOTEMARK)
5774 continue;
5775 if (c == CTLESC)
5776 c = *p++;
5777 if (*p == '-' && p[1] != ']') {
5778 p++;
5779 while (*p == CTLQUOTEMARK)
5780 p++;
5781 if (*p == CTLESC)
5782 p++;
5783 if (chr >= c && chr <= *p)
5784 found = 1;
5785 p++;
5786 } else {
5787 if (chr == c)
5788 found = 1;
5789 }
5790 } while ((c = *p++) != ']');
5791 if (found == invert)
5792 return 0;
5793 break;
5794 }
5795dft: default:
5796 if (squoted && *q == CTLESC)
5797 q++;
5798 if (*q++ != c)
5799 return 0;
5800 break;
5801 }
5802 }
5803breakloop:
5804 if (*q != '\0')
5805 return 0;
5806 return 1;
5807}
5808#endif
5809
5810
5811
5812/*
5813 * Remove any CTLESC characters from a string.
5814 */
5815
5816#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
5817static char *
5818_rmescapes(char *str, int flag)
5819{
5820 char *p, *q, *r;
5821 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5822
5823 p = strpbrk(str, qchars);
5824 if (!p) {
5825 return str;
5826 }
5827 q = p;
5828 r = str;
5829 if (flag & RMESCAPE_ALLOC) {
5830 size_t len = p - str;
5831 q = r = stalloc(strlen(p) + len + 1);
5832 if (len > 0) {
5833 memcpy(q, str, len);
5834 q += len;
5835 }
5836 }
5837 while (*p) {
5838 if (*p == CTLQUOTEMARK) {
5839 p++;
5840 continue;
5841 }
5842 if (*p == CTLESC) {
5843 p++;
5844 if (flag & RMESCAPE_GLOB && *p != '/') {
5845 *q++ = '\\';
5846 }
5847 }
5848 *q++ = *p++;
5849 }
5850 *q = '\0';
5851 return r;
5852}
5853#else
5854static void
5855rmescapes(str)
5856 char *str;
5857{
5858 char *p, *q;
5859
5860 p = str;
5861 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5862 if (*p++ == '\0')
5863 return;
5864 }
5865 q = p;
5866 while (*p) {
5867 if (*p == CTLQUOTEMARK) {
5868 p++;
5869 continue;
5870 }
5871 if (*p == CTLESC)
5872 p++;
5873 *q++ = *p++;
5874 }
5875 *q = '\0';
5876}
5877#endif
5878
5879
5880
5881/*
5882 * See if a pattern matches in a case statement.
5883 */
5884
5885static int
5886casematch(union node *pattern, const char *val)
5887{
5888 struct stackmark smark;
5889 int result;
5890 char *p;
5891
5892 setstackmark(&smark);
5893 argbackq = pattern->narg.backquote;
5894 STARTSTACKSTR(expdest);
5895 ifslastp = NULL;
5896 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5897 STPUTC('\0', expdest);
5898 p = grabstackstr(expdest);
5899 result = patmatch(p, (char *)val, 0);
5900 popstackmark(&smark);
5901 return result;
5902}
5903
5904/*
5905 * Our own itoa().
5906 */
5907
5908static char *
5909cvtnum(num, buf)
5910 int num;
5911 char *buf;
5912 {
5913 int len;
5914
5915 CHECKSTRSPACE(32, buf);
5916 len = sprintf(buf, "%d", num);
5917 STADJUST(len, buf);
5918 return buf;
5919}
5920/*
5921 * Editline and history functions (and glue).
5922 */
5923static int histcmd(argc, argv)
5924 int argc;
5925 char **argv;
5926{
5927 error("not compiled with history support");
5928 /* NOTREACHED */
5929}
5930
5931
5932struct redirtab {
5933 struct redirtab *next;
5934 short renamed[10]; /* Current ash support only 0-9 descriptors */
5935 /* char on arm (and others) can't be negative */
5936};
5937
5938static struct redirtab *redirlist;
5939
5940extern char **environ;
5941
5942
5943
5944/*
5945 * Initialization code.
5946 */
5947
5948static void
5949init(void) {
5950
5951 /* from cd.c: */
5952 {
5953 setpwd(0, 0);
5954 }
5955
5956 /* from input.c: */
5957 {
5958 basepf.nextc = basepf.buf = basebuf;
5959 }
5960
5961 /* from var.c: */
5962 {
5963 char **envp;
5964 char ppid[32];
5965
5966 initvar();
5967 for (envp = environ ; *envp ; envp++) {
5968 if (strchr(*envp, '=')) {
5969 setvareq(*envp, VEXPORT|VTEXTFIXED);
5970 }
5971 }
5972
5973 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
5974 setvar("PPID", ppid, 0);
5975 }
5976}
5977
5978
5979
5980/*
5981 * This routine is called when an error or an interrupt occurs in an
5982 * interactive shell and control is returned to the main command loop.
5983 */
5984
5985/* 1 == check for aliases, 2 == also check for assignments */
5986static int checkalias; /* also used in no alias mode for check assignments */
5987
5988static void
5989reset(void) {
5990
5991 /* from eval.c: */
5992 {
5993 evalskip = 0;
5994 loopnest = 0;
5995 funcnest = 0;
5996 }
5997
5998 /* from input.c: */
5999 {
6000 if (exception != EXSHELLPROC)
6001 parselleft = parsenleft = 0; /* clear input buffer */
6002 popallfiles();
6003 }
6004
6005 /* from parser.c: */
6006 {
6007 tokpushback = 0;
6008 checkkwd = 0;
6009 checkalias = 0;
6010 }
6011
6012 /* from redir.c: */
6013 {
6014 while (redirlist)
6015 popredir();
6016 }
6017
6018}
6019
6020
6021
6022/*
6023 * This file implements the input routines used by the parser.
6024 */
6025
6026#ifdef BB_FEATURE_COMMAND_EDITING
6027static const char * cmdedit_prompt;
6028static inline void putprompt(const char *s) {
6029 cmdedit_prompt = s;
6030}
6031#else
6032static inline void putprompt(const char *s) {
6033 out2str(s);
6034}
6035#endif
6036
6037#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
6038
6039
6040
6041/*
6042 * Same as pgetc(), but ignores PEOA.
6043 */
6044
6045#ifdef ASH_ALIAS
6046static int
6047pgetc2(void)
6048{
6049 int c;
6050 do {
6051 c = pgetc_macro();
6052 } while (c == PEOA);
6053 return c;
6054}
6055#else
6056static inline int pgetc2() { return pgetc_macro(); }
6057#endif
6058
6059/*
6060 * Read a line from the script.
6061 */
6062
6063static inline char *
6064pfgets(char *line, int len)
6065{
6066 char *p = line;
6067 int nleft = len;
6068 int c;
6069
6070 while (--nleft > 0) {
6071 c = pgetc2();
6072 if (c == PEOF) {
6073 if (p == line)
6074 return NULL;
6075 break;
6076 }
6077 *p++ = c;
6078 if (c == '\n')
6079 break;
6080 }
6081 *p = '\0';
6082 return line;
6083}
6084
6085static inline int
6086preadfd(void)
6087{
6088 int nr;
6089 char *buf = parsefile->buf;
6090 parsenextc = buf;
6091
6092retry:
6093#ifdef BB_FEATURE_COMMAND_EDITING
6094 {
6095 if (!iflag || parsefile->fd)
6096 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6097 else {
6098 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
6099 }
6100 }
6101#else
6102 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6103#endif
6104
6105 if (nr < 0) {
6106 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6107 int flags = fcntl(0, F_GETFL, 0);
6108 if (flags >= 0 && flags & O_NONBLOCK) {
6109 flags &=~ O_NONBLOCK;
6110 if (fcntl(0, F_SETFL, flags) >= 0) {
6111 out2str("sh: turning off NDELAY mode\n");
6112 goto retry;
6113 }
6114 }
6115 }
6116 }
6117 return nr;
6118}
6119
6120static void
6121popstring(void)
6122{
6123 struct strpush *sp = parsefile->strpush;
6124
6125 INTOFF;
6126#ifdef ASH_ALIAS
6127 if (sp->ap) {
6128 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6129 if (!checkalias) {
6130 checkalias = 1;
6131 }
6132 }
6133 if (sp->string != sp->ap->val) {
6134 ckfree(sp->string);
6135 }
6136
6137 sp->ap->flag &= ~ALIASINUSE;
6138 if (sp->ap->flag & ALIASDEAD) {
6139 unalias(sp->ap->name);
6140 }
6141 }
6142#endif
6143 parsenextc = sp->prevstring;
6144 parsenleft = sp->prevnleft;
6145/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6146 parsefile->strpush = sp->prev;
6147 if (sp != &(parsefile->basestrpush))
6148 ckfree(sp);
6149 INTON;
6150}
6151
6152
6153/*
6154 * Refill the input buffer and return the next input character:
6155 *
6156 * 1) If a string was pushed back on the input, pop it;
6157 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6158 * from a string so we can't refill the buffer, return EOF.
6159 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6160 * 4) Process input up to the next newline, deleting nul characters.
6161 */
6162
6163static int
6164preadbuffer(void)
6165{
6166 char *p, *q;
6167 int more;
6168 char savec;
6169
6170 while (parsefile->strpush) {
6171#ifdef ASH_ALIAS
6172 if (parsenleft == -1 && parsefile->strpush->ap &&
6173 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6174 return PEOA;
6175 }
6176#endif
6177 popstring();
6178 if (--parsenleft >= 0)
6179 return (*parsenextc++);
6180 }
6181 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6182 return PEOF;
6183 flushall();
6184
6185again:
6186 if (parselleft <= 0) {
6187 if ((parselleft = preadfd()) <= 0) {
6188 parselleft = parsenleft = EOF_NLEFT;
6189 return PEOF;
6190 }
6191 }
6192
6193 q = p = parsenextc;
6194
6195 /* delete nul characters */
6196 for (more = 1; more;) {
6197 switch (*p) {
6198 case '\0':
6199 p++; /* Skip nul */
6200 goto check;
6201
6202
6203 case '\n':
6204 parsenleft = q - parsenextc;
6205 more = 0; /* Stop processing here */
6206 break;
6207 }
6208
6209 *q++ = *p++;
6210check:
6211 if (--parselleft <= 0 && more) {
6212 parsenleft = q - parsenextc - 1;
6213 if (parsenleft < 0)
6214 goto again;
6215 more = 0;
6216 }
6217 }
6218
6219 savec = *q;
6220 *q = '\0';
6221
6222 if (vflag) {
6223 out2str(parsenextc);
6224 }
6225
6226 *q = savec;
6227
6228 return *parsenextc++;
6229}
6230
6231
6232/*
6233 * Push a string back onto the input at this current parsefile level.
6234 * We handle aliases this way.
6235 */
6236static void
6237pushstring(char *s, int len, void *ap)
6238{
6239 struct strpush *sp;
6240
6241 INTOFF;
6242/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6243 if (parsefile->strpush) {
6244 sp = ckmalloc(sizeof (struct strpush));
6245 sp->prev = parsefile->strpush;
6246 parsefile->strpush = sp;
6247 } else
6248 sp = parsefile->strpush = &(parsefile->basestrpush);
6249 sp->prevstring = parsenextc;
6250 sp->prevnleft = parsenleft;
6251#ifdef ASH_ALIAS
6252 sp->ap = (struct alias *)ap;
6253 if (ap) {
6254 ((struct alias *)ap)->flag |= ALIASINUSE;
6255 sp->string = s;
6256 }
6257#endif
6258 parsenextc = s;
6259 parsenleft = len;
6260 INTON;
6261}
6262
6263
6264/*
6265 * Like setinputfile, but takes input from a string.
6266 */
6267
6268static void
6269setinputstring(char *string)
6270{
6271 INTOFF;
6272 pushfile();
6273 parsenextc = string;
6274 parsenleft = strlen(string);
6275 parsefile->buf = NULL;
6276 plinno = 1;
6277 INTON;
6278}
6279
6280
6281
6282/*
6283 * To handle the "." command, a stack of input files is used. Pushfile
6284 * adds a new entry to the stack and popfile restores the previous level.
6285 */
6286
6287static void
6288pushfile(void) {
6289 struct parsefile *pf;
6290
6291 parsefile->nleft = parsenleft;
6292 parsefile->lleft = parselleft;
6293 parsefile->nextc = parsenextc;
6294 parsefile->linno = plinno;
6295 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6296 pf->prev = parsefile;
6297 pf->fd = -1;
6298 pf->strpush = NULL;
6299 pf->basestrpush.prev = NULL;
6300 parsefile = pf;
6301}
6302
6303#ifdef JOBS
6304static void restartjob (struct job *);
6305#endif
6306static void freejob (struct job *);
6307static struct job *getjob (const char *);
6308static int dowait (int, struct job *);
6309static void waitonint(int);
6310
6311
6312/*
6313 * We keep track of whether or not fd0 has been redirected. This is for
6314 * background commands, where we want to redirect fd0 to /dev/null only
6315 * if it hasn't already been redirected.
6316*/
6317static int fd0_redirected = 0;
6318
6319/* Return true if fd 0 has already been redirected at least once. */
6320static inline int
6321fd0_redirected_p (void)
6322{
6323 return fd0_redirected != 0;
6324}
6325
6326static void dupredirect (const union node *, int, int fd1dup);
6327
6328#ifdef JOBS
6329/*
6330 * Turn job control on and off.
6331 *
6332 * Note: This code assumes that the third arg to ioctl is a character
6333 * pointer, which is true on Berkeley systems but not System V. Since
6334 * System V doesn't have job control yet, this isn't a problem now.
6335 */
6336
6337
6338
6339static void setjobctl(int enable)
6340{
6341#ifdef OLD_TTY_DRIVER
6342 int ldisc;
6343#endif
6344
6345 if (enable == jobctl || rootshell == 0)
6346 return;
6347 if (enable) {
6348 do { /* while we are in the background */
6349#ifdef OLD_TTY_DRIVER
6350 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
6351#else
6352 initialpgrp = tcgetpgrp(2);
6353 if (initialpgrp < 0) {
6354#endif
6355 out2str("sh: can't access tty; job control turned off\n");
6356 mflag = 0;
6357 return;
6358 }
6359 if (initialpgrp == -1)
6360 initialpgrp = getpgrp();
6361 else if (initialpgrp != getpgrp()) {
6362 killpg(initialpgrp, SIGTTIN);
6363 continue;
6364 }
6365 } while (0);
6366#ifdef OLD_TTY_DRIVER
6367 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
6368 out2str("sh: need new tty driver to run job control; job control turned off\n");
6369 mflag = 0;
6370 return;
6371 }
6372#endif
6373 setsignal(SIGTSTP);
6374 setsignal(SIGTTOU);
6375 setsignal(SIGTTIN);
6376 setpgid(0, rootpid);
6377#ifdef OLD_TTY_DRIVER
6378 ioctl(2, TIOCSPGRP, (char *)&rootpid);
6379#else
6380 tcsetpgrp(2, rootpid);
6381#endif
6382 } else { /* turning job control off */
6383 setpgid(0, initialpgrp);
6384#ifdef OLD_TTY_DRIVER
6385 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
6386#else
6387 tcsetpgrp(2, initialpgrp);
6388#endif
6389 setsignal(SIGTSTP);
6390 setsignal(SIGTTOU);
6391 setsignal(SIGTTIN);
6392 }
6393 jobctl = enable;
6394}
6395#endif
6396
6397
6398#ifdef JOBS
6399static int
6400killcmd(argc, argv)
6401 int argc;
6402 char **argv;
6403{
6404 int signo = -1;
6405 int list = 0;
6406 int i;
6407 pid_t pid;
6408 struct job *jp;
6409
6410 if (argc <= 1) {
6411usage:
6412 error(
6413"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6414"kill -l [exitstatus]"
6415 );
6416 }
6417
6418 if (*argv[1] == '-') {
6419 signo = decode_signal(argv[1] + 1, 1);
6420 if (signo < 0) {
6421 int c;
6422
6423 while ((c = nextopt("ls:")) != '\0')
6424 switch (c) {
6425 case 'l':
6426 list = 1;
6427 break;
6428 case 's':
6429 signo = decode_signal(optionarg, 1);
6430 if (signo < 0) {
6431 error(
6432 "invalid signal number or name: %s",
6433 optionarg
6434 );
6435 }
6436 break;
6437#ifdef DEBUG
6438 default:
6439 error(
6440 "nextopt returned character code 0%o", c);
6441#endif
6442 }
6443 } else
6444 argptr++;
6445 }
6446
6447 if (!list && signo < 0)
6448 signo = SIGTERM;
6449
6450 if ((signo < 0 || !*argptr) ^ list) {
6451 goto usage;
6452 }
6453
6454 if (list) {
6455 const char *name;
6456
6457 if (!*argptr) {
6458 out1str("0\n");
6459 for (i = 1; i < NSIG; i++) {
6460 name = u_signal_names(0, &i, 1);
6461 if(name)
6462 printf(snlfmt, name);
6463 }
6464 return 0;
6465 }
6466 name = u_signal_names(*argptr, &signo, -1);
6467 if (name)
6468 printf(snlfmt, name);
6469 else
6470 error("invalid signal number or exit status: %s",
6471 *argptr);
6472 return 0;
6473 }
6474
6475 do {
6476 if (**argptr == '%') {
6477 jp = getjob(*argptr);
6478 if (jp->jobctl == 0)
6479 error("job %s not created under job control",
6480 *argptr);
6481 pid = -jp->ps[0].pid;
6482 } else
6483 pid = atoi(*argptr);
6484 if (kill(pid, signo) != 0)
6485 error("%s: %m", *argptr);
6486 } while (*++argptr);
6487
6488 return 0;
6489}
6490
6491static int
6492fgcmd(argc, argv)
6493 int argc;
6494 char **argv;
6495{
6496 struct job *jp;
6497 int pgrp;
6498 int status;
6499
6500 jp = getjob(argv[1]);
6501 if (jp->jobctl == 0)
6502 error("job not created under job control");
6503 pgrp = jp->ps[0].pid;
6504#ifdef OLD_TTY_DRIVER
6505 ioctl(2, TIOCSPGRP, (char *)&pgrp);
6506#else
6507 tcsetpgrp(2, pgrp);
6508#endif
6509 restartjob(jp);
6510 INTOFF;
6511 status = waitforjob(jp);
6512 INTON;
6513 return status;
6514}
6515
6516
6517static int
6518bgcmd(argc, argv)
6519 int argc;
6520 char **argv;
6521{
6522 struct job *jp;
6523
6524 do {
6525 jp = getjob(*++argv);
6526 if (jp->jobctl == 0)
6527 error("job not created under job control");
6528 restartjob(jp);
6529 } while (--argc > 1);
6530 return 0;
6531}
6532
6533
6534static void
6535restartjob(jp)
6536 struct job *jp;
6537{
6538 struct procstat *ps;
6539 int i;
6540
6541 if (jp->state == JOBDONE)
6542 return;
6543 INTOFF;
6544 killpg(jp->ps[0].pid, SIGCONT);
6545 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6546 if (WIFSTOPPED(ps->status)) {
6547 ps->status = -1;
6548 jp->state = 0;
6549 }
6550 }
6551 INTON;
6552}
6553#endif
6554
6555static void showjobs(int change);
6556
6557
6558static int
6559jobscmd(argc, argv)
6560 int argc;
6561 char **argv;
6562{
6563 showjobs(0);
6564 return 0;
6565}
6566
6567
6568/*
6569 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6570 * statuses have changed since the last call to showjobs.
6571 *
6572 * If the shell is interrupted in the process of creating a job, the
6573 * result may be a job structure containing zero processes. Such structures
6574 * will be freed here.
6575 */
6576
6577static void
6578showjobs(change)
6579 int change;
6580{
6581 int jobno;
6582 int procno;
6583 int i;
6584 struct job *jp;
6585 struct procstat *ps;
6586 int col;
6587 char s[64];
6588
6589 TRACE(("showjobs(%d) called\n", change));
6590 while (dowait(0, (struct job *)NULL) > 0);
6591 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6592 if (! jp->used)
6593 continue;
6594 if (jp->nprocs == 0) {
6595 freejob(jp);
6596 continue;
6597 }
6598 if (change && ! jp->changed)
6599 continue;
6600 procno = jp->nprocs;
6601 for (ps = jp->ps ; ; ps++) { /* for each process */
6602 if (ps == jp->ps)
6603 snprintf(s, 64, "[%d] %ld ", jobno,
6604 (long)ps->pid);
6605 else
6606 snprintf(s, 64, " %ld ",
6607 (long)ps->pid);
6608 out1str(s);
6609 col = strlen(s);
6610 s[0] = '\0';
6611 if (ps->status == -1) {
6612 /* don't print anything */
6613 } else if (WIFEXITED(ps->status)) {
6614 snprintf(s, 64, "Exit %d",
6615 WEXITSTATUS(ps->status));
6616 } else {
6617#ifdef JOBS
6618 if (WIFSTOPPED(ps->status))
6619 i = WSTOPSIG(ps->status);
6620 else /* WIFSIGNALED(ps->status) */
6621#endif
6622 i = WTERMSIG(ps->status);
6623 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
6624 strcpy(s, sys_siglist[i & 0x7F]);
6625 else
6626 snprintf(s, 64, "Signal %d", i & 0x7F);
6627 if (WCOREDUMP(ps->status))
6628 strcat(s, " (core dumped)");
6629 }
6630 out1str(s);
6631 col += strlen(s);
6632 printf(
6633 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6634 ps->cmd
6635 );
6636 if (--procno <= 0)
6637 break;
6638 }
6639 jp->changed = 0;
6640 if (jp->state == JOBDONE) {
6641 freejob(jp);
6642 }
6643 }
6644}
6645
6646
6647/*
6648 * Mark a job structure as unused.
6649 */
6650
6651static void
6652freejob(struct job *jp)
6653{
6654 const struct procstat *ps;
6655 int i;
6656
6657 INTOFF;
6658 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6659 if (ps->cmd != nullstr)
6660 ckfree(ps->cmd);
6661 }
6662 if (jp->ps != &jp->ps0)
6663 ckfree(jp->ps);
6664 jp->used = 0;
6665#ifdef JOBS
6666 if (curjob == jp - jobtab + 1)
6667 curjob = 0;
6668#endif
6669 INTON;
6670}
6671
6672
6673
6674static int
6675waitcmd(argc, argv)
6676 int argc;
6677 char **argv;
6678{
6679 struct job *job;
6680 int status, retval;
6681 struct job *jp;
6682
6683 if (--argc > 0) {
6684start:
6685 job = getjob(*++argv);
6686 } else {
6687 job = NULL;
6688 }
6689 for (;;) { /* loop until process terminated or stopped */
6690 if (job != NULL) {
6691 if (job->state) {
6692 status = job->ps[job->nprocs - 1].status;
6693 if (! iflag)
6694 freejob(job);
6695 if (--argc) {
6696 goto start;
6697 }
6698 if (WIFEXITED(status))
6699 retval = WEXITSTATUS(status);
6700#ifdef JOBS
6701 else if (WIFSTOPPED(status))
6702 retval = WSTOPSIG(status) + 128;
6703#endif
6704 else {
6705 /* XXX: limits number of signals */
6706 retval = WTERMSIG(status) + 128;
6707 }
6708 return retval;
6709 }
6710 } else {
6711 for (jp = jobtab ; ; jp++) {
6712 if (jp >= jobtab + njobs) { /* no running procs */
6713 return 0;
6714 }
6715 if (jp->used && jp->state == 0)
6716 break;
6717 }
6718 }
6719 if (dowait(2, 0) < 0 && errno == EINTR) {
6720 return 129;
6721 }
6722 }
6723}
6724
6725
6726
6727/*
6728 * Convert a job name to a job structure.
6729 */
6730
6731static struct job *
6732getjob(const char *name)
6733{
6734 int jobno;
6735 struct job *jp;
6736 int pid;
6737 int i;
6738
6739 if (name == NULL) {
6740#ifdef JOBS
6741currentjob:
6742 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6743 error("No current job");
6744 return &jobtab[jobno - 1];
6745#else
6746 error("No current job");
6747#endif
6748 } else if (name[0] == '%') {
6749 if (is_digit(name[1])) {
6750 jobno = number(name + 1);
6751 if (jobno > 0 && jobno <= njobs
6752 && jobtab[jobno - 1].used != 0)
6753 return &jobtab[jobno - 1];
6754#ifdef JOBS
6755 } else if (name[1] == '%' && name[2] == '\0') {
6756 goto currentjob;
6757#endif
6758 } else {
6759 struct job *found = NULL;
6760 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6761 if (jp->used && jp->nprocs > 0
6762 && prefix(name + 1, jp->ps[0].cmd)) {
6763 if (found)
6764 error("%s: ambiguous", name);
6765 found = jp;
6766 }
6767 }
6768 if (found)
6769 return found;
6770 }
6771 } else if (is_number(name, &pid)) {
6772 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6773 if (jp->used && jp->nprocs > 0
6774 && jp->ps[jp->nprocs - 1].pid == pid)
6775 return jp;
6776 }
6777 }
6778 error("No such job: %s", name);
6779 /* NOTREACHED */
6780}
6781
6782
6783
6784/*
6785 * Return a new job structure,
6786 */
6787
6788static struct job *
6789makejob(const union node *node, int nprocs)
6790{
6791 int i;
6792 struct job *jp;
6793
6794 for (i = njobs, jp = jobtab ; ; jp++) {
6795 if (--i < 0) {
6796 INTOFF;
6797 if (njobs == 0) {
6798 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6799 } else {
6800 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6801 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6802 /* Relocate `ps' pointers */
6803 for (i = 0; i < njobs; i++)
6804 if (jp[i].ps == &jobtab[i].ps0)
6805 jp[i].ps = &jp[i].ps0;
6806 ckfree(jobtab);
6807 jobtab = jp;
6808 }
6809 jp = jobtab + njobs;
6810 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6811 INTON;
6812 break;
6813 }
6814 if (jp->used == 0)
6815 break;
6816 }
6817 INTOFF;
6818 jp->state = 0;
6819 jp->used = 1;
6820 jp->changed = 0;
6821 jp->nprocs = 0;
6822#ifdef JOBS
6823 jp->jobctl = jobctl;
6824#endif
6825 if (nprocs > 1) {
6826 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6827 } else {
6828 jp->ps = &jp->ps0;
6829 }
6830 INTON;
6831 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6832 jp - jobtab + 1));
6833 return jp;
6834}
6835
6836
6837/*
6838 * Fork of a subshell. If we are doing job control, give the subshell its
6839 * own process group. Jp is a job structure that the job is to be added to.
6840 * N is the command that will be evaluated by the child. Both jp and n may
6841 * be NULL. The mode parameter can be one of the following:
6842 * FORK_FG - Fork off a foreground process.
6843 * FORK_BG - Fork off a background process.
6844 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6845 * process group even if job control is on.
6846 *
6847 * When job control is turned off, background processes have their standard
6848 * input redirected to /dev/null (except for the second and later processes
6849 * in a pipeline).
6850 */
6851
6852
6853
6854static int
6855forkshell(struct job *jp, const union node *n, int mode)
6856{
6857 int pid;
6858#ifdef JOBS
6859 int pgrp;
6860#endif
6861 const char *devnull = _PATH_DEVNULL;
6862 const char *nullerr = "Can't open %s";
6863
6864 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6865 mode));
6866 INTOFF;
6867 pid = fork();
6868 if (pid == -1) {
6869 TRACE(("Fork failed, errno=%d\n", errno));
6870 INTON;
6871 error("Cannot fork");
6872 }
6873 if (pid == 0) {
6874 struct job *p;
6875 int wasroot;
6876 int i;
6877
6878 TRACE(("Child shell %d\n", getpid()));
6879 wasroot = rootshell;
6880 rootshell = 0;
6881 closescript();
6882 INTON;
6883 clear_traps();
6884#ifdef JOBS
6885 jobctl = 0; /* do job control only in root shell */
6886 if (wasroot && mode != FORK_NOJOB && mflag) {
6887 if (jp == NULL || jp->nprocs == 0)
6888 pgrp = getpid();
6889 else
6890 pgrp = jp->ps[0].pid;
6891 setpgid(0, pgrp);
6892 if (mode == FORK_FG) {
6893 /*** this causes superfluous TIOCSPGRPS ***/
6894#ifdef OLD_TTY_DRIVER
6895 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
6896 error("TIOCSPGRP failed, errno=%d", errno);
6897#else
6898 if (tcsetpgrp(2, pgrp) < 0)
6899 error("tcsetpgrp failed, errno=%d", errno);
6900#endif
6901 }
6902 setsignal(SIGTSTP);
6903 setsignal(SIGTTOU);
6904 } else if (mode == FORK_BG) {
6905 ignoresig(SIGINT);
6906 ignoresig(SIGQUIT);
6907 if ((jp == NULL || jp->nprocs == 0) &&
6908 ! fd0_redirected_p ()) {
6909 close(0);
6910 if (open(devnull, O_RDONLY) != 0)
6911 error(nullerr, devnull);
6912 }
6913 }
6914#else
6915 if (mode == FORK_BG) {
6916 ignoresig(SIGINT);
6917 ignoresig(SIGQUIT);
6918 if ((jp == NULL || jp->nprocs == 0) &&
6919 ! fd0_redirected_p ()) {
6920 close(0);
6921 if (open(devnull, O_RDONLY) != 0)
6922 error(nullerr, devnull);
6923 }
6924 }
6925#endif
6926 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6927 if (p->used)
6928 freejob(p);
6929 if (wasroot && iflag) {
6930 setsignal(SIGINT);
6931 setsignal(SIGQUIT);
6932 setsignal(SIGTERM);
6933 }
6934 return pid;
6935 }
6936#ifdef JOBS
6937 if (rootshell && mode != FORK_NOJOB && mflag) {
6938 if (jp == NULL || jp->nprocs == 0)
6939 pgrp = pid;
6940 else
6941 pgrp = jp->ps[0].pid;
6942 setpgid(pid, pgrp);
6943 }
6944#endif
6945 if (mode == FORK_BG)
6946 backgndpid = pid; /* set $! */
6947 if (jp) {
6948 struct procstat *ps = &jp->ps[jp->nprocs++];
6949 ps->pid = pid;
6950 ps->status = -1;
6951 ps->cmd = nullstr;
6952 if (iflag && rootshell && n)
6953 ps->cmd = commandtext(n);
6954 }
6955 INTON;
6956 TRACE(("In parent shell: child = %d\n", pid));
6957 return pid;
6958}
6959
6960
6961
6962/*
6963 * Wait for job to finish.
6964 *
6965 * Under job control we have the problem that while a child process is
6966 * running interrupts generated by the user are sent to the child but not
6967 * to the shell. This means that an infinite loop started by an inter-
6968 * active user may be hard to kill. With job control turned off, an
6969 * interactive user may place an interactive program inside a loop. If
6970 * the interactive program catches interrupts, the user doesn't want
6971 * these interrupts to also abort the loop. The approach we take here
6972 * is to have the shell ignore interrupt signals while waiting for a
6973 * forground process to terminate, and then send itself an interrupt
6974 * signal if the child process was terminated by an interrupt signal.
6975 * Unfortunately, some programs want to do a bit of cleanup and then
6976 * exit on interrupt; unless these processes terminate themselves by
6977 * sending a signal to themselves (instead of calling exit) they will
6978 * confuse this approach.
6979 */
6980
6981static int
6982waitforjob(struct job *jp)
6983{
6984#ifdef JOBS
6985 int mypgrp = getpgrp();
6986#endif
6987 int status;
6988 int st;
6989 struct sigaction act, oact;
6990
6991 INTOFF;
6992 intreceived = 0;
6993#ifdef JOBS
6994 if (!jobctl) {
6995#else
6996 if (!iflag) {
6997#endif
6998 sigaction(SIGINT, 0, &act);
6999 act.sa_handler = waitonint;
7000 sigaction(SIGINT, &act, &oact);
7001 }
7002 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7003 while (jp->state == 0) {
7004 dowait(1, jp);
7005 }
7006#ifdef JOBS
7007 if (!jobctl) {
7008#else
7009 if (!iflag) {
7010#endif
7011 sigaction(SIGINT, &oact, 0);
7012 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7013 }
7014#ifdef JOBS
7015 if (jp->jobctl) {
7016#ifdef OLD_TTY_DRIVER
7017 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
7018 error("TIOCSPGRP failed, errno=%d\n", errno);
7019#else
7020 if (tcsetpgrp(2, mypgrp) < 0)
7021 error("tcsetpgrp failed, errno=%d\n", errno);
7022#endif
7023 }
7024 if (jp->state == JOBSTOPPED)
7025 curjob = jp - jobtab + 1;
7026#endif
7027 status = jp->ps[jp->nprocs - 1].status;
7028 /* convert to 8 bits */
7029 if (WIFEXITED(status))
7030 st = WEXITSTATUS(status);
7031#ifdef JOBS
7032 else if (WIFSTOPPED(status))
7033 st = WSTOPSIG(status) + 128;
7034#endif
7035 else
7036 st = WTERMSIG(status) + 128;
7037#ifdef JOBS
7038 if (jp->jobctl) {
7039 /*
7040 * This is truly gross.
7041 * If we're doing job control, then we did a TIOCSPGRP which
7042 * caused us (the shell) to no longer be in the controlling
7043 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7044 * intuit from the subprocess exit status whether a SIGINT
7045 * occured, and if so interrupt ourselves. Yuck. - mycroft
7046 */
7047 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7048 raise(SIGINT);
7049 }
7050 if (jp->state == JOBDONE)
7051
7052#endif
7053 freejob(jp);
7054 INTON;
7055 return st;
7056}
7057
7058
7059
7060/*
7061 * Wait for a process to terminate.
7062 */
7063
7064/*
7065 * Do a wait system call. If job control is compiled in, we accept
7066 * stopped processes. If block is zero, we return a value of zero
7067 * rather than blocking.
7068 *
7069 * System V doesn't have a non-blocking wait system call. It does
7070 * have a SIGCLD signal that is sent to a process when one of it's
7071 * children dies. The obvious way to use SIGCLD would be to install
7072 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7073 * was received, and have waitproc bump another counter when it got
7074 * the status of a process. Waitproc would then know that a wait
7075 * system call would not block if the two counters were different.
7076 * This approach doesn't work because if a process has children that
7077 * have not been waited for, System V will send it a SIGCLD when it
7078 * installs a signal handler for SIGCLD. What this means is that when
7079 * a child exits, the shell will be sent SIGCLD signals continuously
7080 * until is runs out of stack space, unless it does a wait call before
7081 * restoring the signal handler. The code below takes advantage of
7082 * this (mis)feature by installing a signal handler for SIGCLD and
7083 * then checking to see whether it was called. If there are any
7084 * children to be waited for, it will be.
7085 *
7086 */
7087
7088static inline int
7089waitproc(int block, int *status)
7090{
7091 int flags;
7092
7093 flags = 0;
7094#ifdef JOBS
7095 if (jobctl)
7096 flags |= WUNTRACED;
7097#endif
7098 if (block == 0)
7099 flags |= WNOHANG;
7100 return wait3(status, flags, (struct rusage *)NULL);
7101}
7102
7103static int
7104dowait(int block, struct job *job)
7105{
7106 int pid;
7107 int status;
7108 struct procstat *sp;
7109 struct job *jp;
7110 struct job *thisjob;
7111 int done;
7112 int stopped;
7113 int core;
7114 int sig;
7115
7116 TRACE(("dowait(%d) called\n", block));
7117 do {
7118 pid = waitproc(block, &status);
7119 TRACE(("wait returns %d, status=%d\n", pid, status));
7120 } while (!(block & 2) && pid == -1 && errno == EINTR);
7121 if (pid <= 0)
7122 return pid;
7123 INTOFF;
7124 thisjob = NULL;
7125 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7126 if (jp->used) {
7127 done = 1;
7128 stopped = 1;
7129 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7130 if (sp->pid == -1)
7131 continue;
7132 if (sp->pid == pid) {
7133 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7134 sp->status = status;
7135 thisjob = jp;
7136 }
7137 if (sp->status == -1)
7138 stopped = 0;
7139 else if (WIFSTOPPED(sp->status))
7140 done = 0;
7141 }
7142 if (stopped) { /* stopped or done */
7143 int state = done? JOBDONE : JOBSTOPPED;
7144 if (jp->state != state) {
7145 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7146 jp->state = state;
7147#ifdef JOBS
7148 if (done && curjob == jp - jobtab + 1)
7149 curjob = 0; /* no current job */
7150#endif
7151 }
7152 }
7153 }
7154 }
7155 INTON;
7156 if (! rootshell || ! iflag || (job && thisjob == job)) {
7157 core = WCOREDUMP(status);
7158#ifdef JOBS
7159 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7160 else
7161#endif
7162 if (WIFEXITED(status)) sig = 0;
7163 else sig = WTERMSIG(status);
7164
7165 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7166 if (thisjob != job)
7167 out2fmt("%d: ", pid);
7168#ifdef JOBS
7169 if (sig == SIGTSTP && rootshell && iflag)
7170 out2fmt("%%%ld ",
7171 (long)(job - jobtab + 1));
7172#endif
7173 if (sig < NSIG && sys_siglist[sig])
7174 out2str(sys_siglist[sig]);
7175 else
7176 out2fmt("Signal %d", sig);
7177 if (core)
7178 out2str(" - core dumped");
7179 out2c('\n');
7180 } else {
7181 TRACE(("Not printing status: status=%d, sig=%d\n",
7182 status, sig));
7183 }
7184 } else {
7185 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7186 if (thisjob)
7187 thisjob->changed = 1;
7188 }
7189 return pid;
7190}
7191
7192
7193
7194
7195/*
7196 * return 1 if there are stopped jobs, otherwise 0
7197 */
7198static int
7199stoppedjobs(void)
7200{
7201 int jobno;
7202 struct job *jp;
7203
7204 if (job_warning)
7205 return (0);
7206 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7207 if (jp->used == 0)
7208 continue;
7209 if (jp->state == JOBSTOPPED) {
7210 out2str("You have stopped jobs.\n");
7211 job_warning = 2;
7212 return (1);
7213 }
7214 }
7215
7216 return (0);
7217}
7218
7219/*
7220 * Return a string identifying a command (to be printed by the
7221 * jobs command.
7222 */
7223
7224static char *cmdnextc;
7225static int cmdnleft;
7226#define MAXCMDTEXT 200
7227
7228static void
7229cmdputs(const char *s)
7230{
7231 const char *p;
7232 char *q;
7233 char c;
7234 int subtype = 0;
7235
7236 if (cmdnleft <= 0)
7237 return;
7238 p = s;
7239 q = cmdnextc;
7240 while ((c = *p++) != '\0') {
7241 if (c == CTLESC)
7242 *q++ = *p++;
7243 else if (c == CTLVAR) {
7244 *q++ = '$';
7245 if (--cmdnleft > 0)
7246 *q++ = '{';
7247 subtype = *p++;
7248 } else if (c == '=' && subtype != 0) {
7249 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7250 subtype = 0;
7251 } else if (c == CTLENDVAR) {
7252 *q++ = '}';
7253 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7254 cmdnleft++; /* ignore it */
7255 else
7256 *q++ = c;
7257 if (--cmdnleft <= 0) {
7258 *q++ = '.';
7259 *q++ = '.';
7260 *q++ = '.';
7261 break;
7262 }
7263 }
7264 cmdnextc = q;
7265}
7266
7267#define CMDTXT_TABLE
7268#ifdef CMDTXT_TABLE
7269/*
7270 * To collect a lot of redundant code in cmdtxt() case statements, we
7271 * implement a mini language here. Each type of node struct has an
7272 * associated instruction sequence that operates on its members via
7273 * their offsets. The instruction are pack in unsigned chars with
7274 * format IIDDDDDE where the bits are
7275 * I : part of the instruction opcode, which are
7276 * 00 : member is a pointer to another node -- process it recursively
7277 * 40 : member is a pointer to a char string -- output it
7278 * 80 : output the string whose index is stored in the data field
7279 * CC : flag signaling that this case needs external processing
7280 * D : data - either the (shifted) index of a fixed string to output or
7281 * the actual offset of the member to operate on in the struct
7282 * (since we assume bit 0 is set, the offset is not shifted)
7283 * E : flag signaling end of instruction sequence
7284 *
7285 * WARNING: In order to handle larger offsets for 64bit archs, this code
7286 * assumes that no offset can be an odd number and stores the
7287 * end-of-instructions flag in bit 0.
7288 */
7289
7290#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7291#define CMDTXT_CHARPTR 0x40
7292#define CMDTXT_STRING 0x80
7293#define CMDTXT_SPECIAL 0xC0
7294#define CMDTXT_OFFSETMASK 0x3E
7295
7296static const char * const cmdtxt_strings[] = {
7297 /* 0 1 2 3 4 5 6 7 */
7298 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7299 /* 8 9 10 11 12 13 */
7300 "while ", "; do ", "; done", "until ", "for ", " in ...",
7301 /* 14 15 16 17 */
7302 "case ", "???", "() ...", "<<..."
7303};
7304
7305static const char * const redir_strings[] = {
7306 ">", "<", "<>", ">>", ">|", ">&", "<&"
7307};
7308
7309static const unsigned char cmdtxt_ops[] = {
7310#define CMDTXT_NSEMI 0
7311 offsetof(union node, nbinary.ch1),
7312 0|CMDTXT_STRING,
7313 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7314#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7315#define CMDTXT_NPIPE (CMDTXT_NCMD)
7316#define CMDTXT_NCASE (CMDTXT_NCMD)
7317#define CMDTXT_NTO (CMDTXT_NCMD)
7318#define CMDTXT_NFROM (CMDTXT_NCMD)
7319#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7320#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7321#define CMDTXT_NTOOV (CMDTXT_NCMD)
7322#define CMDTXT_NTOFD (CMDTXT_NCMD)
7323#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7324 CMDTXT_SPECIAL,
7325#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7326#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7327 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7328#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7329 (1*2)|CMDTXT_STRING,
7330 offsetof(union node, nredir.n),
7331 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7332#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7333 offsetof(union node, nbinary.ch1),
7334 (3*2)|CMDTXT_STRING,
7335 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7336#define CMDTXT_NOR (CMDTXT_NAND + 3)
7337 offsetof(union node, nbinary.ch1),
7338 (4*2)|CMDTXT_STRING,
7339 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7340#define CMDTXT_NIF (CMDTXT_NOR + 3)
7341 (5*2)|CMDTXT_STRING,
7342 offsetof(union node, nif.test),
7343 (6*2)|CMDTXT_STRING,
7344 offsetof(union node, nif.ifpart),
7345 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7346#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7347 (8*2)|CMDTXT_STRING,
7348 offsetof(union node, nbinary.ch1),
7349 (9*2)|CMDTXT_STRING,
7350 offsetof(union node, nbinary.ch2),
7351 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7352#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7353 (11*2)|CMDTXT_STRING,
7354 offsetof(union node, nbinary.ch1),
7355 (9*2)|CMDTXT_STRING,
7356 offsetof(union node, nbinary.ch2),
7357 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7358#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7359 (12*2)|CMDTXT_STRING,
7360 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7361 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7362#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7363#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7364 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7365#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7366 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7367 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7368#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7369 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7370#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7371#define CMDTXT_NXHERE (CMDTXT_NHERE)
7372 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7373};
7374
7375#if CMDTXT_NXHERE != 36
7376#error CMDTXT_NXHERE
7377#endif
7378
7379static const unsigned char cmdtxt_ops_index[26] = {
7380 CMDTXT_NSEMI,
7381 CMDTXT_NCMD,
7382 CMDTXT_NPIPE,
7383 CMDTXT_NREDIR,
7384 CMDTXT_NBACKGND,
7385 CMDTXT_NSUBSHELL,
7386 CMDTXT_NAND,
7387 CMDTXT_NOR,
7388 CMDTXT_NIF,
7389 CMDTXT_NWHILE,
7390 CMDTXT_NUNTIL,
7391 CMDTXT_NFOR,
7392 CMDTXT_NCASE,
7393 CMDTXT_NCLIST,
7394 CMDTXT_NDEFUN,
7395 CMDTXT_NARG,
7396 CMDTXT_NTO,
7397 CMDTXT_NFROM,
7398 CMDTXT_NFROMTO,
7399 CMDTXT_NAPPEND,
7400 CMDTXT_NTOOV,
7401 CMDTXT_NTOFD,
7402 CMDTXT_NFROMFD,
7403 CMDTXT_NHERE,
7404 CMDTXT_NXHERE,
7405 CMDTXT_NNOT,
7406};
7407
7408static void
7409cmdtxt(const union node *n)
7410{
7411 const char *p;
7412
7413 if (n == NULL)
7414 return;
7415
7416 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7417 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7418 do {
7419 if (*p & CMDTXT_STRING) { /* output fixed string */
7420 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
7421 } else {
7422 const char *pf = ((const char *) n)
7423 + ((int)(*p & CMDTXT_OFFSETMASK));
7424 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7425 cmdputs(*((const char **) pf));
7426 } else { /* output field */
7427 cmdtxt(*((const union node **) pf));
7428 }
7429 }
7430 } while (!(*p++ & CMDTXT_NOMORE));
7431 } else if (n->type == NCMD) {
7432 union node *np;
7433 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7434 cmdtxt(np);
7435 if (np->narg.next)
7436 cmdputs(spcstr);
7437 }
7438 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7439 cmdputs(spcstr);
7440 cmdtxt(np);
7441 }
7442 } else if (n->type == NPIPE) {
7443 struct nodelist *lp;
7444 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7445 cmdtxt(lp->n);
7446 if (lp->next)
7447 cmdputs(" | ");
7448 }
7449 } else if (n->type == NCASE) {
7450 cmdputs(cmdtxt_strings[14]);
7451 cmdputs(n->ncase.expr->narg.text);
7452 cmdputs(cmdtxt_strings[13]);
7453 } else {
7454#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7455#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7456#endif
7457 char s[2];
7458
7459#ifdef DEBUG
7460 assert((n->type >= NTO) && (n->type <= NFROMFD));
7461#endif
7462
7463 p = redir_strings[n->type - NTO];
7464 if (n->nfile.fd != ('>' == *p)) {
7465 s[0] = n->nfile.fd + '0';
7466 s[1] = '\0';
7467 cmdputs(s);
7468 }
7469 cmdputs(p);
7470 if (n->type >= NTOFD) {
7471 s[0] = n->ndup.dupfd + '0';
7472 s[1] = '\0';
7473 cmdputs(s);
7474 } else {
7475 cmdtxt(n->nfile.fname);
7476 }
7477 }
7478}
7479#else /* CMDTXT_TABLE */
7480static void
7481cmdtxt(const union node *n)
7482{
7483 union node *np;
7484 struct nodelist *lp;
7485 const char *p;
7486 int i;
7487 char s[2];
7488
7489 if (n == NULL)
7490 return;
7491 switch (n->type) {
7492 case NSEMI:
7493 cmdtxt(n->nbinary.ch1);
7494 cmdputs("; ");
7495 cmdtxt(n->nbinary.ch2);
7496 break;
7497 case NAND:
7498 cmdtxt(n->nbinary.ch1);
7499 cmdputs(" && ");
7500 cmdtxt(n->nbinary.ch2);
7501 break;
7502 case NOR:
7503 cmdtxt(n->nbinary.ch1);
7504 cmdputs(" || ");
7505 cmdtxt(n->nbinary.ch2);
7506 break;
7507 case NPIPE:
7508 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7509 cmdtxt(lp->n);
7510 if (lp->next)
7511 cmdputs(" | ");
7512 }
7513 break;
7514 case NSUBSHELL:
7515 cmdputs("(");
7516 cmdtxt(n->nredir.n);
7517 cmdputs(")");
7518 break;
7519 case NREDIR:
7520 case NBACKGND:
7521 cmdtxt(n->nredir.n);
7522 break;
7523 case NIF:
7524 cmdputs("if ");
7525 cmdtxt(n->nif.test);
7526 cmdputs("; then ");
7527 cmdtxt(n->nif.ifpart);
7528 cmdputs("...");
7529 break;
7530 case NWHILE:
7531 cmdputs("while ");
7532 goto until;
7533 case NUNTIL:
7534 cmdputs("until ");
7535until:
7536 cmdtxt(n->nbinary.ch1);
7537 cmdputs("; do ");
7538 cmdtxt(n->nbinary.ch2);
7539 cmdputs("; done");
7540 break;
7541 case NFOR:
7542 cmdputs("for ");
7543 cmdputs(n->nfor.var);
7544 cmdputs(" in ...");
7545 break;
7546 case NCASE:
7547 cmdputs("case ");
7548 cmdputs(n->ncase.expr->narg.text);
7549 cmdputs(" in ...");
7550 break;
7551 case NDEFUN:
7552 cmdputs(n->narg.text);
7553 cmdputs("() ...");
7554 break;
7555 case NCMD:
7556 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7557 cmdtxt(np);
7558 if (np->narg.next)
7559 cmdputs(spcstr);
7560 }
7561 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7562 cmdputs(spcstr);
7563 cmdtxt(np);
7564 }
7565 break;
7566 case NARG:
7567 cmdputs(n->narg.text);
7568 break;
7569 case NTO:
7570 p = ">"; i = 1; goto redir;
7571 case NAPPEND:
7572 p = ">>"; i = 1; goto redir;
7573 case NTOFD:
7574 p = ">&"; i = 1; goto redir;
7575 case NTOOV:
7576 p = ">|"; i = 1; goto redir;
7577 case NFROM:
7578 p = "<"; i = 0; goto redir;
7579 case NFROMFD:
7580 p = "<&"; i = 0; goto redir;
7581 case NFROMTO:
7582 p = "<>"; i = 0; goto redir;
7583redir:
7584 if (n->nfile.fd != i) {
7585 s[0] = n->nfile.fd + '0';
7586 s[1] = '\0';
7587 cmdputs(s);
7588 }
7589 cmdputs(p);
7590 if (n->type == NTOFD || n->type == NFROMFD) {
7591 s[0] = n->ndup.dupfd + '0';
7592 s[1] = '\0';
7593 cmdputs(s);
7594 } else {
7595 cmdtxt(n->nfile.fname);
7596 }
7597 break;
7598 case NHERE:
7599 case NXHERE:
7600 cmdputs("<<...");
7601 break;
7602 default:
7603 cmdputs("???");
7604 break;
7605 }
7606}
7607#endif /* CMDTXT_TABLE */
7608
7609static char *
7610commandtext(const union node *n)
7611{
7612 char *name;
7613
7614 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7615 cmdnleft = MAXCMDTEXT - 4;
7616 cmdtxt(n);
7617 *cmdnextc = '\0';
7618 return name;
7619}
7620
7621
7622static void waitonint(int sig) {
7623 intreceived = 1;
7624 return;
7625}
7626/*
7627 * Routines to check for mail. (Perhaps make part of main.c?)
7628 */
7629
7630
7631#define MAXMBOXES 10
7632
7633
7634static int nmboxes; /* number of mailboxes */
7635static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
7636
7637
7638
7639/*
7640 * Print appropriate message(s) if mail has arrived. If the argument is
7641 * nozero, then the value of MAIL has changed, so we just update the
7642 * values.
7643 */
7644
7645static void
7646chkmail(int silent)
7647{
7648 int i;
7649 const char *mpath;
7650 char *p;
7651 char *q;
7652 struct stackmark smark;
7653 struct stat statb;
7654
7655 if (silent)
7656 nmboxes = 10;
7657 if (nmboxes == 0)
7658 return;
7659 setstackmark(&smark);
7660 mpath = mpathset()? mpathval() : mailval();
7661 for (i = 0 ; i < nmboxes ; i++) {
7662 p = padvance(&mpath, nullstr);
7663 if (p == NULL)
7664 break;
7665 if (*p == '\0')
7666 continue;
7667 for (q = p ; *q ; q++);
7668#ifdef DEBUG
7669 if (q[-1] != '/')
7670 abort();
7671#endif
7672 q[-1] = '\0'; /* delete trailing '/' */
7673 if (stat(p, &statb) < 0)
7674 statb.st_size = 0;
7675 if (statb.st_size > mailtime[i] && ! silent) {
7676 out2fmt(snlfmt,
7677 pathopt? pathopt : "you have mail");
7678 }
7679 mailtime[i] = statb.st_size;
7680 }
7681 nmboxes = i;
7682 popstackmark(&smark);
7683}
7684
7685#define PROFILE 0
7686
7687#if PROFILE
7688static short profile_buf[16384];
7689extern int etext();
7690#endif
7691
7692static void read_profile (const char *);
7693static void cmdloop (int);
7694static void options (int);
7695static void setoption (int, int);
7696static void procargs (int, char **);
7697
7698
7699/*
7700 * Main routine. We initialize things, parse the arguments, execute
7701 * profiles if we're a login shell, and then call cmdloop to execute
7702 * commands. The setjmp call sets up the location to jump to when an
7703 * exception occurs. When an exception occurs the variable "state"
7704 * is used to figure out how far we had gotten.
7705 */
7706
7707int
7708ash_main(argc, argv)
7709 int argc;
7710 char **argv;
7711{
7712 struct jmploc jmploc;
7713 struct stackmark smark;
7714 volatile int state;
7715 const char *shinit;
7716
7717 BLTINCMD = find_builtin("builtin");
7718 EXECCMD = find_builtin("exec");
7719 EVALCMD = find_builtin("eval");
7720
7721#ifndef BB_FEATURE_SH_FANCY_PROMPT
7722 unsetenv("PS1");
7723 unsetenv("PS2");
7724#endif
7725
7726#if PROFILE
7727 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7728#endif
7729#if defined(linux) || defined(__GNU__)
7730 signal(SIGCHLD, SIG_DFL);
7731#endif
7732 state = 0;
7733 if (setjmp(jmploc.loc)) {
7734 INTOFF;
7735 /*
7736 * When a shell procedure is executed, we raise the
7737 * exception EXSHELLPROC to clean up before executing
7738 * the shell procedure.
7739 */
7740 if (exception == EXSHELLPROC) {
7741 rootpid = getpid();
7742 rootshell = 1;
7743 minusc = NULL;
7744 state = 3;
7745 } else {
7746 if (exception == EXEXEC) {
7747 exitstatus = exerrno;
7748 } else if (exception == EXERROR) {
7749 exitstatus = 2;
7750 }
7751 if (state == 0 || iflag == 0 || ! rootshell)
7752 exitshell(exitstatus);
7753 }
7754 reset();
7755 if (exception == EXINT) {
7756 out2c('\n');
7757 }
7758 popstackmark(&smark);
7759 FORCEINTON; /* enable interrupts */
7760 if (state == 1)
7761 goto state1;
7762 else if (state == 2)
7763 goto state2;
7764 else if (state == 3)
7765 goto state3;
7766 else
7767 goto state4;
7768 }
7769 handler = &jmploc;
7770#ifdef DEBUG
7771 opentrace();
7772 trputs("Shell args: "); trargs(argv);
7773#endif
7774 rootpid = getpid();
7775 rootshell = 1;
7776 init();
7777 setstackmark(&smark);
7778 procargs(argc, argv);
7779 if (argv[0] && argv[0][0] == '-') {
7780 state = 1;
7781 read_profile("/etc/profile");
7782state1:
7783 state = 2;
7784 read_profile(".profile");
7785 }
7786state2:
7787 state = 3;
7788#ifndef linux
7789 if (getuid() == geteuid() && getgid() == getegid()) {
7790#endif
7791 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7792 state = 3;
7793 read_profile(shinit);
7794 }
7795#ifndef linux
7796 }
7797#endif
7798state3:
7799 state = 4;
7800 if (sflag == 0 || minusc) {
7801 static const char sigs[] = {
7802 SIGINT, SIGQUIT, SIGHUP,
7803#ifdef SIGTSTP
7804 SIGTSTP,
7805#endif
7806 SIGPIPE
7807 };
7808#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
7809 int i;
7810
7811 for (i = 0; i < SIGSSIZE; i++)
7812 setsignal(sigs[i]);
7813 }
7814
7815 if (minusc)
7816 evalstring(minusc, 0);
7817
7818 if (sflag || minusc == NULL) {
7819state4: /* XXX ??? - why isn't this before the "if" statement */
7820 cmdloop(1);
7821 }
7822#if PROFILE
7823 monitor(0);
7824#endif
7825 exitshell(exitstatus);
7826 /* NOTREACHED */
7827}
7828
7829
7830/*
7831 * Read and execute commands. "Top" is nonzero for the top level command
7832 * loop; it turns on prompting if the shell is interactive.
7833 */
7834
7835static void
7836cmdloop(int top)
7837{
7838 union node *n;
7839 struct stackmark smark;
7840 int inter;
7841 int numeof = 0;
7842
7843 TRACE(("cmdloop(%d) called\n", top));
7844 setstackmark(&smark);
7845 for (;;) {
7846 if (pendingsigs)
7847 dotrap();
7848 inter = 0;
7849 if (iflag && top) {
7850 inter++;
7851 showjobs(1);
7852 chkmail(0);
7853 flushall();
7854 }
7855 n = parsecmd(inter);
7856 /* showtree(n); DEBUG */
7857 if (n == NEOF) {
7858 if (!top || numeof >= 50)
7859 break;
7860 if (!stoppedjobs()) {
7861 if (!Iflag)
7862 break;
7863 out2str("\nUse \"exit\" to leave shell.\n");
7864 }
7865 numeof++;
7866 } else if (n != NULL && nflag == 0) {
7867 job_warning = (job_warning == 2) ? 1 : 0;
7868 numeof = 0;
7869 evaltree(n, 0);
7870 }
7871 popstackmark(&smark);
7872 setstackmark(&smark);
7873 if (evalskip == SKIPFILE) {
7874 evalskip = 0;
7875 break;
7876 }
7877 }
7878 popstackmark(&smark);
7879}
7880
7881
7882
7883/*
7884 * Read /etc/profile or .profile. Return on error.
7885 */
7886
7887static void
7888read_profile(name)
7889 const char *name;
7890{
7891 int fd;
7892 int xflag_save;
7893 int vflag_save;
7894
7895 INTOFF;
7896 if ((fd = open(name, O_RDONLY)) >= 0)
7897 setinputfd(fd, 1);
7898 INTON;
7899 if (fd < 0)
7900 return;
7901 /* -q turns off -x and -v just when executing init files */
7902 /* Note: Might do a little redundant work, but reduces code size. */
7903 xflag_save = xflag;
7904 vflag_save = vflag;
7905 if (qflag) {
7906 vflag = xflag = 0;
7907 }
7908 cmdloop(0);
7909 xflag = xflag_save;
7910 vflag = vflag_save;
7911 popfile();
7912}
7913
7914
7915
7916/*
7917 * Read a file containing shell functions.
7918 */
7919
7920static void
7921readcmdfile(const char *name)
7922{
7923 int fd;
7924
7925 INTOFF;
7926 if ((fd = open(name, O_RDONLY)) >= 0)
7927 setinputfd(fd, 1);
7928 else
7929 error("Can't open %s", name);
7930 INTON;
7931 cmdloop(0);
7932 popfile();
7933}
7934
7935
7936
7937/*
7938 * Take commands from a file. To be compatable we should do a path
7939 * search for the file, which is necessary to find sub-commands.
7940 */
7941
7942
7943static inline char *
7944find_dot_file(char *mybasename)
7945{
7946 char *fullname;
7947 const char *path = pathval();
7948 struct stat statb;
7949
7950 /* don't try this for absolute or relative paths */
7951 if (strchr(mybasename, '/'))
7952 return mybasename;
7953
7954 while ((fullname = padvance(&path, mybasename)) != NULL) {
7955 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7956 /*
7957 * Don't bother freeing here, since it will
7958 * be freed by the caller.
7959 */
7960 return fullname;
7961 }
7962 stunalloc(fullname);
7963 }
7964
7965 /* not found in the PATH */
7966 error("%s: not found", mybasename);
7967 /* NOTREACHED */
7968}
7969
7970static int
7971dotcmd(argc, argv)
7972 int argc;
7973 char **argv;
7974{
7975 struct strlist *sp;
7976 exitstatus = 0;
7977
7978 for (sp = cmdenviron; sp ; sp = sp->next)
7979 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7980
7981 if (argc >= 2) { /* That's what SVR2 does */
7982 char *fullname;
7983 struct stackmark smark;
7984
7985 setstackmark(&smark);
7986 fullname = find_dot_file(argv[1]);
7987 setinputfile(fullname, 1);
7988 commandname = fullname;
7989 cmdloop(0);
7990 popfile();
7991 popstackmark(&smark);
7992 }
7993 return exitstatus;
7994}
7995
7996
7997static int
7998exitcmd(argc, argv)
7999 int argc;
8000 char **argv;
8001{
8002 if (stoppedjobs())
8003 return 0;
8004 if (argc > 1)
8005 exitstatus = number(argv[1]);
8006 else
8007 exitstatus = oexitstatus;
8008 exitshell(exitstatus);
8009 /* NOTREACHED */
8010}
8011
8012static pointer
8013stalloc(int nbytes)
8014{
8015 char *p;
8016
8017 nbytes = ALIGN(nbytes);
8018 if (nbytes > stacknleft) {
8019 int blocksize;
8020 struct stack_block *sp;
8021
8022 blocksize = nbytes;
8023 if (blocksize < MINSIZE)
8024 blocksize = MINSIZE;
8025 INTOFF;
8026 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8027 sp->prev = stackp;
8028 stacknxt = sp->space;
8029 stacknleft = blocksize;
8030 stackp = sp;
8031 INTON;
8032 }
8033 p = stacknxt;
8034 stacknxt += nbytes;
8035 stacknleft -= nbytes;
8036 return p;
8037}
8038
8039
8040static void
8041stunalloc(pointer p)
8042{
8043#ifdef DEBUG
8044 if (p == NULL) { /*DEBUG */
8045 write(2, "stunalloc\n", 10);
8046 abort();
8047 }
8048#endif
8049 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8050 p = stackp->space;
8051 }
8052 stacknleft += stacknxt - (char *)p;
8053 stacknxt = p;
8054}
8055
8056
8057static void
8058setstackmark(struct stackmark *mark)
8059{
8060 mark->stackp = stackp;
8061 mark->stacknxt = stacknxt;
8062 mark->stacknleft = stacknleft;
8063 mark->marknext = markp;
8064 markp = mark;
8065}
8066
8067
8068static void
8069popstackmark(struct stackmark *mark)
8070{
8071 struct stack_block *sp;
8072
8073 INTOFF;
8074 markp = mark->marknext;
8075 while (stackp != mark->stackp) {
8076 sp = stackp;
8077 stackp = sp->prev;
8078 ckfree(sp);
8079 }
8080 stacknxt = mark->stacknxt;
8081 stacknleft = mark->stacknleft;
8082 INTON;
8083}
8084
8085
8086/*
8087 * When the parser reads in a string, it wants to stick the string on the
8088 * stack and only adjust the stack pointer when it knows how big the
8089 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8090 * of space on top of the stack and stackblocklen returns the length of
8091 * this block. Growstackblock will grow this space by at least one byte,
8092 * possibly moving it (like realloc). Grabstackblock actually allocates the
8093 * part of the block that has been used.
8094 */
8095
8096static void
8097growstackblock(void) {
8098 char *p;
8099 int newlen = ALIGN(stacknleft * 2 + 100);
8100 char *oldspace = stacknxt;
8101 int oldlen = stacknleft;
8102 struct stack_block *sp;
8103 struct stack_block *oldstackp;
8104
8105 if (stacknxt == stackp->space && stackp != &stackbase) {
8106 INTOFF;
8107 oldstackp = stackp;
8108 sp = stackp;
8109 stackp = sp->prev;
8110 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8111 sp->prev = stackp;
8112 stackp = sp;
8113 stacknxt = sp->space;
8114 stacknleft = newlen;
8115 {
8116 /* Stack marks pointing to the start of the old block
8117 * must be relocated to point to the new block
8118 */
8119 struct stackmark *xmark;
8120 xmark = markp;
8121 while (xmark != NULL && xmark->stackp == oldstackp) {
8122 xmark->stackp = stackp;
8123 xmark->stacknxt = stacknxt;
8124 xmark->stacknleft = stacknleft;
8125 xmark = xmark->marknext;
8126 }
8127 }
8128 INTON;
8129 } else {
8130 p = stalloc(newlen);
8131 memcpy(p, oldspace, oldlen);
8132 stacknxt = p; /* free the space */
8133 stacknleft += newlen; /* we just allocated */
8134 }
8135}
8136
8137
8138
8139static inline void
8140grabstackblock(int len)
8141{
8142 len = ALIGN(len);
8143 stacknxt += len;
8144 stacknleft -= len;
8145}
8146
8147
8148
8149/*
8150 * The following routines are somewhat easier to use that the above.
8151 * The user declares a variable of type STACKSTR, which may be declared
8152 * to be a register. The macro STARTSTACKSTR initializes things. Then
8153 * the user uses the macro STPUTC to add characters to the string. In
8154 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8155 * grown as necessary. When the user is done, she can just leave the
8156 * string there and refer to it using stackblock(). Or she can allocate
8157 * the space for it using grabstackstr(). If it is necessary to allow
8158 * someone else to use the stack temporarily and then continue to grow
8159 * the string, the user should use grabstack to allocate the space, and
8160 * then call ungrabstr(p) to return to the previous mode of operation.
8161 *
8162 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8163 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8164 * is space for at least one character.
8165 */
8166
8167
8168static char *
8169growstackstr(void) {
8170 int len = stackblocksize();
8171 if (herefd >= 0 && len >= 1024) {
8172 xwrite(herefd, stackblock(), len);
8173 sstrnleft = len - 1;
8174 return stackblock();
8175 }
8176 growstackblock();
8177 sstrnleft = stackblocksize() - len - 1;
8178 return stackblock() + len;
8179}
8180
8181
8182/*
8183 * Called from CHECKSTRSPACE.
8184 */
8185
8186static char *
8187makestrspace(size_t newlen) {
8188 int len = stackblocksize() - sstrnleft;
8189 do {
8190 growstackblock();
8191 sstrnleft = stackblocksize() - len;
8192 } while (sstrnleft < newlen);
8193 return stackblock() + len;
8194}
8195
8196
8197
8198static void
8199ungrabstackstr(char *s, char *p)
8200{
8201 stacknleft += stacknxt - s;
8202 stacknxt = s;
8203 sstrnleft = stacknleft - (p - s);
8204}
8205/*
8206 * Miscelaneous builtins.
8207 */
8208
8209
8210#undef rflag
8211
8212#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
8213typedef long rlim_t;
8214#endif
8215
8216
8217
8218/*
8219 * The read builtin. The -e option causes backslashes to escape the
8220 * following character.
8221 *
8222 * This uses unbuffered input, which may be avoidable in some cases.
8223 */
8224
8225static int
8226readcmd(int argc, char **argv)
8227{
8228 char **ap;
8229 int backslash;
8230 char c;
8231 int rflag;
8232 char *prompt;
8233 const char *ifs;
8234 char *p;
8235 int startword;
8236 int status;
8237 int i;
8238
8239 rflag = 0;
8240 prompt = NULL;
8241 while ((i = nextopt("p:r")) != '\0') {
8242 if (i == 'p')
8243 prompt = optionarg;
8244 else
8245 rflag = 1;
8246 }
8247 if (prompt && isatty(0)) {
8248 out2str(prompt); /* read without cmdedit */
8249 flushall();
8250 }
8251 if (*(ap = argptr) == NULL)
8252 error("arg count");
8253 if ((ifs = bltinlookup("IFS")) == NULL)
8254 ifs = defifs;
8255 status = 0;
8256 startword = 1;
8257 backslash = 0;
8258 STARTSTACKSTR(p);
8259 for (;;) {
8260 if (read(0, &c, 1) != 1) {
8261 status = 1;
8262 break;
8263 }
8264 if (c == '\0')
8265 continue;
8266 if (backslash) {
8267 backslash = 0;
8268 if (c != '\n')
8269 STPUTC(c, p);
8270 continue;
8271 }
8272 if (!rflag && c == '\\') {
8273 backslash++;
8274 continue;
8275 }
8276 if (c == '\n')
8277 break;
8278 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8279 continue;
8280 }
8281 startword = 0;
8282 if (backslash && c == '\\') {
8283 if (read(0, &c, 1) != 1) {
8284 status = 1;
8285 break;
8286 }
8287 STPUTC(c, p);
8288 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8289 STACKSTRNUL(p);
8290 setvar(*ap, stackblock(), 0);
8291 ap++;
8292 startword = 1;
8293 STARTSTACKSTR(p);
8294 } else {
8295 STPUTC(c, p);
8296 }
8297 }
8298 STACKSTRNUL(p);
8299 /* Remove trailing blanks */
8300 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8301 *p = '\0';
8302 setvar(*ap, stackblock(), 0);
8303 while (*++ap != NULL)
8304 setvar(*ap, nullstr, 0);
8305 return status;
8306}
8307
8308
8309
8310static int
8311umaskcmd(argc, argv)
8312 int argc;
8313 char **argv;
8314{
8315 static const char permuser[3] = "ugo";
8316 static const char permmode[3] = "rwx";
8317 static const short int permmask[] = {
8318 S_IRUSR, S_IWUSR, S_IXUSR,
8319 S_IRGRP, S_IWGRP, S_IXGRP,
8320 S_IROTH, S_IWOTH, S_IXOTH
8321 };
8322
8323 char *ap;
8324 mode_t mask;
8325 int i;
8326 int symbolic_mode = 0;
8327
8328 while (nextopt("S") != '\0') {
8329 symbolic_mode = 1;
8330 }
8331
8332 INTOFF;
8333 mask = umask(0);
8334 umask(mask);
8335 INTON;
8336
8337 if ((ap = *argptr) == NULL) {
8338 if (symbolic_mode) {
8339 char buf[18];
8340 char *p = buf;
8341 for (i=0 ; i<3 ; i++) {
8342 int j;
8343 *p++ = permuser[i];
8344 *p++ = '=';
8345 for (j=0 ; j<3 ; j++) {
8346 if ((mask & permmask[3*i+j]) == 0) {
8347 *p++ = permmode[j];
8348 }
8349 }
8350 *p++ = ',';
8351 }
8352 *--p = 0;
8353 puts(buf);
8354 } else {
8355 printf("%.4o\n", mask);
8356 }
8357 } else {
8358 if (is_digit((unsigned char)*ap)) {
8359 mask = 0;
8360 do {
8361 if (*ap >= '8' || *ap < '0')
8362 error("Illegal number: %s", argv[1]);
8363 mask = (mask << 3) + (*ap - '0');
8364 } while (*++ap != '\0');
8365 umask(mask);
8366 } else {
8367 mask = ~mask & 0777;
8368 if (parse_mode(ap, &mask) == FALSE) {
8369 error("Illegal mode: %s", ap);
8370 }
8371 umask(~mask & 0777);
8372 }
8373 }
8374 return 0;
8375}
8376
8377/*
8378 * ulimit builtin
8379 *
8380 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8381 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8382 * ash by J.T. Conklin.
8383 *
8384 * Public domain.
8385 */
8386
8387struct limits {
8388 const char *name;
8389 short cmd;
8390 short factor; /* multiply by to get rlim_{cur,max} values */
8391};
8392
8393static const struct limits limits[] = {
8394#ifdef RLIMIT_CPU
8395 { "time(seconds)", RLIMIT_CPU, 1 },
8396#endif
8397#ifdef RLIMIT_FSIZE
8398 { "file(blocks)", RLIMIT_FSIZE, 512 },
8399#endif
8400#ifdef RLIMIT_DATA
8401 { "data(kbytes)", RLIMIT_DATA, 1024 },
8402#endif
8403#ifdef RLIMIT_STACK
8404 { "stack(kbytes)", RLIMIT_STACK, 1024 },
8405#endif
8406#ifdef RLIMIT_CORE
8407 { "coredump(blocks)", RLIMIT_CORE, 512 },
8408#endif
8409#ifdef RLIMIT_RSS
8410 { "memory(kbytes)", RLIMIT_RSS, 1024 },
8411#endif
8412#ifdef RLIMIT_MEMLOCK
8413 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
8414#endif
8415#ifdef RLIMIT_NPROC
8416 { "process(processes)", RLIMIT_NPROC, 1 },
8417#endif
8418#ifdef RLIMIT_NOFILE
8419 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
8420#endif
8421#ifdef RLIMIT_VMEM
8422 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
8423#endif
8424#ifdef RLIMIT_SWAP
8425 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
8426#endif
8427 { NULL, 0, 0 }
8428};
8429
8430static int
8431ulimitcmd(argc, argv)
8432 int argc;
8433 char **argv;
8434{
8435 static const char unlimited_string[] = "unlimited";
8436 int c;
8437 rlim_t val = 0;
8438 enum { SOFT = 0x1, HARD = 0x2 }
8439 how = SOFT | HARD;
8440 const struct limits *l;
8441 int set, all = 0;
8442 int optc, what;
8443 struct rlimit limit;
8444
8445 what = 'f';
8446
8447 while ((optc = nextopt("HSa"
8448#ifdef RLIMIT_CPU
8449 "t"
8450#endif
8451#ifdef RLIMIT_FSIZE
8452 "f"
8453#endif
8454#ifdef RLIMIT_DATA
8455 "d"
8456#endif
8457#ifdef RLIMIT_STACK
8458 "s"
8459#endif
8460#ifdef RLIMIT_CORE
8461 "c"
8462#endif
8463#ifdef RLIMIT_RSS
8464 "m"
8465#endif
8466#ifdef RLIMIT_MEMLOCK
8467 "l"
8468#endif
8469#ifdef RLIMIT_NPROC
8470 "p"
8471#endif
8472#ifdef RLIMIT_NOFILE
8473 "n"
8474#endif
8475#ifdef RLIMIT_VMEM
8476 "v"
8477#endif
8478#ifdef RLIMIT_SWAP
8479 "w"
8480#endif
8481 )) != '\0') {
8482 if (optc == 'H') {
8483 how = HARD;
8484 } else if (optc == 'S') {
8485 how = SOFT;
8486 } else if (optc == 'a') {
8487 all = 1;
8488 } else {
8489 what = optc;
8490 }
8491 }
8492
8493 for (l = limits; l->name; l++) {
8494 if(l->name[0] == what)
8495 break;
8496 if(l->name[1]=='w' && what=='w')
8497 break;
8498 }
8499
8500 set = *argptr ? 1 : 0;
8501 if (set) {
8502 char *p = *argptr;
8503
8504 if (all || argptr[1])
8505 error("too many arguments");
8506 if (strcmp(p, unlimited_string) == 0)
8507 val = RLIM_INFINITY;
8508 else {
8509 val = (rlim_t) 0;
8510
8511 while ((c = *p++) >= '0' && c <= '9')
8512 {
8513 val = (val * 10) + (long)(c - '0');
8514 if (val < (rlim_t) 0)
8515 break;
8516 }
8517 if (c)
8518 error("bad number");
8519 val *= l->factor;
8520 }
8521 }
8522
8523 if (all) {
8524 for (l = limits; l->name; l++) {
8525 printf("%-20s ", l->name);
8526 getrlimit(l->cmd, &limit);
8527 OUTPUT_LIMIT:
8528 if (how & SOFT)
8529 val = limit.rlim_cur;
8530 else if (how & HARD)
8531 val = limit.rlim_max;
8532
8533 if (val == RLIM_INFINITY)
8534 puts(unlimited_string);
8535 else
8536 {
8537 val /= l->factor;
8538 printf("%lld\n", (long long) val);
8539 }
8540 if (!all) {
8541 break;
8542 }
8543 }
8544 return 0;
8545 }
8546
8547 if (!set) {
8548 goto OUTPUT_LIMIT;
8549 }
8550
8551 getrlimit(l->cmd, &limit);
8552 if (how & HARD)
8553 limit.rlim_max = val;
8554 if (how & SOFT)
8555 limit.rlim_cur = val;
8556 if (setrlimit(l->cmd, &limit) < 0)
8557 error("error setting limit (%m)");
8558 return 0;
8559}
8560/*
8561 * prefix -- see if pfx is a prefix of string.
8562 */
8563
8564static int
8565prefix(char const *pfx, char const *string)
8566{
8567 while (*pfx) {
8568 if (*pfx++ != *string++)
8569 return 0;
8570 }
8571 return 1;
8572}
8573
8574/*
8575 * Return true if s is a string of digits, and save munber in intptr
8576 * nagative is bad
8577 */
8578
8579static int
8580is_number(const char *p, int *intptr)
8581{
8582 int ret = 0;
8583
8584 do {
8585 if (! is_digit(*p))
8586 return 0;
8587 ret *= 10;
8588 ret += digit_val(*p);
8589 p++;
8590 } while (*p != '\0');
8591
8592 *intptr = ret;
8593 return 1;
8594}
8595
8596/*
8597 * Convert a string of digits to an integer, printing an error message on
8598 * failure.
8599 */
8600
8601static int
8602number(const char *s)
8603{
8604 int i;
8605 if (! is_number(s, &i))
8606 error("Illegal number: %s", s);
8607 return i;
8608}
8609
8610/*
8611 * Produce a possibly single quoted string suitable as input to the shell.
8612 * The return string is allocated on the stack.
8613 */
8614
8615static char *
8616single_quote(const char *s) {
8617 char *p;
8618
8619 STARTSTACKSTR(p);
8620
8621 do {
8622 char *q = p;
8623 size_t len1, len1p, len2, len2p;
8624
8625 len1 = strcspn(s, "'");
8626 len2 = strspn(s + len1, "'");
8627
8628 len1p = len1 ? len1 + 2 : len1;
8629 len2p = len2 + ((len2 < 2) ? len2 : 2);
8630
8631 CHECKSTRSPACE(len1p + len2p + 1, p);
8632
8633 if (len1) {
8634 *p = '\'';
8635 q = p + 1 + len1;
8636 memcpy(p + 1, s, len1);
8637 *q++ = '\'';
8638 s += len1;
8639 }
8640
8641 if (len2 > 1) {
8642 *q = '"';
8643 q += 1 + len2;
8644 memcpy(q + 1, s, len2);
8645 *q = '"';
8646 s += len2;
8647 } else if (len2 == 1) {
8648 *q++ = '\\';
8649 *q = '\'';
8650 s++;
8651 }
8652
8653 STADJUST(len1p + len2p, p);
8654 } while (*s);
8655
8656 USTPUTC(0, p);
8657
8658 return grabstackstr(p);
8659}
8660
8661/*
8662 * Like strdup but works with the ash stack.
8663 */
8664
8665static char *
8666sstrdup(const char *p)
8667{
8668 size_t len = strlen(p) + 1;
8669 return memcpy(stalloc(len), p, len);
8670}
8671
8672
8673/*
8674 * Routine for dealing with parsed shell commands.
8675 */
8676
8677
8678static void sizenodelist (const struct nodelist *);
8679static struct nodelist *copynodelist (const struct nodelist *);
8680static char *nodesavestr (const char *);
8681
8682#define CALCSIZE_TABLE
8683#define COPYNODE_TABLE
8684#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8685/*
8686 * To collect a lot of redundant code in case statements for copynode()
8687 * and calcsize(), we implement a mini language here. Each type of node
8688 * struct has an associated instruction sequence that operates on its
8689 * members via their offsets. The instruction are pack in unsigned chars
8690 * with format IIDDDDDE where the bits are
8691 * I : part of the instruction opcode, which are
8692 * 00 : member is a pointer to another node
8693 * 40 : member is an integer
8694 * 80 : member is a pointer to a nodelist
8695 * CC : member is a pointer to a char string
8696 * D : data - the actual offset of the member to operate on in the struct
8697 * (since we assume bit 0 is set, it is not shifted)
8698 * E : flag signaling end of instruction sequence
8699 *
8700 * WARNING: In order to handle larger offsets for 64bit archs, this code
8701 * assumes that no offset can be an odd number and stores the
8702 * end-of-instructions flag in bit 0.
8703 */
8704
8705#define NODE_INTEGER 0x40
8706#define NODE_NODELIST 0x80
8707#define NODE_CHARPTR 0xC0
8708#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8709#define NODE_MBRMASK 0xC0
8710#define NODE_OFFSETMASK 0x3E
8711
8712static const unsigned char copynode_ops[35] = {
8713#define COPYNODE_OPS0 0
8714 offsetof(union node, nbinary.ch2),
8715 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8716#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8717 offsetof(union node, ncmd.redirect),
8718 offsetof(union node, ncmd.args),
8719 offsetof(union node, ncmd.assign),
8720 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8721#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8722 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8723 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8724#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8725 offsetof(union node, nredir.redirect),
8726 offsetof(union node, nredir.n)|NODE_NOMORE,
8727#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8728 offsetof(union node, nif.elsepart),
8729 offsetof(union node, nif.ifpart),
8730 offsetof(union node, nif.test)|NODE_NOMORE,
8731#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8732 offsetof(union node, nfor.var)|NODE_CHARPTR,
8733 offsetof(union node, nfor.body),
8734 offsetof(union node, nfor.args)|NODE_NOMORE,
8735#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8736 offsetof(union node, ncase.cases),
8737 offsetof(union node, ncase.expr)|NODE_NOMORE,
8738#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8739 offsetof(union node, nclist.body),
8740 offsetof(union node, nclist.pattern),
8741 offsetof(union node, nclist.next)|NODE_NOMORE,
8742#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8743 offsetof(union node, narg.backquote)|NODE_NODELIST,
8744 offsetof(union node, narg.text)|NODE_CHARPTR,
8745 offsetof(union node, narg.next)|NODE_NOMORE,
8746#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8747 offsetof(union node, nfile.fname),
8748 offsetof(union node, nfile.fd)|NODE_INTEGER,
8749 offsetof(union node, nfile.next)|NODE_NOMORE,
8750#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8751 offsetof(union node, ndup.vname),
8752 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8753 offsetof(union node, ndup.fd)|NODE_INTEGER,
8754 offsetof(union node, ndup.next)|NODE_NOMORE,
8755#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8756 offsetof(union node, nhere.doc),
8757 offsetof(union node, nhere.fd)|NODE_INTEGER,
8758 offsetof(union node, nhere.next)|NODE_NOMORE,
8759#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8760 offsetof(union node, nnot.com)|NODE_NOMORE,
8761};
8762
8763#if COPYNODE_OPS12 != 34
8764#error COPYNODE_OPS12 is incorrect
8765#endif
8766
8767static const unsigned char copynode_ops_index[26] = {
8768 COPYNODE_OPS0, /* NSEMI */
8769 COPYNODE_OPS1, /* NCMD */
8770 COPYNODE_OPS2, /* NPIPE */
8771 COPYNODE_OPS3, /* NREDIR */
8772 COPYNODE_OPS3, /* NBACKGND */
8773 COPYNODE_OPS3, /* NSUBSHELL */
8774 COPYNODE_OPS0, /* NAND */
8775 COPYNODE_OPS0, /* NOR */
8776 COPYNODE_OPS4, /* NIF */
8777 COPYNODE_OPS0, /* NWHILE */
8778 COPYNODE_OPS0, /* NUNTIL */
8779 COPYNODE_OPS5, /* NFOR */
8780 COPYNODE_OPS6, /* NCASE */
8781 COPYNODE_OPS7, /* NCLIST */
8782 COPYNODE_OPS8, /* NDEFUN */
8783 COPYNODE_OPS8, /* NARG */
8784 COPYNODE_OPS9, /* NTO */
8785 COPYNODE_OPS9, /* NFROM */
8786 COPYNODE_OPS9, /* NFROMTO */
8787 COPYNODE_OPS9, /* NAPPEND */
8788 COPYNODE_OPS9, /* NTOOV */
8789 COPYNODE_OPS10, /* NTOFD */
8790 COPYNODE_OPS10, /* NFROMFD */
8791 COPYNODE_OPS11, /* NHERE */
8792 COPYNODE_OPS11, /* NXHERE */
8793 COPYNODE_OPS12, /* NNOT */
8794};
8795
8796#if NODE_CHARPTR != NODE_MBRMASK
8797#error NODE_CHARPTR != NODE_MBRMASK!!!
8798#endif
8799#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8800
8801#ifdef COPYNODE_TABLE
8802static union node *
8803copynode(const union node *n)
8804{
8805 union node *new;
8806 const unsigned char *p;
8807
8808 if (n == NULL) {
8809 return NULL;
8810 }
8811 new = funcblock;
8812 new->type = n->type;
8813 funcblock = (char *) funcblock + (int) nodesize[n->type];
8814 p = copynode_ops + (int) copynode_ops_index[n->type];
8815 do {
8816 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8817 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8818
8819 if (!(*p & NODE_MBRMASK)) { /* standard node */
8820 *((union node **)nn) = copynode(*((const union node **) no));
8821 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8822 *((const char **)nn) = nodesavestr(*((const char **)no));
8823 } else if (*p & NODE_NODELIST) { /* nodelist */
8824 *((struct nodelist **)nn)
8825 = copynodelist(*((const struct nodelist **) no));
8826 } else { /* integer */
8827 *((int *) nn) = *((int *) no);
8828 }
8829 } while (!(*p++ & NODE_NOMORE));
8830 return new;
8831}
8832#else /* COPYNODE_TABLE */
8833static union node *
8834copynode(const union node *n)
8835{
8836 union node *new;
8837
8838 if (n == NULL)
8839 return NULL;
8840 new = funcblock;
8841 funcblock = (char *) funcblock + nodesize[n->type];
8842 switch (n->type) {
8843 case NSEMI:
8844 case NAND:
8845 case NOR:
8846 case NWHILE:
8847 case NUNTIL:
8848 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8849 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8850 break;
8851 case NCMD:
8852 new->ncmd.redirect = copynode(n->ncmd.redirect);
8853 new->ncmd.args = copynode(n->ncmd.args);
8854 new->ncmd.assign = copynode(n->ncmd.assign);
8855 new->ncmd.backgnd = n->ncmd.backgnd;
8856 break;
8857 case NPIPE:
8858 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8859 new->npipe.backgnd = n->npipe.backgnd;
8860 break;
8861 case NREDIR:
8862 case NBACKGND:
8863 case NSUBSHELL:
8864 new->nredir.redirect = copynode(n->nredir.redirect);
8865 new->nredir.n = copynode(n->nredir.n);
8866 break;
8867 case NIF:
8868 new->nif.elsepart = copynode(n->nif.elsepart);
8869 new->nif.ifpart = copynode(n->nif.ifpart);
8870 new->nif.test = copynode(n->nif.test);
8871 break;
8872 case NFOR:
8873 new->nfor.var = nodesavestr(n->nfor.var);
8874 new->nfor.body = copynode(n->nfor.body);
8875 new->nfor.args = copynode(n->nfor.args);
8876 break;
8877 case NCASE:
8878 new->ncase.cases = copynode(n->ncase.cases);
8879 new->ncase.expr = copynode(n->ncase.expr);
8880 break;
8881 case NCLIST:
8882 new->nclist.body = copynode(n->nclist.body);
8883 new->nclist.pattern = copynode(n->nclist.pattern);
8884 new->nclist.next = copynode(n->nclist.next);
8885 break;
8886 case NDEFUN:
8887 case NARG:
8888 new->narg.backquote = copynodelist(n->narg.backquote);
8889 new->narg.text = nodesavestr(n->narg.text);
8890 new->narg.next = copynode(n->narg.next);
8891 break;
8892 case NTO:
8893 case NFROM:
8894 case NFROMTO:
8895 case NAPPEND:
8896 case NTOOV:
8897 new->nfile.fname = copynode(n->nfile.fname);
8898 new->nfile.fd = n->nfile.fd;
8899 new->nfile.next = copynode(n->nfile.next);
8900 break;
8901 case NTOFD:
8902 case NFROMFD:
8903 new->ndup.vname = copynode(n->ndup.vname);
8904 new->ndup.dupfd = n->ndup.dupfd;
8905 new->ndup.fd = n->ndup.fd;
8906 new->ndup.next = copynode(n->ndup.next);
8907 break;
8908 case NHERE:
8909 case NXHERE:
8910 new->nhere.doc = copynode(n->nhere.doc);
8911 new->nhere.fd = n->nhere.fd;
8912 new->nhere.next = copynode(n->nhere.next);
8913 break;
8914 case NNOT:
8915 new->nnot.com = copynode(n->nnot.com);
8916 break;
8917 };
8918 new->type = n->type;
8919 return new;
8920}
8921#endif /* COPYNODE_TABLE */
8922
8923#ifdef CALCSIZE_TABLE
8924static void
8925calcsize(const union node *n)
8926{
8927 const unsigned char *p;
8928
8929 if (n == NULL)
8930 return;
8931 funcblocksize += (int) nodesize[n->type];
8932
8933 p = copynode_ops + (int) copynode_ops_index[n->type];
8934 do {
8935 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8936
8937 if (!(*p & NODE_MBRMASK)) { /* standard node */
8938 calcsize(*((const union node **) no));
8939 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8940 funcstringsize += strlen(*((const char **)no)) + 1;
8941 } else if (*p & NODE_NODELIST) { /* nodelist */
8942 sizenodelist(*((const struct nodelist **) no));
8943 } /* else integer -- ignore */
8944 } while (!(*p++ & NODE_NOMORE));
8945}
8946#else /* CALCSIZE_TABLE */
8947static void
8948calcsize(const union node *n)
8949{
8950 if (n == NULL)
8951 return;
8952 funcblocksize += nodesize[n->type];
8953 switch (n->type) {
8954 case NSEMI:
8955 case NAND:
8956 case NOR:
8957 case NWHILE:
8958 case NUNTIL:
8959 calcsize(n->nbinary.ch2);
8960 calcsize(n->nbinary.ch1);
8961 break;
8962 case NCMD:
8963 calcsize(n->ncmd.redirect);
8964 calcsize(n->ncmd.args);
8965 calcsize(n->ncmd.assign);
8966 break;
8967 case NPIPE:
8968 sizenodelist(n->npipe.cmdlist);
8969 break;
8970 case NREDIR:
8971 case NBACKGND:
8972 case NSUBSHELL:
8973 calcsize(n->nredir.redirect);
8974 calcsize(n->nredir.n);
8975 break;
8976 case NIF:
8977 calcsize(n->nif.elsepart);
8978 calcsize(n->nif.ifpart);
8979 calcsize(n->nif.test);
8980 break;
8981 case NFOR:
8982 funcstringsize += strlen(n->nfor.var) + 1;
8983 calcsize(n->nfor.body);
8984 calcsize(n->nfor.args);
8985 break;
8986 case NCASE:
8987 calcsize(n->ncase.cases);
8988 calcsize(n->ncase.expr);
8989 break;
8990 case NCLIST:
8991 calcsize(n->nclist.body);
8992 calcsize(n->nclist.pattern);
8993 calcsize(n->nclist.next);
8994 break;
8995 case NDEFUN:
8996 case NARG:
8997 sizenodelist(n->narg.backquote);
8998 funcstringsize += strlen(n->narg.text) + 1;
8999 calcsize(n->narg.next);
9000 break;
9001 case NTO:
9002 case NFROM:
9003 case NFROMTO:
9004 case NAPPEND:
9005 case NTOOV:
9006 calcsize(n->nfile.fname);
9007 calcsize(n->nfile.next);
9008 break;
9009 case NTOFD:
9010 case NFROMFD:
9011 calcsize(n->ndup.vname);
9012 calcsize(n->ndup.next);
9013 break;
9014 case NHERE:
9015 case NXHERE:
9016 calcsize(n->nhere.doc);
9017 calcsize(n->nhere.next);
9018 break;
9019 case NNOT:
9020 calcsize(n->nnot.com);
9021 break;
9022 };
9023}
9024#endif /* CALCSIZE_TABLE */
9025
9026static void
9027sizenodelist(const struct nodelist *lp)
9028{
9029 while (lp) {
9030 funcblocksize += ALIGN(sizeof(struct nodelist));
9031 calcsize(lp->n);
9032 lp = lp->next;
9033 }
9034}
9035
9036
9037static struct nodelist *
9038copynodelist(const struct nodelist *lp)
9039{
9040 struct nodelist *start;
9041 struct nodelist **lpp;
9042
9043 lpp = &start;
9044 while (lp) {
9045 *lpp = funcblock;
9046 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9047 (*lpp)->n = copynode(lp->n);
9048 lp = lp->next;
9049 lpp = &(*lpp)->next;
9050 }
9051 *lpp = NULL;
9052 return start;
9053}
9054
9055
9056static char *
9057nodesavestr(const char *s)
9058{
9059 const char *p = s;
9060 char *q = funcstring;
9061 char *rtn = funcstring;
9062
9063 while ((*q++ = *p++) != '\0')
9064 continue;
9065 funcstring = q;
9066 return rtn;
9067}
9068
9069#ifdef ASH_GETOPTS
9070static int getopts (char *, char *, char **, int *, int *);
9071#endif
9072
9073
9074/*
9075 * Process the shell command line arguments.
9076 */
9077
9078static void
9079procargs(argc, argv)
9080 int argc;
9081 char **argv;
9082{
9083 int i;
9084
9085 argptr = argv;
9086 if (argc > 0)
9087 argptr++;
9088 for (i = 0; i < NOPTS; i++)
9089 optent_val(i) = 2;
9090 options(1);
9091 if (*argptr == NULL && minusc == NULL)
9092 sflag = 1;
9093 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9094 iflag = 1;
9095 if (mflag == 2)
9096 mflag = iflag;
9097 for (i = 0; i < NOPTS; i++)
9098 if (optent_val(i) == 2)
9099 optent_val(i) = 0;
9100 arg0 = argv[0];
9101 if (sflag == 0 && minusc == NULL) {
9102 commandname = argv[0];
9103 arg0 = *argptr++;
9104 setinputfile(arg0, 0);
9105 commandname = arg0;
9106 }
9107 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9108 if (argptr && minusc && *argptr)
9109 arg0 = *argptr++;
9110
9111 shellparam.p = argptr;
9112 shellparam.optind = 1;
9113 shellparam.optoff = -1;
9114 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9115 while (*argptr) {
9116 shellparam.nparam++;
9117 argptr++;
9118 }
9119 optschanged();
9120}
9121
9122
9123
9124/*
9125 * Process shell options. The global variable argptr contains a pointer
9126 * to the argument list; we advance it past the options.
9127 */
9128
9129static inline void
9130minus_o(const char *name, int val)
9131{
9132 int i;
9133
9134 if (name == NULL) {
9135 out1str("Current option settings\n");
9136 for (i = 0; i < NOPTS; i++)
9137 printf("%-16s%s\n", optent_name(optlist[i]),
9138 optent_val(i) ? "on" : "off");
9139 } else {
9140 for (i = 0; i < NOPTS; i++)
9141 if (equal(name, optent_name(optlist[i]))) {
9142 setoption(optent_letter(optlist[i]), val);
9143 return;
9144 }
9145 error("Illegal option -o %s", name);
9146 }
9147}
9148
9149
9150static void
9151options(int cmdline)
9152{
9153 char *p;
9154 int val;
9155 int c;
9156
9157 if (cmdline)
9158 minusc = NULL;
9159 while ((p = *argptr) != NULL) {
9160 argptr++;
9161 if ((c = *p++) == '-') {
9162 val = 1;
9163 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9164 if (!cmdline) {
9165 /* "-" means turn off -x and -v */
9166 if (p[0] == '\0')
9167 xflag = vflag = 0;
9168 /* "--" means reset params */
9169 else if (*argptr == NULL)
9170 setparam(argptr);
9171 }
9172 break; /* "-" or "--" terminates options */
9173 }
9174 } else if (c == '+') {
9175 val = 0;
9176 } else {
9177 argptr--;
9178 break;
9179 }
9180 while ((c = *p++) != '\0') {
9181 if (c == 'c' && cmdline) {
9182 char *q;
9183#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
9184 if (*p == '\0')
9185#endif
9186 q = *argptr++;
9187 if (q == NULL || minusc != NULL)
9188 error("Bad -c option");
9189 minusc = q;
9190#ifdef NOHACK
9191 break;
9192#endif
9193 } else if (c == 'o') {
9194 minus_o(*argptr, val);
9195 if (*argptr)
9196 argptr++;
9197 } else {
9198 setoption(c, val);
9199 }
9200 }
9201 }
9202}
9203
9204
9205static void
9206setoption(int flag, int val)
9207{
9208 int i;
9209
9210 for (i = 0; i < NOPTS; i++)
9211 if (optent_letter(optlist[i]) == flag) {
9212 optent_val(i) = val;
9213 if (val) {
9214 /* #%$ hack for ksh semantics */
9215 if (flag == 'V')
9216 Eflag = 0;
9217 else if (flag == 'E')
9218 Vflag = 0;
9219 }
9220 return;
9221 }
9222 error("Illegal option -%c", flag);
9223 /* NOTREACHED */
9224}
9225
9226
9227
9228/*
9229 * Set the shell parameters.
9230 */
9231
9232static void
9233setparam(char **argv)
9234{
9235 char **newparam;
9236 char **ap;
9237 int nparam;
9238
9239 for (nparam = 0 ; argv[nparam] ; nparam++);
9240 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9241 while (*argv) {
9242 *ap++ = savestr(*argv++);
9243 }
9244 *ap = NULL;
9245 freeparam(&shellparam);
9246 shellparam.malloc = 1;
9247 shellparam.nparam = nparam;
9248 shellparam.p = newparam;
9249 shellparam.optind = 1;
9250 shellparam.optoff = -1;
9251}
9252
9253
9254/*
9255 * Free the list of positional parameters.
9256 */
9257
9258static void
9259freeparam(volatile struct shparam *param)
9260{
9261 char **ap;
9262
9263 if (param->malloc) {
9264 for (ap = param->p ; *ap ; ap++)
9265 ckfree(*ap);
9266 ckfree(param->p);
9267 }
9268}
9269
9270
9271
9272/*
9273 * The shift builtin command.
9274 */
9275
9276static int
9277shiftcmd(argc, argv)
9278 int argc;
9279 char **argv;
9280{
9281 int n;
9282 char **ap1, **ap2;
9283
9284 n = 1;
9285 if (argc > 1)
9286 n = number(argv[1]);
9287 if (n > shellparam.nparam)
9288 error("can't shift that many");
9289 INTOFF;
9290 shellparam.nparam -= n;
9291 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9292 if (shellparam.malloc)
9293 ckfree(*ap1);
9294 }
9295 ap2 = shellparam.p;
9296 while ((*ap2++ = *ap1++) != NULL);
9297 shellparam.optind = 1;
9298 shellparam.optoff = -1;
9299 INTON;
9300 return 0;
9301}
9302
9303
9304
9305/*
9306 * The set command builtin.
9307 */
9308
9309static int
9310setcmd(argc, argv)
9311 int argc;
9312 char **argv;
9313{
9314 if (argc == 1)
9315 return showvarscmd(argc, argv);
9316 INTOFF;
9317 options(0);
9318 optschanged();
9319 if (*argptr != NULL) {
9320 setparam(argptr);
9321 }
9322 INTON;
9323 return 0;
9324}
9325
9326
9327static void
9328getoptsreset(const char *value)
9329{
9330 shellparam.optind = number(value);
9331 shellparam.optoff = -1;
9332}
9333
9334#ifdef BB_LOCALE_SUPPORT
9335static void change_lc_all(const char *value)
9336{
9337 if(value != 0 && *value != 0)
9338 setlocale(LC_ALL, value);
9339}
9340
9341static void change_lc_ctype(const char *value)
9342{
9343 if(value != 0 && *value != 0)
9344 setlocale(LC_CTYPE, value);
9345}
9346
9347#endif
9348
9349#ifdef ASH_GETOPTS
9350/*
9351 * The getopts builtin. Shellparam.optnext points to the next argument
9352 * to be processed. Shellparam.optptr points to the next character to
9353 * be processed in the current argument. If shellparam.optnext is NULL,
9354 * then it's the first time getopts has been called.
9355 */
9356
9357static int
9358getoptscmd(argc, argv)
9359 int argc;
9360 char **argv;
9361{
9362 char **optbase;
9363
9364 if (argc < 3)
9365 error("Usage: getopts optstring var [arg]");
9366 else if (argc == 3) {
9367 optbase = shellparam.p;
9368 if (shellparam.optind > shellparam.nparam + 1) {
9369 shellparam.optind = 1;
9370 shellparam.optoff = -1;
9371 }
9372 }
9373 else {
9374 optbase = &argv[3];
9375 if (shellparam.optind > argc - 2) {
9376 shellparam.optind = 1;
9377 shellparam.optoff = -1;
9378 }
9379 }
9380
9381 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9382 &shellparam.optoff);
9383}
9384
9385/*
9386 * Safe version of setvar, returns 1 on success 0 on failure.
9387 */
9388
9389static int
9390setvarsafe(name, val, flags)
9391 const char *name, *val;
9392 int flags;
9393{
9394 struct jmploc jmploc;
9395 struct jmploc *volatile savehandler = handler;
9396 int err = 0;
9397#ifdef __GNUC__
9398 (void) &err;
9399#endif
9400
9401 if (setjmp(jmploc.loc))
9402 err = 1;
9403 else {
9404 handler = &jmploc;
9405 setvar(name, val, flags);
9406 }
9407 handler = savehandler;
9408 return err;
9409}
9410
9411static int
9412getopts(optstr, optvar, optfirst, myoptind, optoff)
9413 char *optstr;
9414 char *optvar;
9415 char **optfirst;
9416 int *myoptind;
9417 int *optoff;
9418{
9419 char *p, *q;
9420 char c = '?';
9421 int done = 0;
9422 int err = 0;
9423 char s[10];
9424 char **optnext = optfirst + *myoptind - 1;
9425
9426 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9427 strlen(*(optnext - 1)) < *optoff)
9428 p = NULL;
9429 else
9430 p = *(optnext - 1) + *optoff;
9431 if (p == NULL || *p == '\0') {
9432 /* Current word is done, advance */
9433 if (optnext == NULL)
9434 return 1;
9435 p = *optnext;
9436 if (p == NULL || *p != '-' || *++p == '\0') {
9437atend:
9438 *myoptind = optnext - optfirst + 1;
9439 p = NULL;
9440 done = 1;
9441 goto out;
9442 }
9443 optnext++;
9444 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9445 goto atend;
9446 }
9447
9448 c = *p++;
9449 for (q = optstr; *q != c; ) {
9450 if (*q == '\0') {
9451 if (optstr[0] == ':') {
9452 s[0] = c;
9453 s[1] = '\0';
9454 err |= setvarsafe("OPTARG", s, 0);
9455 }
9456 else {
9457 out2fmt("Illegal option -%c\n", c);
9458 (void) unsetvar("OPTARG");
9459 }
9460 c = '?';
9461 goto bad;
9462 }
9463 if (*++q == ':')
9464 q++;
9465 }
9466
9467 if (*++q == ':') {
9468 if (*p == '\0' && (p = *optnext) == NULL) {
9469 if (optstr[0] == ':') {
9470 s[0] = c;
9471 s[1] = '\0';
9472 err |= setvarsafe("OPTARG", s, 0);
9473 c = ':';
9474 }
9475 else {
9476 out2fmt("No arg for -%c option\n", c);
9477 (void) unsetvar("OPTARG");
9478 c = '?';
9479 }
9480 goto bad;
9481 }
9482
9483 if (p == *optnext)
9484 optnext++;
9485 setvarsafe("OPTARG", p, 0);
9486 p = NULL;
9487 }
9488 else
9489 setvarsafe("OPTARG", "", 0);
9490 *myoptind = optnext - optfirst + 1;
9491 goto out;
9492
9493bad:
9494 *myoptind = 1;
9495 p = NULL;
9496out:
9497 *optoff = p ? p - *(optnext - 1) : -1;
9498 snprintf(s, sizeof(s), "%d", *myoptind);
9499 err |= setvarsafe("OPTIND", s, VNOFUNC);
9500 s[0] = c;
9501 s[1] = '\0';
9502 err |= setvarsafe(optvar, s, 0);
9503 if (err) {
9504 *myoptind = 1;
9505 *optoff = -1;
9506 exraise(EXERROR);
9507 }
9508 return done;
9509}
9510#endif
9511
9512/*
9513 * XXX - should get rid of. have all builtins use getopt(3). the
9514 * library getopt must have the BSD extension static variable "optreset"
9515 * otherwise it can't be used within the shell safely.
9516 *
9517 * Standard option processing (a la getopt) for builtin routines. The
9518 * only argument that is passed to nextopt is the option string; the
9519 * other arguments are unnecessary. It return the character, or '\0' on
9520 * end of input.
9521 */
9522
9523static int
9524nextopt(const char *optstring)
9525{
9526 char *p;
9527 const char *q;
9528 char c;
9529
9530 if ((p = optptr) == NULL || *p == '\0') {
9531 p = *argptr;
9532 if (p == NULL || *p != '-' || *++p == '\0')
9533 return '\0';
9534 argptr++;
9535 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9536 return '\0';
9537 }
9538 c = *p++;
9539 for (q = optstring ; *q != c ; ) {
9540 if (*q == '\0')
9541 error("Illegal option -%c", c);
9542 if (*++q == ':')
9543 q++;
9544 }
9545 if (*++q == ':') {
9546 if (*p == '\0' && (p = *argptr++) == NULL)
9547 error("No arg for -%c option", c);
9548 optionarg = p;
9549 p = NULL;
9550 }
9551 optptr = p;
9552 return c;
9553}
9554
9555static void
9556flushall() {
9557 INTOFF;
9558 fflush(stdout);
9559 INTON;
9560}
9561
9562
9563static void
9564out2fmt(const char *fmt, ...)
9565{
9566 va_list ap;
9567 va_start(ap, fmt);
9568 vfprintf(stderr, fmt, ap);
9569 va_end(ap);
9570}
9571
9572/*
9573 * Version of write which resumes after a signal is caught.
9574 */
9575
9576static int
9577xwrite(int fd, const char *buf, int nbytes)
9578{
9579 int ntry;
9580 int i;
9581 int n;
9582
9583 n = nbytes;
9584 ntry = 0;
9585 for (;;) {
9586 i = write(fd, buf, n);
9587 if (i > 0) {
9588 if ((n -= i) <= 0)
9589 return nbytes;
9590 buf += i;
9591 ntry = 0;
9592 } else if (i == 0) {
9593 if (++ntry > 10)
9594 return nbytes - n;
9595 } else if (errno != EINTR) {
9596 return -1;
9597 }
9598 }
9599}
9600
9601
9602/*
9603 * Shell command parser.
9604 */
9605
9606#define EOFMARKLEN 79
9607
9608
9609
9610struct heredoc {
9611 struct heredoc *next; /* next here document in list */
9612 union node *here; /* redirection node */
9613 char *eofmark; /* string indicating end of input */
9614 int striptabs; /* if set, strip leading tabs */
9615};
9616
9617static struct heredoc *heredoclist; /* list of here documents to read */
9618static int parsebackquote; /* nonzero if we are inside backquotes */
9619static int doprompt; /* if set, prompt the user */
9620static int needprompt; /* true if interactive and at start of line */
9621static int lasttoken; /* last token read */
9622
9623static char *wordtext; /* text of last word returned by readtoken */
9624
9625static struct nodelist *backquotelist;
9626static union node *redirnode;
9627static struct heredoc *heredoc;
9628static int quoteflag; /* set if (part of) last token was quoted */
9629static int startlinno; /* line # where last token started */
9630
9631
9632static union node *list (int);
9633static union node *andor (void);
9634static union node *pipeline (void);
9635static union node *command (void);
9636static union node *simplecmd (void);
9637static void parsefname (void);
9638static void parseheredoc (void);
9639static char peektoken (void);
9640static int readtoken (void);
9641static int xxreadtoken (void);
9642static int readtoken1 (int, int, const char *, int);
9643static int noexpand (char *);
9644static void synexpect (int) __attribute__((noreturn));
9645static void synerror (const char *) __attribute__((noreturn));
9646static void setprompt (int);
9647
9648
9649/*
9650 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9651 * valid parse tree indicating a blank line.)
9652 */
9653
9654static union node *
9655parsecmd(int interact)
9656{
9657 int t;
9658
9659 tokpushback = 0;
9660 doprompt = interact;
9661 if (doprompt)
9662 setprompt(1);
9663 else
9664 setprompt(0);
9665 needprompt = 0;
9666 t = readtoken();
9667 if (t == TEOF)
9668 return NEOF;
9669 if (t == TNL)
9670 return NULL;
9671 tokpushback++;
9672 return list(1);
9673}
9674
9675
9676static union node *
9677list(nlflag)
9678 int nlflag;
9679{
9680 union node *n1, *n2, *n3;
9681 int tok;
9682
9683 checkkwd = 2;
9684 if (nlflag == 0 && peektoken())
9685 return NULL;
9686 n1 = NULL;
9687 for (;;) {
9688 n2 = andor();
9689 tok = readtoken();
9690 if (tok == TBACKGND) {
9691 if (n2->type == NCMD || n2->type == NPIPE) {
9692 n2->ncmd.backgnd = 1;
9693 } else if (n2->type == NREDIR) {
9694 n2->type = NBACKGND;
9695 } else {
9696 n3 = (union node *)stalloc(sizeof (struct nredir));
9697 n3->type = NBACKGND;
9698 n3->nredir.n = n2;
9699 n3->nredir.redirect = NULL;
9700 n2 = n3;
9701 }
9702 }
9703 if (n1 == NULL) {
9704 n1 = n2;
9705 }
9706 else {
9707 n3 = (union node *)stalloc(sizeof (struct nbinary));
9708 n3->type = NSEMI;
9709 n3->nbinary.ch1 = n1;
9710 n3->nbinary.ch2 = n2;
9711 n1 = n3;
9712 }
9713 switch (tok) {
9714 case TBACKGND:
9715 case TSEMI:
9716 tok = readtoken();
9717 /* fall through */
9718 case TNL:
9719 if (tok == TNL) {
9720 parseheredoc();
9721 if (nlflag)
9722 return n1;
9723 } else {
9724 tokpushback++;
9725 }
9726 checkkwd = 2;
9727 if (peektoken())
9728 return n1;
9729 break;
9730 case TEOF:
9731 if (heredoclist)
9732 parseheredoc();
9733 else
9734 pungetc(); /* push back EOF on input */
9735 return n1;
9736 default:
9737 if (nlflag)
9738 synexpect(-1);
9739 tokpushback++;
9740 return n1;
9741 }
9742 }
9743}
9744
9745
9746
9747static union node *
9748andor() {
9749 union node *n1, *n2, *n3;
9750 int t;
9751
9752 checkkwd = 1;
9753 n1 = pipeline();
9754 for (;;) {
9755 if ((t = readtoken()) == TAND) {
9756 t = NAND;
9757 } else if (t == TOR) {
9758 t = NOR;
9759 } else {
9760 tokpushback++;
9761 return n1;
9762 }
9763 checkkwd = 2;
9764 n2 = pipeline();
9765 n3 = (union node *)stalloc(sizeof (struct nbinary));
9766 n3->type = t;
9767 n3->nbinary.ch1 = n1;
9768 n3->nbinary.ch2 = n2;
9769 n1 = n3;
9770 }
9771}
9772
9773
9774
9775static union node *
9776pipeline() {
9777 union node *n1, *n2, *pipenode;
9778 struct nodelist *lp, *prev;
9779 int negate;
9780
9781 negate = 0;
9782 TRACE(("pipeline: entered\n"));
9783 if (readtoken() == TNOT) {
9784 negate = !negate;
9785 checkkwd = 1;
9786 } else
9787 tokpushback++;
9788 n1 = command();
9789 if (readtoken() == TPIPE) {
9790 pipenode = (union node *)stalloc(sizeof (struct npipe));
9791 pipenode->type = NPIPE;
9792 pipenode->npipe.backgnd = 0;
9793 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9794 pipenode->npipe.cmdlist = lp;
9795 lp->n = n1;
9796 do {
9797 prev = lp;
9798 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9799 checkkwd = 2;
9800 lp->n = command();
9801 prev->next = lp;
9802 } while (readtoken() == TPIPE);
9803 lp->next = NULL;
9804 n1 = pipenode;
9805 }
9806 tokpushback++;
9807 if (negate) {
9808 n2 = (union node *)stalloc(sizeof (struct nnot));
9809 n2->type = NNOT;
9810 n2->nnot.com = n1;
9811 return n2;
9812 } else
9813 return n1;
9814}
9815
9816
9817
9818static union node *
9819command() {
9820 union node *n1, *n2;
9821 union node *ap, **app;
9822 union node *cp, **cpp;
9823 union node *redir, **rpp;
9824 int t;
9825
9826 redir = NULL;
9827 n1 = NULL;
9828 rpp = &redir;
9829
9830 /* Check for redirection which may precede command */
9831 while (readtoken() == TREDIR) {
9832 *rpp = n2 = redirnode;
9833 rpp = &n2->nfile.next;
9834 parsefname();
9835 }
9836 tokpushback++;
9837
9838 switch (readtoken()) {
9839 case TIF:
9840 n1 = (union node *)stalloc(sizeof (struct nif));
9841 n1->type = NIF;
9842 n1->nif.test = list(0);
9843 if (readtoken() != TTHEN)
9844 synexpect(TTHEN);
9845 n1->nif.ifpart = list(0);
9846 n2 = n1;
9847 while (readtoken() == TELIF) {
9848 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9849 n2 = n2->nif.elsepart;
9850 n2->type = NIF;
9851 n2->nif.test = list(0);
9852 if (readtoken() != TTHEN)
9853 synexpect(TTHEN);
9854 n2->nif.ifpart = list(0);
9855 }
9856 if (lasttoken == TELSE)
9857 n2->nif.elsepart = list(0);
9858 else {
9859 n2->nif.elsepart = NULL;
9860 tokpushback++;
9861 }
9862 if (readtoken() != TFI)
9863 synexpect(TFI);
9864 checkkwd = 1;
9865 break;
9866 case TWHILE:
9867 case TUNTIL: {
9868 int got;
9869 n1 = (union node *)stalloc(sizeof (struct nbinary));
9870 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9871 n1->nbinary.ch1 = list(0);
9872 if ((got=readtoken()) != TDO) {
9873TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9874 synexpect(TDO);
9875 }
9876 n1->nbinary.ch2 = list(0);
9877 if (readtoken() != TDONE)
9878 synexpect(TDONE);
9879 checkkwd = 1;
9880 break;
9881 }
9882 case TFOR:
9883 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9884 synerror("Bad for loop variable");
9885 n1 = (union node *)stalloc(sizeof (struct nfor));
9886 n1->type = NFOR;
9887 n1->nfor.var = wordtext;
9888 checkkwd = 1;
9889 if (readtoken() == TIN) {
9890 app = &ap;
9891 while (readtoken() == TWORD) {
9892 n2 = (union node *)stalloc(sizeof (struct narg));
9893 n2->type = NARG;
9894 n2->narg.text = wordtext;
9895 n2->narg.backquote = backquotelist;
9896 *app = n2;
9897 app = &n2->narg.next;
9898 }
9899 *app = NULL;
9900 n1->nfor.args = ap;
9901 if (lasttoken != TNL && lasttoken != TSEMI)
9902 synexpect(-1);
9903 } else {
9904 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9905 '@', '=', '\0'};
9906 n2 = (union node *)stalloc(sizeof (struct narg));
9907 n2->type = NARG;
9908 n2->narg.text = argvars;
9909 n2->narg.backquote = NULL;
9910 n2->narg.next = NULL;
9911 n1->nfor.args = n2;
9912 /*
9913 * Newline or semicolon here is optional (but note
9914 * that the original Bourne shell only allowed NL).
9915 */
9916 if (lasttoken != TNL && lasttoken != TSEMI)
9917 tokpushback++;
9918 }
9919 checkkwd = 2;
9920 if (readtoken() != TDO)
9921 synexpect(TDO);
9922 n1->nfor.body = list(0);
9923 if (readtoken() != TDONE)
9924 synexpect(TDONE);
9925 checkkwd = 1;
9926 break;
9927 case TCASE:
9928 n1 = (union node *)stalloc(sizeof (struct ncase));
9929 n1->type = NCASE;
9930 if (readtoken() != TWORD)
9931 synexpect(TWORD);
9932 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9933 n2->type = NARG;
9934 n2->narg.text = wordtext;
9935 n2->narg.backquote = backquotelist;
9936 n2->narg.next = NULL;
9937 do {
9938 checkkwd = 1;
9939 } while (readtoken() == TNL);
9940 if (lasttoken != TIN)
9941 synerror("expecting \"in\"");
9942 cpp = &n1->ncase.cases;
9943 checkkwd = 2, readtoken();
9944 do {
9945 if (lasttoken == TLP)
9946 readtoken();
9947 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9948 cp->type = NCLIST;
9949 app = &cp->nclist.pattern;
9950 for (;;) {
9951 *app = ap = (union node *)stalloc(sizeof (struct narg));
9952 ap->type = NARG;
9953 ap->narg.text = wordtext;
9954 ap->narg.backquote = backquotelist;
9955 if (checkkwd = 2, readtoken() != TPIPE)
9956 break;
9957 app = &ap->narg.next;
9958 readtoken();
9959 }
9960 ap->narg.next = NULL;
9961 if (lasttoken != TRP)
9962 synexpect(TRP);
9963 cp->nclist.body = list(0);
9964
9965 checkkwd = 2;
9966 if ((t = readtoken()) != TESAC) {
9967 if (t != TENDCASE)
9968 synexpect(TENDCASE);
9969 else
9970 checkkwd = 2, readtoken();
9971 }
9972 cpp = &cp->nclist.next;
9973 } while(lasttoken != TESAC);
9974 *cpp = NULL;
9975 checkkwd = 1;
9976 break;
9977 case TLP:
9978 n1 = (union node *)stalloc(sizeof (struct nredir));
9979 n1->type = NSUBSHELL;
9980 n1->nredir.n = list(0);
9981 n1->nredir.redirect = NULL;
9982 if (readtoken() != TRP)
9983 synexpect(TRP);
9984 checkkwd = 1;
9985 break;
9986 case TBEGIN:
9987 n1 = list(0);
9988 if (readtoken() != TEND)
9989 synexpect(TEND);
9990 checkkwd = 1;
9991 break;
9992 /* Handle an empty command like other simple commands. */
9993 case TSEMI:
9994 case TAND:
9995 case TOR:
9996 case TNL:
9997 case TEOF:
9998 case TRP:
9999 case TBACKGND:
10000 /*
10001 * An empty command before a ; doesn't make much sense, and
10002 * should certainly be disallowed in the case of `if ;'.
10003 */
10004 if (!redir)
10005 synexpect(-1);
10006 case TWORD:
10007 tokpushback++;
10008 n1 = simplecmd();
10009 return n1;
10010 default:
10011 synexpect(-1);
10012 /* NOTREACHED */
10013 }
10014
10015 /* Now check for redirection which may follow command */
10016 while (readtoken() == TREDIR) {
10017 *rpp = n2 = redirnode;
10018 rpp = &n2->nfile.next;
10019 parsefname();
10020 }
10021 tokpushback++;
10022 *rpp = NULL;
10023 if (redir) {
10024 if (n1->type != NSUBSHELL) {
10025 n2 = (union node *)stalloc(sizeof (struct nredir));
10026 n2->type = NREDIR;
10027 n2->nredir.n = n1;
10028 n1 = n2;
10029 }
10030 n1->nredir.redirect = redir;
10031 }
10032
10033 return n1;
10034}
10035
10036
10037static union node *
10038simplecmd() {
10039 union node *args, **app;
10040 union node *n = NULL;
10041 union node *vars, **vpp;
10042 union node **rpp, *redir;
10043
10044 args = NULL;
10045 app = &args;
10046 vars = NULL;
10047 vpp = &vars;
10048 redir = NULL;
10049 rpp = &redir;
10050
10051 checkalias = 2;
10052 for (;;) {
10053 switch (readtoken()) {
10054 case TWORD:
10055 case TASSIGN:
10056 n = (union node *)stalloc(sizeof (struct narg));
10057 n->type = NARG;
10058 n->narg.text = wordtext;
10059 n->narg.backquote = backquotelist;
10060 if (lasttoken == TWORD) {
10061 *app = n;
10062 app = &n->narg.next;
10063 } else {
10064 *vpp = n;
10065 vpp = &n->narg.next;
10066 }
10067 break;
10068 case TREDIR:
10069 *rpp = n = redirnode;
10070 rpp = &n->nfile.next;
10071 parsefname(); /* read name of redirection file */
10072 break;
10073 case TLP:
10074 if (
10075 args && app == &args->narg.next &&
10076 !vars && !redir
10077 ) {
10078 /* We have a function */
10079 if (readtoken() != TRP)
10080 synexpect(TRP);
10081 n->type = NDEFUN;
10082 checkkwd = 2;
10083 n->narg.next = command();
10084 return n;
10085 }
10086 /* fall through */
10087 default:
10088 tokpushback++;
10089 goto out;
10090 }
10091 }
10092out:
10093 *app = NULL;
10094 *vpp = NULL;
10095 *rpp = NULL;
10096 n = (union node *)stalloc(sizeof (struct ncmd));
10097 n->type = NCMD;
10098 n->ncmd.backgnd = 0;
10099 n->ncmd.args = args;
10100 n->ncmd.assign = vars;
10101 n->ncmd.redirect = redir;
10102 return n;
10103}
10104
10105static union node *
10106makename(void) {
10107 union node *n;
10108
10109 n = (union node *)stalloc(sizeof (struct narg));
10110 n->type = NARG;
10111 n->narg.next = NULL;
10112 n->narg.text = wordtext;
10113 n->narg.backquote = backquotelist;
10114 return n;
10115}
10116
10117static void fixredir(union node *n, const char *text, int err)
10118{
10119 TRACE(("Fix redir %s %d\n", text, err));
10120 if (!err)
10121 n->ndup.vname = NULL;
10122
10123 if (is_digit(text[0]) && text[1] == '\0')
10124 n->ndup.dupfd = digit_val(text[0]);
10125 else if (text[0] == '-' && text[1] == '\0')
10126 n->ndup.dupfd = -1;
10127 else {
10128
10129 if (err)
10130 synerror("Bad fd number");
10131 else
10132 n->ndup.vname = makename();
10133 }
10134}
10135
10136
10137static void
10138parsefname(void) {
10139 union node *n = redirnode;
10140
10141 if (readtoken() != TWORD)
10142 synexpect(-1);
10143 if (n->type == NHERE) {
10144 struct heredoc *here = heredoc;
10145 struct heredoc *p;
10146 int i;
10147
10148 if (quoteflag == 0)
10149 n->type = NXHERE;
10150 TRACE(("Here document %d\n", n->type));
10151 if (here->striptabs) {
10152 while (*wordtext == '\t')
10153 wordtext++;
10154 }
10155 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10156 synerror("Illegal eof marker for << redirection");
10157 rmescapes(wordtext);
10158 here->eofmark = wordtext;
10159 here->next = NULL;
10160 if (heredoclist == NULL)
10161 heredoclist = here;
10162 else {
10163 for (p = heredoclist ; p->next ; p = p->next);
10164 p->next = here;
10165 }
10166 } else if (n->type == NTOFD || n->type == NFROMFD) {
10167 fixredir(n, wordtext, 0);
10168 } else {
10169 n->nfile.fname = makename();
10170 }
10171}
10172
10173
10174/*
10175 * Input any here documents.
10176 */
10177
10178static void
10179parseheredoc() {
10180 struct heredoc *here;
10181 union node *n;
10182
10183 while (heredoclist) {
10184 here = heredoclist;
10185 heredoclist = here->next;
10186 if (needprompt) {
10187 setprompt(2);
10188 needprompt = 0;
10189 }
10190 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10191 here->eofmark, here->striptabs);
10192 n = (union node *)stalloc(sizeof (struct narg));
10193 n->narg.type = NARG;
10194 n->narg.next = NULL;
10195 n->narg.text = wordtext;
10196 n->narg.backquote = backquotelist;
10197 here->here->nhere.doc = n;
10198 }
10199}
10200
10201static char
10202peektoken() {
10203 int t;
10204
10205 t = readtoken();
10206 tokpushback++;
10207 return tokname_array[t][0];
10208}
10209
10210static int
10211readtoken() {
10212 int t;
10213
10214#ifdef ASH_ALIAS
10215 int savecheckalias = checkalias;
10216 int savecheckkwd = checkkwd;
10217 struct alias *ap;
10218#endif
10219
10220#ifdef DEBUG
10221 int alreadyseen = tokpushback;
10222#endif
10223
10224#ifdef ASH_ALIAS
10225top:
10226#endif
10227
10228 t = xxreadtoken();
10229
10230#ifdef ASH_ALIAS
10231 checkalias = savecheckalias;
10232#endif
10233
10234 if (checkkwd) {
10235 /*
10236 * eat newlines
10237 */
10238 if (checkkwd == 2) {
10239 checkkwd = 0;
10240 while (t == TNL) {
10241 parseheredoc();
10242 t = xxreadtoken();
10243 }
10244 }
10245 checkkwd = 0;
10246 /*
10247 * check for keywords
10248 */
10249 if (t == TWORD && !quoteflag)
10250 {
10251 const char *const *pp;
10252
10253 if ((pp = findkwd(wordtext))) {
10254 lasttoken = t = pp - tokname_array;
10255 TRACE(("keyword %s recognized\n", tokname(t)));
10256 goto out;
10257 }
10258 }
10259 }
10260
10261
10262 if (t != TWORD) {
10263 if (t != TREDIR) {
10264 checkalias = 0;
10265 }
10266 } else if (checkalias == 2 && isassignment(wordtext)) {
10267 lasttoken = t = TASSIGN;
10268#ifdef ASH_ALIAS
10269 } else if (checkalias) {
10270 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10271 if (*ap->val) {
10272 pushstring(ap->val, strlen(ap->val), ap);
10273 }
10274 checkkwd = savecheckkwd;
10275 goto top;
10276 }
10277 checkalias = 0;
10278#endif
10279 }
10280out:
10281#ifdef DEBUG
10282 if (!alreadyseen)
10283 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
10284 else
10285 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
10286#endif
10287 return (t);
10288}
10289
10290
10291/*
10292 * Read the next input token.
10293 * If the token is a word, we set backquotelist to the list of cmds in
10294 * backquotes. We set quoteflag to true if any part of the word was
10295 * quoted.
10296 * If the token is TREDIR, then we set redirnode to a structure containing
10297 * the redirection.
10298 * In all cases, the variable startlinno is set to the number of the line
10299 * on which the token starts.
10300 *
10301 * [Change comment: here documents and internal procedures]
10302 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10303 * word parsing code into a separate routine. In this case, readtoken
10304 * doesn't need to have any internal procedures, but parseword does.
10305 * We could also make parseoperator in essence the main routine, and
10306 * have parseword (readtoken1?) handle both words and redirection.]
10307 */
10308
10309#define NEW_xxreadtoken
10310#ifdef NEW_xxreadtoken
10311
10312static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10313static const char xxreadtoken_tokens[] = {
10314 TNL, TLP, TRP, /* only single occurrence allowed */
10315 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10316 TEOF, /* corresponds to trailing nul */
10317 TAND, TOR, TENDCASE, /* if double occurrence */
10318};
10319
10320#define xxreadtoken_doubles \
10321 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10322#define xxreadtoken_singles \
10323 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10324
10325static int
10326xxreadtoken() {
10327 int c;
10328
10329 if (tokpushback) {
10330 tokpushback = 0;
10331 return lasttoken;
10332 }
10333 if (needprompt) {
10334 setprompt(2);
10335 needprompt = 0;
10336 }
10337 startlinno = plinno;
10338 for (;;) { /* until token or start of word found */
10339 c = pgetc_macro();
10340
10341 if ((c!=' ') && (c!='\t')
10342#ifdef ASH_ALIAS
10343 && (c!=PEOA)
10344#endif
10345 ) {
10346 if (c=='#') {
10347 while ((c = pgetc()) != '\n' && c != PEOF);
10348 pungetc();
10349 } else if (c=='\\') {
10350 if (pgetc() != '\n') {
10351 pungetc();
10352 goto READTOKEN1;
10353 }
10354 startlinno = ++plinno;
10355 setprompt(doprompt ? 2 : 0);
10356 } else {
10357 const char *p
10358 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10359
10360 if (c!=PEOF) {
10361 if (c=='\n') {
10362 plinno++;
10363 needprompt = doprompt;
10364 }
10365
10366 p = strchr(xxreadtoken_chars, c);
10367 if (p == NULL) {
10368 READTOKEN1:
10369 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10370 }
10371
10372 if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10373 if (pgetc() == *p) { /* double occurrence? */
10374 p += xxreadtoken_doubles + 1;
10375 } else {
10376 pungetc();
10377 }
10378 }
10379 }
10380
10381 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10382 }
10383 }
10384 }
10385}
10386
10387
10388#else
10389#define RETURN(token) return lasttoken = token
10390
10391static int
10392xxreadtoken() {
10393 int c;
10394
10395 if (tokpushback) {
10396 tokpushback = 0;
10397 return lasttoken;
10398 }
10399 if (needprompt) {
10400 setprompt(2);
10401 needprompt = 0;
10402 }
10403 startlinno = plinno;
10404 for (;;) { /* until token or start of word found */
10405 c = pgetc_macro();
10406 switch (c) {
10407 case ' ': case '\t':
10408#ifdef ASH_ALIAS
10409 case PEOA:
10410#endif
10411 continue;
10412 case '#':
10413 while ((c = pgetc()) != '\n' && c != PEOF);
10414 pungetc();
10415 continue;
10416 case '\\':
10417 if (pgetc() == '\n') {
10418 startlinno = ++plinno;
10419 if (doprompt)
10420 setprompt(2);
10421 else
10422 setprompt(0);
10423 continue;
10424 }
10425 pungetc();
10426 goto breakloop;
10427 case '\n':
10428 plinno++;
10429 needprompt = doprompt;
10430 RETURN(TNL);
10431 case PEOF:
10432 RETURN(TEOF);
10433 case '&':
10434 if (pgetc() == '&')
10435 RETURN(TAND);
10436 pungetc();
10437 RETURN(TBACKGND);
10438 case '|':
10439 if (pgetc() == '|')
10440 RETURN(TOR);
10441 pungetc();
10442 RETURN(TPIPE);
10443 case ';':
10444 if (pgetc() == ';')
10445 RETURN(TENDCASE);
10446 pungetc();
10447 RETURN(TSEMI);
10448 case '(':
10449 RETURN(TLP);
10450 case ')':
10451 RETURN(TRP);
10452 default:
10453 goto breakloop;
10454 }
10455 }
10456breakloop:
10457 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10458#undef RETURN
10459}
10460#endif
10461
10462
10463/*
10464 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10465 * is not NULL, read a here document. In the latter case, eofmark is the
10466 * word which marks the end of the document and striptabs is true if
10467 * leading tabs should be stripped from the document. The argument firstc
10468 * is the first character of the input token or document.
10469 *
10470 * Because C does not have internal subroutines, I have simulated them
10471 * using goto's to implement the subroutine linkage. The following macros
10472 * will run code that appears at the end of readtoken1.
10473 */
10474
10475#define CHECKEND() {goto checkend; checkend_return:;}
10476#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10477#define PARSESUB() {goto parsesub; parsesub_return:;}
10478#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10479#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10480#define PARSEARITH() {goto parsearith; parsearith_return:;}
10481
10482static int
10483readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10484{
10485 int c = firstc;
10486 char *out;
10487 int len;
10488 char line[EOFMARKLEN + 1];
10489 struct nodelist *bqlist;
10490 int quotef;
10491 int dblquote;
10492 int varnest; /* levels of variables expansion */
10493 int arinest; /* levels of arithmetic expansion */
10494 int parenlevel; /* levels of parens in arithmetic */
10495 int dqvarnest; /* levels of variables expansion within double quotes */
10496 int oldstyle;
10497 int prevsyntax; /* syntax before arithmetic */
10498#if __GNUC__
10499 /* Avoid longjmp clobbering */
10500 (void) &out;
10501 (void) &quotef;
10502 (void) &dblquote;
10503 (void) &varnest;
10504 (void) &arinest;
10505 (void) &parenlevel;
10506 (void) &dqvarnest;
10507 (void) &oldstyle;
10508 (void) &prevsyntax;
10509 (void) &syntax;
10510#endif
10511
10512 startlinno = plinno;
10513 dblquote = 0;
10514 if (syntax == DQSYNTAX)
10515 dblquote = 1;
10516 quotef = 0;
10517 bqlist = NULL;
10518 varnest = 0;
10519 arinest = 0;
10520 parenlevel = 0;
10521 dqvarnest = 0;
10522
10523 STARTSTACKSTR(out);
10524 loop: { /* for each line, until end of word */
10525 CHECKEND(); /* set c to PEOF if at end of here document */
10526 for (;;) { /* until end of line or end of word */
10527 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
10528 switch(SIT(c,syntax)) {
10529 case CNL: /* '\n' */
10530 if (syntax == BASESYNTAX)
10531 goto endword; /* exit outer loop */
10532 USTPUTC(c, out);
10533 plinno++;
10534 if (doprompt)
10535 setprompt(2);
10536 else
10537 setprompt(0);
10538 c = pgetc();
10539 goto loop; /* continue outer loop */
10540 case CWORD:
10541 USTPUTC(c, out);
10542 break;
10543 case CCTL:
10544 if ((eofmark == NULL || dblquote) &&
10545 dqvarnest == 0)
10546 USTPUTC(CTLESC, out);
10547 USTPUTC(c, out);
10548 break;
10549 case CBACK: /* backslash */
10550 c = pgetc2();
10551 if (c == PEOF) {
10552 USTPUTC('\\', out);
10553 pungetc();
10554 } else if (c == '\n') {
10555 if (doprompt)
10556 setprompt(2);
10557 else
10558 setprompt(0);
10559 } else {
10560 if (dblquote && c != '\\' && c != '`' && c != '$'
10561 && (c != '"' || eofmark != NULL))
10562 USTPUTC('\\', out);
10563 if (SIT(c,SQSYNTAX) == CCTL)
10564 USTPUTC(CTLESC, out);
10565 else if (eofmark == NULL)
10566 USTPUTC(CTLQUOTEMARK, out);
10567 USTPUTC(c, out);
10568 quotef++;
10569 }
10570 break;
10571 case CSQUOTE:
10572 if (eofmark == NULL)
10573 USTPUTC(CTLQUOTEMARK, out);
10574 syntax = SQSYNTAX;
10575 break;
10576 case CDQUOTE:
10577 if (eofmark == NULL)
10578 USTPUTC(CTLQUOTEMARK, out);
10579 syntax = DQSYNTAX;
10580 dblquote = 1;
10581 break;
10582 case CENDQUOTE:
10583 if (eofmark != NULL && arinest == 0 &&
10584 varnest == 0) {
10585 USTPUTC(c, out);
10586 } else {
10587 if (arinest) {
10588 syntax = ARISYNTAX;
10589 dblquote = 0;
10590 } else if (eofmark == NULL &&
10591 dqvarnest == 0) {
10592 syntax = BASESYNTAX;
10593 dblquote = 0;
10594 }
10595 quotef++;
10596 }
10597 break;
10598 case CVAR: /* '$' */
10599 PARSESUB(); /* parse substitution */
10600 break;
10601 case CENDVAR: /* '}' */
10602 if (varnest > 0) {
10603 varnest--;
10604 if (dqvarnest > 0) {
10605 dqvarnest--;
10606 }
10607 USTPUTC(CTLENDVAR, out);
10608 } else {
10609 USTPUTC(c, out);
10610 }
10611 break;
10612#ifdef ASH_MATH_SUPPORT
10613 case CLP: /* '(' in arithmetic */
10614 parenlevel++;
10615 USTPUTC(c, out);
10616 break;
10617 case CRP: /* ')' in arithmetic */
10618 if (parenlevel > 0) {
10619 USTPUTC(c, out);
10620 --parenlevel;
10621 } else {
10622 if (pgetc() == ')') {
10623 if (--arinest == 0) {
10624 USTPUTC(CTLENDARI, out);
10625 syntax = prevsyntax;
10626 if (syntax == DQSYNTAX)
10627 dblquote = 1;
10628 else
10629 dblquote = 0;
10630 } else
10631 USTPUTC(')', out);
10632 } else {
10633 /*
10634 * unbalanced parens
10635 * (don't 2nd guess - no error)
10636 */
10637 pungetc();
10638 USTPUTC(')', out);
10639 }
10640 }
10641 break;
10642#endif
10643 case CBQUOTE: /* '`' */
10644 PARSEBACKQOLD();
10645 break;
10646 case CENDFILE:
10647 goto endword; /* exit outer loop */
10648 case CIGN:
10649 break;
10650 default:
10651 if (varnest == 0)
10652 goto endword; /* exit outer loop */
10653#ifdef ASH_ALIAS
10654 if (c != PEOA)
10655#endif
10656 USTPUTC(c, out);
10657
10658 }
10659 c = pgetc_macro();
10660 }
10661 }
10662endword:
10663 if (syntax == ARISYNTAX)
10664 synerror("Missing '))'");
10665 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10666 synerror("Unterminated quoted string");
10667 if (varnest != 0) {
10668 startlinno = plinno;
10669 synerror("Missing '}'");
10670 }
10671 USTPUTC('\0', out);
10672 len = out - stackblock();
10673 out = stackblock();
10674 if (eofmark == NULL) {
10675 if ((c == '>' || c == '<')
10676 && quotef == 0
10677 && len <= 2
10678 && (*out == '\0' || is_digit(*out))) {
10679 PARSEREDIR();
10680 return lasttoken = TREDIR;
10681 } else {
10682 pungetc();
10683 }
10684 }
10685 quoteflag = quotef;
10686 backquotelist = bqlist;
10687 grabstackblock(len);
10688 wordtext = out;
10689 return lasttoken = TWORD;
10690/* end of readtoken routine */
10691
10692
10693
10694/*
10695 * Check to see whether we are at the end of the here document. When this
10696 * is called, c is set to the first character of the next input line. If
10697 * we are at the end of the here document, this routine sets the c to PEOF.
10698 */
10699
10700checkend: {
10701 if (eofmark) {
10702#ifdef ASH_ALIAS
10703 if (c == PEOA) {
10704 c = pgetc2();
10705 }
10706#endif
10707 if (striptabs) {
10708 while (c == '\t') {
10709 c = pgetc2();
10710 }
10711 }
10712 if (c == *eofmark) {
10713 if (pfgets(line, sizeof line) != NULL) {
10714 const char *p, *q;
10715
10716 p = line;
10717 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10718 if (*p == '\n' && *q == '\0') {
10719 c = PEOF;
10720 plinno++;
10721 needprompt = doprompt;
10722 } else {
10723 pushstring(line, strlen(line), NULL);
10724 }
10725 }
10726 }
10727 }
10728 goto checkend_return;
10729}
10730
10731
10732/*
10733 * Parse a redirection operator. The variable "out" points to a string
10734 * specifying the fd to be redirected. The variable "c" contains the
10735 * first character of the redirection operator.
10736 */
10737
10738parseredir: {
10739 char fd = *out;
10740 union node *np;
10741
10742 np = (union node *)stalloc(sizeof (struct nfile));
10743 if (c == '>') {
10744 np->nfile.fd = 1;
10745 c = pgetc();
10746 if (c == '>')
10747 np->type = NAPPEND;
10748 else if (c == '&')
10749 np->type = NTOFD;
10750 else if (c == '|')
10751 np->type = NTOOV;
10752 else {
10753 np->type = NTO;
10754 pungetc();
10755 }
10756 } else { /* c == '<' */
10757 np->nfile.fd = 0;
10758 switch (c = pgetc()) {
10759 case '<':
10760 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10761 np = (union node *)stalloc(sizeof (struct nhere));
10762 np->nfile.fd = 0;
10763 }
10764 np->type = NHERE;
10765 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10766 heredoc->here = np;
10767 if ((c = pgetc()) == '-') {
10768 heredoc->striptabs = 1;
10769 } else {
10770 heredoc->striptabs = 0;
10771 pungetc();
10772 }
10773 break;
10774
10775 case '&':
10776 np->type = NFROMFD;
10777 break;
10778
10779 case '>':
10780 np->type = NFROMTO;
10781 break;
10782
10783 default:
10784 np->type = NFROM;
10785 pungetc();
10786 break;
10787 }
10788 }
10789 if (fd != '\0')
10790 np->nfile.fd = digit_val(fd);
10791 redirnode = np;
10792 goto parseredir_return;
10793}
10794
10795
10796/*
10797 * Parse a substitution. At this point, we have read the dollar sign
10798 * and nothing else.
10799 */
10800
10801parsesub: {
10802 int subtype;
10803 int typeloc;
10804 int flags;
10805 char *p;
10806 static const char types[] = "}-+?=";
10807
10808 c = pgetc();
10809 if (
10810 c <= PEOA ||
10811 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10812 ) {
10813 USTPUTC('$', out);
10814 pungetc();
10815 } else if (c == '(') { /* $(command) or $((arith)) */
10816 if (pgetc() == '(') {
10817 PARSEARITH();
10818 } else {
10819 pungetc();
10820 PARSEBACKQNEW();
10821 }
10822 } else {
10823 USTPUTC(CTLVAR, out);
10824 typeloc = out - stackblock();
10825 USTPUTC(VSNORMAL, out);
10826 subtype = VSNORMAL;
10827 if (c == '{') {
10828 c = pgetc();
10829 if (c == '#') {
10830 if ((c = pgetc()) == '}')
10831 c = '#';
10832 else
10833 subtype = VSLENGTH;
10834 }
10835 else
10836 subtype = 0;
10837 }
10838 if (c > PEOA && is_name(c)) {
10839 do {
10840 STPUTC(c, out);
10841 c = pgetc();
10842 } while (c > PEOA && is_in_name(c));
10843 } else if (is_digit(c)) {
10844 do {
10845 USTPUTC(c, out);
10846 c = pgetc();
10847 } while (is_digit(c));
10848 }
10849 else if (is_special(c)) {
10850 USTPUTC(c, out);
10851 c = pgetc();
10852 }
10853 else
10854badsub: synerror("Bad substitution");
10855
10856 STPUTC('=', out);
10857 flags = 0;
10858 if (subtype == 0) {
10859 switch (c) {
10860 case ':':
10861 flags = VSNUL;
10862 c = pgetc();
10863 /*FALLTHROUGH*/
10864 default:
10865 p = strchr(types, c);
10866 if (p == NULL)
10867 goto badsub;
10868 subtype = p - types + VSNORMAL;
10869 break;
10870 case '%':
10871 case '#':
10872 {
10873 int cc = c;
10874 subtype = c == '#' ? VSTRIMLEFT :
10875 VSTRIMRIGHT;
10876 c = pgetc();
10877 if (c == cc)
10878 subtype++;
10879 else
10880 pungetc();
10881 break;
10882 }
10883 }
10884 } else {
10885 pungetc();
10886 }
10887 if (dblquote || arinest)
10888 flags |= VSQUOTE;
10889 *(stackblock() + typeloc) = subtype | flags;
10890 if (subtype != VSNORMAL) {
10891 varnest++;
10892 if (dblquote) {
10893 dqvarnest++;
10894 }
10895 }
10896 }
10897 goto parsesub_return;
10898}
10899
10900
10901/*
10902 * Called to parse command substitutions. Newstyle is set if the command
10903 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10904 * list of commands (passed by reference), and savelen is the number of
10905 * characters on the top of the stack which must be preserved.
10906 */
10907
10908parsebackq: {
10909 struct nodelist **nlpp;
10910 int savepbq;
10911 union node *n;
10912 char *volatile str;
10913 struct jmploc jmploc;
10914 struct jmploc *volatile savehandler;
10915 int savelen;
10916 int saveprompt;
10917#ifdef __GNUC__
10918 (void) &saveprompt;
10919#endif
10920
10921 savepbq = parsebackquote;
10922 if (setjmp(jmploc.loc)) {
10923 if (str)
10924 ckfree(str);
10925 parsebackquote = 0;
10926 handler = savehandler;
10927 longjmp(handler->loc, 1);
10928 }
10929 INTOFF;
10930 str = NULL;
10931 savelen = out - stackblock();
10932 if (savelen > 0) {
10933 str = ckmalloc(savelen);
10934 memcpy(str, stackblock(), savelen);
10935 }
10936 savehandler = handler;
10937 handler = &jmploc;
10938 INTON;
10939 if (oldstyle) {
10940 /* We must read until the closing backquote, giving special
10941 treatment to some slashes, and then push the string and
10942 reread it as input, interpreting it normally. */
10943 char *pout;
10944 int pc;
10945 int psavelen;
10946 char *pstr;
10947
10948
10949 STARTSTACKSTR(pout);
10950 for (;;) {
10951 if (needprompt) {
10952 setprompt(2);
10953 needprompt = 0;
10954 }
10955 switch (pc = pgetc()) {
10956 case '`':
10957 goto done;
10958
10959 case '\\':
10960 if ((pc = pgetc()) == '\n') {
10961 plinno++;
10962 if (doprompt)
10963 setprompt(2);
10964 else
10965 setprompt(0);
10966 /*
10967 * If eating a newline, avoid putting
10968 * the newline into the new character
10969 * stream (via the STPUTC after the
10970 * switch).
10971 */
10972 continue;
10973 }
10974 if (pc != '\\' && pc != '`' && pc != '$'
10975 && (!dblquote || pc != '"'))
10976 STPUTC('\\', pout);
10977 if (pc > PEOA) {
10978 break;
10979 }
10980 /* fall through */
10981
10982 case PEOF:
10983#ifdef ASH_ALIAS
10984 case PEOA:
10985#endif
10986 startlinno = plinno;
10987 synerror("EOF in backquote substitution");
10988
10989 case '\n':
10990 plinno++;
10991 needprompt = doprompt;
10992 break;
10993
10994 default:
10995 break;
10996 }
10997 STPUTC(pc, pout);
10998 }
10999done:
11000 STPUTC('\0', pout);
11001 psavelen = pout - stackblock();
11002 if (psavelen > 0) {
11003 pstr = grabstackstr(pout);
11004 setinputstring(pstr);
11005 }
11006 }
11007 nlpp = &bqlist;
11008 while (*nlpp)
11009 nlpp = &(*nlpp)->next;
11010 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
11011 (*nlpp)->next = NULL;
11012 parsebackquote = oldstyle;
11013
11014 if (oldstyle) {
11015 saveprompt = doprompt;
11016 doprompt = 0;
11017 }
11018
11019 n = list(0);
11020
11021 if (oldstyle)
11022 doprompt = saveprompt;
11023 else {
11024 if (readtoken() != TRP)
11025 synexpect(TRP);
11026 }
11027
11028 (*nlpp)->n = n;
11029 if (oldstyle) {
11030 /*
11031 * Start reading from old file again, ignoring any pushed back
11032 * tokens left from the backquote parsing
11033 */
11034 popfile();
11035 tokpushback = 0;
11036 }
11037 while (stackblocksize() <= savelen)
11038 growstackblock();
11039 STARTSTACKSTR(out);
11040 if (str) {
11041 memcpy(out, str, savelen);
11042 STADJUST(savelen, out);
11043 INTOFF;
11044 ckfree(str);
11045 str = NULL;
11046 INTON;
11047 }
11048 parsebackquote = savepbq;
11049 handler = savehandler;
11050 if (arinest || dblquote)
11051 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11052 else
11053 USTPUTC(CTLBACKQ, out);
11054 if (oldstyle)
11055 goto parsebackq_oldreturn;
11056 else
11057 goto parsebackq_newreturn;
11058}
11059
11060/*
11061 * Parse an arithmetic expansion (indicate start of one and set state)
11062 */
11063parsearith: {
11064
11065 if (++arinest == 1) {
11066 prevsyntax = syntax;
11067 syntax = ARISYNTAX;
11068 USTPUTC(CTLARI, out);
11069 if (dblquote)
11070 USTPUTC('"',out);
11071 else
11072 USTPUTC(' ',out);
11073 } else {
11074 /*
11075 * we collapse embedded arithmetic expansion to
11076 * parenthesis, which should be equivalent
11077 */
11078 USTPUTC('(', out);
11079 }
11080 goto parsearith_return;
11081}
11082
11083} /* end of readtoken */
11084
11085
11086/*
11087 * Returns true if the text contains nothing to expand (no dollar signs
11088 * or backquotes).
11089 */
11090
11091static int
11092noexpand(text)
11093 char *text;
11094 {
11095 char *p;
11096 char c;
11097
11098 p = text;
11099 while ((c = *p++) != '\0') {
11100 if (c == CTLQUOTEMARK)
11101 continue;
11102 if (c == CTLESC)
11103 p++;
11104 else if (SIT(c,BASESYNTAX) == CCTL)
11105 return 0;
11106 }
11107 return 1;
11108}
11109
11110
11111/*
11112 * Return true if the argument is a legal variable name (a letter or
11113 * underscore followed by zero or more letters, underscores, and digits).
11114 */
11115
11116static int
11117goodname(const char *name)
11118{
11119 const char *p;
11120
11121 p = name;
11122 if (! is_name(*p))
11123 return 0;
11124 while (*++p) {
11125 if (! is_in_name(*p))
11126 return 0;
11127 }
11128 return 1;
11129}
11130
11131
11132/*
11133 * Called when an unexpected token is read during the parse. The argument
11134 * is the token that is expected, or -1 if more than one type of token can
11135 * occur at this point.
11136 */
11137
11138static void
11139synexpect(token)
11140 int token;
11141{
11142 char msg[64];
11143 int l;
11144
11145 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11146 if (token >= 0)
11147 sprintf(msg+l, " (expecting %s)", tokname(token));
11148 synerror(msg);
11149 /* NOTREACHED */
11150}
11151
11152
11153static void
11154synerror(const char *msg)
11155{
11156 if (commandname)
11157 out2fmt("%s: %d: ", commandname, startlinno);
11158 out2fmt("Syntax error: %s\n", msg);
11159 error((char *)NULL);
11160 /* NOTREACHED */
11161}
11162
11163
11164/*
11165 * called by editline -- any expansions to the prompt
11166 * should be added here.
11167 */
11168static void
11169setprompt(int whichprompt)
11170{
11171 char *prompt;
11172 switch (whichprompt) {
11173 case 1:
11174 prompt = ps1val();
11175 break;
11176 case 2:
11177 prompt = ps2val();
11178 break;
11179 default: /* 0 */
11180 prompt = "";
11181 }
11182 putprompt(prompt);
11183}
11184
11185
11186/*
11187 * Code for dealing with input/output redirection.
11188 */
11189
11190#define EMPTY -2 /* marks an unused slot in redirtab */
11191#ifndef PIPE_BUF
11192# define PIPESIZE 4096 /* amount of buffering in a pipe */
11193#else
11194# define PIPESIZE PIPE_BUF
11195#endif
11196
11197
11198/*
11199 * Open a file in noclobber mode.
11200 * The code was copied from bash.
11201 */
11202static inline int
11203noclobberopen(const char *fname)
11204{
11205 int r, fd;
11206 struct stat finfo, finfo2;
11207
11208 /*
11209 * If the file exists and is a regular file, return an error
11210 * immediately.
11211 */
11212 r = stat(fname, &finfo);
11213 if (r == 0 && S_ISREG(finfo.st_mode)) {
11214 errno = EEXIST;
11215 return -1;
11216 }
11217
11218 /*
11219 * If the file was not present (r != 0), make sure we open it
11220 * exclusively so that if it is created before we open it, our open
11221 * will fail. Make sure that we do not truncate an existing file.
11222 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11223 * file was not a regular file, we leave O_EXCL off.
11224 */
11225 if (r != 0)
11226 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11227 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11228
11229 /* If the open failed, return the file descriptor right away. */
11230 if (fd < 0)
11231 return fd;
11232
11233 /*
11234 * OK, the open succeeded, but the file may have been changed from a
11235 * non-regular file to a regular file between the stat and the open.
11236 * We are assuming that the O_EXCL open handles the case where FILENAME
11237 * did not exist and is symlinked to an existing file between the stat
11238 * and open.
11239 */
11240
11241 /*
11242 * If we can open it and fstat the file descriptor, and neither check
11243 * revealed that it was a regular file, and the file has not been
11244 * replaced, return the file descriptor.
11245 */
11246 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11247 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11248 return fd;
11249
11250 /* The file has been replaced. badness. */
11251 close(fd);
11252 errno = EEXIST;
11253 return -1;
11254}
11255
11256/*
11257 * Handle here documents. Normally we fork off a process to write the
11258 * data to a pipe. If the document is short, we can stuff the data in
11259 * the pipe without forking.
11260 */
11261
11262static inline int
11263openhere(const union node *redir)
11264{
11265 int pip[2];
11266 int len = 0;
11267
11268 if (pipe(pip) < 0)
11269 error("Pipe call failed");
11270 if (redir->type == NHERE) {
11271 len = strlen(redir->nhere.doc->narg.text);
11272 if (len <= PIPESIZE) {
11273 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11274 goto out;
11275 }
11276 }
11277 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11278 close(pip[0]);
11279 signal(SIGINT, SIG_IGN);
11280 signal(SIGQUIT, SIG_IGN);
11281 signal(SIGHUP, SIG_IGN);
11282#ifdef SIGTSTP
11283 signal(SIGTSTP, SIG_IGN);
11284#endif
11285 signal(SIGPIPE, SIG_DFL);
11286 if (redir->type == NHERE)
11287 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11288 else
11289 expandhere(redir->nhere.doc, pip[1]);
11290 _exit(0);
11291 }
11292out:
11293 close(pip[1]);
11294 return pip[0];
11295}
11296
11297
11298static inline int
11299openredirect(const union node *redir)
11300{
11301 char *fname;
11302 int f;
11303
11304 switch (redir->nfile.type) {
11305 case NFROM:
11306 fname = redir->nfile.expfname;
11307 if ((f = open(fname, O_RDONLY)) < 0)
11308 goto eopen;
11309 break;
11310 case NFROMTO:
11311 fname = redir->nfile.expfname;
11312 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11313 goto ecreate;
11314 break;
11315 case NTO:
11316 /* Take care of noclobber mode. */
11317 if (Cflag) {
11318 fname = redir->nfile.expfname;
11319 if ((f = noclobberopen(fname)) < 0)
11320 goto ecreate;
11321 break;
11322 }
11323 case NTOOV:
11324 fname = redir->nfile.expfname;
11325#ifdef O_CREAT
11326 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11327 goto ecreate;
11328#else
11329 if ((f = creat(fname, 0666)) < 0)
11330 goto ecreate;
11331#endif
11332 break;
11333 case NAPPEND:
11334 fname = redir->nfile.expfname;
11335#ifdef O_APPEND
11336 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11337 goto ecreate;
11338#else
11339 if ((f = open(fname, O_WRONLY)) < 0
11340 && (f = creat(fname, 0666)) < 0)
11341 goto ecreate;
11342 lseek(f, (off_t)0, 2);
11343#endif
11344 break;
11345 default:
11346#ifdef DEBUG
11347 abort();
11348#endif
11349 /* Fall through to eliminate warning. */
11350 case NTOFD:
11351 case NFROMFD:
11352 f = -1;
11353 break;
11354 case NHERE:
11355 case NXHERE:
11356 f = openhere(redir);
11357 break;
11358 }
11359
11360 return f;
11361ecreate:
11362 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11363eopen:
11364 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11365}
11366
11367
11368/*
11369 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11370 * old file descriptors are stashed away so that the redirection can be
11371 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11372 * standard output, and the standard error if it becomes a duplicate of
11373 * stdout.
11374 */
11375
11376static void
11377redirect(union node *redir, int flags)
11378{
11379 union node *n;
11380 struct redirtab *sv = NULL;
11381 int i;
11382 int fd;
11383 int newfd;
11384 int try;
11385 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11386
11387 if (flags & REDIR_PUSH) {
11388 sv = ckmalloc(sizeof (struct redirtab));
11389 for (i = 0 ; i < 10 ; i++)
11390 sv->renamed[i] = EMPTY;
11391 sv->next = redirlist;
11392 redirlist = sv;
11393 }
11394 for (n = redir ; n ; n = n->nfile.next) {
11395 fd = n->nfile.fd;
11396 try = 0;
11397 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11398 n->ndup.dupfd == fd)
11399 continue; /* redirect from/to same file descriptor */
11400
11401 INTOFF;
11402 newfd = openredirect(n);
11403 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11404 if (newfd == fd) {
11405 try++;
11406 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11407 switch (errno) {
11408 case EBADF:
11409 if (!try) {
11410 dupredirect(n, newfd, fd1dup);
11411 try++;
11412 break;
11413 }
11414 /* FALLTHROUGH*/
11415 default:
11416 if (newfd >= 0) {
11417 close(newfd);
11418 }
11419 INTON;
11420 error("%d: %m", fd);
11421 /* NOTREACHED */
11422 }
11423 }
11424 if (!try) {
11425 close(fd);
11426 if (flags & REDIR_PUSH) {
11427 sv->renamed[fd] = i;
11428 }
11429 }
11430 } else if (fd != newfd) {
11431 close(fd);
11432 }
11433 if (fd == 0)
11434 fd0_redirected++;
11435 if (!try)
11436 dupredirect(n, newfd, fd1dup);
11437 INTON;
11438 }
11439}
11440
11441
11442static void
11443dupredirect(const union node *redir, int f, int fd1dup)
11444{
11445 int fd = redir->nfile.fd;
11446
11447 if(fd==1)
11448 fd1dup = 0;
11449 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11450 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11451 if (redir->ndup.dupfd!=1 || fd1dup!=1)
11452 dup_as_newfd(redir->ndup.dupfd, fd);
11453 }
11454 return;
11455 }
11456
11457 if (f != fd) {
11458 dup_as_newfd(f, fd);
11459 close(f);
11460 }
11461 return;
11462}
11463
11464
11465
11466/*
11467 * Undo the effects of the last redirection.
11468 */
11469
11470static void
11471popredir(void)
11472{
11473 struct redirtab *rp = redirlist;
11474 int i;
11475
11476 INTOFF;
11477 for (i = 0 ; i < 10 ; i++) {
11478 if (rp->renamed[i] != EMPTY) {
11479 if (i == 0)
11480 fd0_redirected--;
11481 close(i);
11482 if (rp->renamed[i] >= 0) {
11483 dup_as_newfd(rp->renamed[i], i);
11484 close(rp->renamed[i]);
11485 }
11486 }
11487 }
11488 redirlist = rp->next;
11489 ckfree(rp);
11490 INTON;
11491}
11492
11493/*
11494 * Discard all saved file descriptors.
11495 */
11496
11497static void
11498clearredir(void) {
11499 struct redirtab *rp;
11500 int i;
11501
11502 for (rp = redirlist ; rp ; rp = rp->next) {
11503 for (i = 0 ; i < 10 ; i++) {
11504 if (rp->renamed[i] >= 0) {
11505 close(rp->renamed[i]);
11506 }
11507 rp->renamed[i] = EMPTY;
11508 }
11509 }
11510}
11511
11512
11513/*
11514 * Copy a file descriptor to be >= to. Returns -1
11515 * if the source file descriptor is closed, EMPTY if there are no unused
11516 * file descriptors left.
11517 */
11518
11519static int
11520dup_as_newfd(from, to)
11521 int from;
11522 int to;
11523{
11524 int newfd;
11525
11526 newfd = fcntl(from, F_DUPFD, to);
11527 if (newfd < 0) {
11528 if (errno == EMFILE)
11529 return EMPTY;
11530 else
11531 error("%d: %m", from);
11532 }
11533 return newfd;
11534}
11535
11536#ifdef DEBUG
11537static void shtree (union node *, int, char *, FILE*);
11538static void shcmd (union node *, FILE *);
11539static void sharg (union node *, FILE *);
11540static void indent (int, char *, FILE *);
11541static void trstring (char *);
11542
11543
11544static void
11545showtree(n)
11546 union node *n;
11547{
11548 trputs("showtree called\n");
11549 shtree(n, 1, NULL, stdout);
11550}
11551
11552
11553static void
11554shtree(n, ind, pfx, fp)
11555 union node *n;
11556 int ind;
11557 char *pfx;
11558 FILE *fp;
11559{
11560 struct nodelist *lp;
11561 const char *s;
11562
11563 if (n == NULL)
11564 return;
11565
11566 indent(ind, pfx, fp);
11567 switch(n->type) {
11568 case NSEMI:
11569 s = "; ";
11570 goto binop;
11571 case NAND:
11572 s = " && ";
11573 goto binop;
11574 case NOR:
11575 s = " || ";
11576binop:
11577 shtree(n->nbinary.ch1, ind, NULL, fp);
11578 /* if (ind < 0) */
11579 fputs(s, fp);
11580 shtree(n->nbinary.ch2, ind, NULL, fp);
11581 break;
11582 case NCMD:
11583 shcmd(n, fp);
11584 if (ind >= 0)
11585 putc('\n', fp);
11586 break;
11587 case NPIPE:
11588 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11589 shcmd(lp->n, fp);
11590 if (lp->next)
11591 fputs(" | ", fp);
11592 }
11593 if (n->npipe.backgnd)
11594 fputs(" &", fp);
11595 if (ind >= 0)
11596 putc('\n', fp);
11597 break;
11598 default:
11599 fprintf(fp, "<node type %d>", n->type);
11600 if (ind >= 0)
11601 putc('\n', fp);
11602 break;
11603 }
11604}
11605
11606
11607
11608static void
11609shcmd(cmd, fp)
11610 union node *cmd;
11611 FILE *fp;
11612{
11613 union node *np;
11614 int first;
11615 const char *s;
11616 int dftfd;
11617
11618 first = 1;
11619 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11620 if (! first)
11621 putchar(' ');
11622 sharg(np, fp);
11623 first = 0;
11624 }
11625 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11626 if (! first)
11627 putchar(' ');
11628#if 1
11629 s = "*error*";
11630 dftfd = 0;
11631 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11632 s = redir_strings[np->nfile.type - NTO];
11633 if (*s == '>') {
11634 dftfd = 1;
11635 }
11636 }
11637#else
11638 switch (np->nfile.type) {
11639 case NTO: s = ">"; dftfd = 1; break;
11640 case NAPPEND: s = ">>"; dftfd = 1; break;
11641 case NTOFD: s = ">&"; dftfd = 1; break;
11642 case NTOOV: s = ">|"; dftfd = 1; break;
11643 case NFROM: s = "<"; dftfd = 0; break;
11644 case NFROMFD: s = "<&"; dftfd = 0; break;
11645 case NFROMTO: s = "<>"; dftfd = 0; break;
11646 default: s = "*error*"; dftfd = 0; break;
11647 }
11648#endif
11649 if (np->nfile.fd != dftfd)
11650 fprintf(fp, "%d", np->nfile.fd);
11651 fputs(s, fp);
11652 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11653 fprintf(fp, "%d", np->ndup.dupfd);
11654 } else {
11655 sharg(np->nfile.fname, fp);
11656 }
11657 first = 0;
11658 }
11659}
11660
11661
11662
11663static void
11664sharg(arg, fp)
11665 union node *arg;
11666 FILE *fp;
11667 {
11668 char *p;
11669 struct nodelist *bqlist;
11670 int subtype;
11671
11672 if (arg->type != NARG) {
11673 printf("<node type %d>\n", arg->type);
11674 fflush(stdout);
11675 abort();
11676 }
11677 bqlist = arg->narg.backquote;
11678 for (p = arg->narg.text ; *p ; p++) {
11679 switch (*p) {
11680 case CTLESC:
11681 putc(*++p, fp);
11682 break;
11683 case CTLVAR:
11684 putc('$', fp);
11685 putc('{', fp);
11686 subtype = *++p;
11687 if (subtype == VSLENGTH)
11688 putc('#', fp);
11689
11690 while (*p != '=')
11691 putc(*p++, fp);
11692
11693 if (subtype & VSNUL)
11694 putc(':', fp);
11695
11696 switch (subtype & VSTYPE) {
11697 case VSNORMAL:
11698 putc('}', fp);
11699 break;
11700 case VSMINUS:
11701 putc('-', fp);
11702 break;
11703 case VSPLUS:
11704 putc('+', fp);
11705 break;
11706 case VSQUESTION:
11707 putc('?', fp);
11708 break;
11709 case VSASSIGN:
11710 putc('=', fp);
11711 break;
11712 case VSTRIMLEFT:
11713 putc('#', fp);
11714 break;
11715 case VSTRIMLEFTMAX:
11716 putc('#', fp);
11717 putc('#', fp);
11718 break;
11719 case VSTRIMRIGHT:
11720 putc('%', fp);
11721 break;
11722 case VSTRIMRIGHTMAX:
11723 putc('%', fp);
11724 putc('%', fp);
11725 break;
11726 case VSLENGTH:
11727 break;
11728 default:
11729 printf("<subtype %d>", subtype);
11730 }
11731 break;
11732 case CTLENDVAR:
11733 putc('}', fp);
11734 break;
11735 case CTLBACKQ:
11736 case CTLBACKQ|CTLQUOTE:
11737 putc('$', fp);
11738 putc('(', fp);
11739 shtree(bqlist->n, -1, NULL, fp);
11740 putc(')', fp);
11741 break;
11742 default:
11743 putc(*p, fp);
11744 break;
11745 }
11746 }
11747}
11748
11749
11750static void
11751indent(amount, pfx, fp)
11752 int amount;
11753 char *pfx;
11754 FILE *fp;
11755{
11756 int i;
11757
11758 for (i = 0 ; i < amount ; i++) {
11759 if (pfx && i == amount - 1)
11760 fputs(pfx, fp);
11761 putc('\t', fp);
11762 }
11763}
11764#endif
11765
11766
11767
11768/*
11769 * Debugging stuff.
11770 */
11771
11772
11773#ifdef DEBUG
11774FILE *tracefile;
11775
11776#if DEBUG == 2
11777static int debug = 1;
11778#else
11779static int debug = 0;
11780#endif
11781
11782
11783static void
11784trputc(c)
11785 int c;
11786{
11787 if (tracefile == NULL)
11788 return;
11789 putc(c, tracefile);
11790 if (c == '\n')
11791 fflush(tracefile);
11792}
11793
11794static void
11795trace(const char *fmt, ...)
11796{
11797 va_list va;
11798 va_start(va, fmt);
11799 if (tracefile != NULL) {
11800 (void) vfprintf(tracefile, fmt, va);
11801 if (strchr(fmt, '\n'))
11802 (void) fflush(tracefile);
11803 }
11804 va_end(va);
11805}
11806
11807
11808static void
11809trputs(s)
11810 const char *s;
11811{
11812 if (tracefile == NULL)
11813 return;
11814 fputs(s, tracefile);
11815 if (strchr(s, '\n'))
11816 fflush(tracefile);
11817}
11818
11819
11820static void
11821trstring(s)
11822 char *s;
11823{
11824 char *p;
11825 char c;
11826
11827 if (tracefile == NULL)
11828 return;
11829 putc('"', tracefile);
11830 for (p = s ; *p ; p++) {
11831 switch (*p) {
11832 case '\n': c = 'n'; goto backslash;
11833 case '\t': c = 't'; goto backslash;
11834 case '\r': c = 'r'; goto backslash;
11835 case '"': c = '"'; goto backslash;
11836 case '\\': c = '\\'; goto backslash;
11837 case CTLESC: c = 'e'; goto backslash;
11838 case CTLVAR: c = 'v'; goto backslash;
11839 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11840 case CTLBACKQ: c = 'q'; goto backslash;
11841 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11842backslash: putc('\\', tracefile);
11843 putc(c, tracefile);
11844 break;
11845 default:
11846 if (*p >= ' ' && *p <= '~')
11847 putc(*p, tracefile);
11848 else {
11849 putc('\\', tracefile);
11850 putc(*p >> 6 & 03, tracefile);
11851 putc(*p >> 3 & 07, tracefile);
11852 putc(*p & 07, tracefile);
11853 }
11854 break;
11855 }
11856 }
11857 putc('"', tracefile);
11858}
11859
11860
11861static void
11862trargs(ap)
11863 char **ap;
11864{
11865 if (tracefile == NULL)
11866 return;
11867 while (*ap) {
11868 trstring(*ap++);
11869 if (*ap)
11870 putc(' ', tracefile);
11871 else
11872 putc('\n', tracefile);
11873 }
11874 fflush(tracefile);
11875}
11876
11877
11878static void
11879opentrace() {
11880 char s[100];
11881#ifdef O_APPEND
11882 int flags;
11883#endif
11884
11885 if (!debug)
11886 return;
11887#ifdef not_this_way
11888 {
11889 char *p;
11890 if ((p = getenv("HOME")) == NULL) {
11891 if (geteuid() == 0)
11892 p = "/";
11893 else
11894 p = "/tmp";
11895 }
11896 strcpy(s, p);
11897 strcat(s, "/trace");
11898 }
11899#else
11900 strcpy(s, "./trace");
11901#endif /* not_this_way */
11902 if ((tracefile = fopen(s, "a")) == NULL) {
11903 fprintf(stderr, "Can't open %s\n", s);
11904 return;
11905 }
11906#ifdef O_APPEND
11907 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11908 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11909#endif
11910 fputs("\nTracing started.\n", tracefile);
11911 fflush(tracefile);
11912}
11913#endif /* DEBUG */
11914
11915
11916/*
11917 * The trap builtin.
11918 */
11919
11920static int
11921trapcmd(argc, argv)
11922 int argc;
11923 char **argv;
11924{
11925 char *action;
11926 char **ap;
11927 int signo;
11928
11929 if (argc <= 1) {
11930 for (signo = 0 ; signo < NSIG ; signo++) {
11931 if (trap[signo] != NULL) {
11932 char *p;
11933 const char *sn;
11934
11935 p = single_quote(trap[signo]);
11936 sn = sys_siglist[signo];
11937 if(sn==NULL)
11938 sn = u_signal_names(0, &signo, 0);
11939 if(sn==NULL)
11940 sn = "???";
11941 printf("trap -- %s %s\n", p, sn);
11942 stunalloc(p);
11943 }
11944 }
11945 return 0;
11946 }
11947 ap = argv + 1;
11948 if (argc == 2)
11949 action = NULL;
11950 else
11951 action = *ap++;
11952 while (*ap) {
11953 if ((signo = decode_signal(*ap, 0)) < 0)
11954 error("%s: bad trap", *ap);
11955 INTOFF;
11956 if (action) {
11957 if (action[0] == '-' && action[1] == '\0')
11958 action = NULL;
11959 else
11960 action = savestr(action);
11961 }
11962 if (trap[signo])
11963 ckfree(trap[signo]);
11964 trap[signo] = action;
11965 if (signo != 0)
11966 setsignal(signo);
11967 INTON;
11968 ap++;
11969 }
11970 return 0;
11971}
11972
11973
11974
11975
11976
11977
11978/*
11979 * Set the signal handler for the specified signal. The routine figures
11980 * out what it should be set to.
11981 */
11982
11983static void
11984setsignal(int signo)
11985{
11986 int action;
11987 char *t;
11988 struct sigaction act;
11989
11990 if ((t = trap[signo]) == NULL)
11991 action = S_DFL;
11992 else if (*t != '\0')
11993 action = S_CATCH;
11994 else
11995 action = S_IGN;
11996 if (rootshell && action == S_DFL) {
11997 switch (signo) {
11998 case SIGINT:
11999 if (iflag || minusc || sflag == 0)
12000 action = S_CATCH;
12001 break;
12002 case SIGQUIT:
12003#ifdef DEBUG
12004 {
12005
12006 if (debug)
12007 break;
12008 }
12009#endif
12010 /* FALLTHROUGH */
12011 case SIGTERM:
12012 if (iflag)
12013 action = S_IGN;
12014 break;
12015#ifdef JOBS
12016 case SIGTSTP:
12017 case SIGTTOU:
12018 if (mflag)
12019 action = S_IGN;
12020 break;
12021#endif
12022 }
12023 }
12024
12025 t = &sigmode[signo - 1];
12026 if (*t == 0) {
12027 /*
12028 * current setting unknown
12029 */
12030 if (sigaction(signo, 0, &act) == -1) {
12031 /*
12032 * Pretend it worked; maybe we should give a warning
12033 * here, but other shells don't. We don't alter
12034 * sigmode, so that we retry every time.
12035 */
12036 return;
12037 }
12038 if (act.sa_handler == SIG_IGN) {
12039 if (mflag && (signo == SIGTSTP ||
12040 signo == SIGTTIN || signo == SIGTTOU)) {
12041 *t = S_IGN; /* don't hard ignore these */
12042 } else
12043 *t = S_HARD_IGN;
12044 } else {
12045 *t = S_RESET; /* force to be set */
12046 }
12047 }
12048 if (*t == S_HARD_IGN || *t == action)
12049 return;
12050 act.sa_handler = ((action == S_CATCH) ? onsig
12051 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
12052 *t = action;
12053 act.sa_flags = 0;
12054 sigemptyset(&act.sa_mask);
12055 sigaction(signo, &act, 0);
12056}
12057
12058/*
12059 * Ignore a signal.
12060 */
12061
12062static void
12063ignoresig(signo)
12064 int signo;
12065{
12066 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12067 signal(signo, SIG_IGN);
12068 }
12069 sigmode[signo - 1] = S_HARD_IGN;
12070}
12071
12072
12073/*
12074 * Signal handler.
12075 */
12076
12077static void
12078onsig(int signo)
12079{
12080 if (signo == SIGINT && trap[SIGINT] == NULL) {
12081 onint();
12082 return;
12083 }
12084 gotsig[signo - 1] = 1;
12085 pendingsigs++;
12086}
12087
12088
12089/*
12090 * Called to execute a trap. Perhaps we should avoid entering new trap
12091 * handlers while we are executing a trap handler.
12092 */
12093
12094static void
12095dotrap(void)
12096{
12097 int i;
12098 int savestatus;
12099
12100 for (;;) {
12101 for (i = 1 ; ; i++) {
12102 if (gotsig[i - 1])
12103 break;
12104 if (i >= NSIG - 1)
12105 goto done;
12106 }
12107 gotsig[i - 1] = 0;
12108 savestatus=exitstatus;
12109 evalstring(trap[i], 0);
12110 exitstatus=savestatus;
12111 }
12112done:
12113 pendingsigs = 0;
12114}
12115
12116/*
12117 * Called to exit the shell.
12118 */
12119
12120static void
12121exitshell(int status)
12122{
12123 struct jmploc loc1, loc2;
12124 char *p;
12125
12126 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12127 if (setjmp(loc1.loc)) {
12128 goto l1;
12129 }
12130 if (setjmp(loc2.loc)) {
12131 goto l2;
12132 }
12133 handler = &loc1;
12134 if ((p = trap[0]) != NULL && *p != '\0') {
12135 trap[0] = NULL;
12136 evalstring(p, 0);
12137 }
12138l1: handler = &loc2; /* probably unnecessary */
12139 flushall();
12140#ifdef JOBS
12141 setjobctl(0);
12142#endif
12143l2: _exit(status);
12144 /* NOTREACHED */
12145}
12146
12147static int decode_signal(const char *string, int minsig)
12148{
12149 int signo;
12150 const char *name = u_signal_names(string, &signo, minsig);
12151
12152 return name ? signo : -1;
12153}
12154
12155static struct var **hashvar (const char *);
12156static void showvars (const char *, int, int);
12157static struct var **findvar (struct var **, const char *);
12158
12159/*
12160 * Initialize the varable symbol tables and import the environment
12161 */
12162
12163/*
12164 * This routine initializes the builtin variables. It is called when the
12165 * shell is initialized and again when a shell procedure is spawned.
12166 */
12167
12168static void
12169initvar() {
12170 const struct varinit *ip;
12171 struct var *vp;
12172 struct var **vpp;
12173
12174 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12175 if ((vp->flags & VEXPORT) == 0) {
12176 vpp = hashvar(ip->text);
12177 vp->next = *vpp;
12178 *vpp = vp;
12179 vp->text = strdup(ip->text);
12180 vp->flags = ip->flags;
12181 vp->func = ip->func;
12182 }
12183 }
12184 /*
12185 * PS1 depends on uid
12186 */
12187 if ((vps1.flags & VEXPORT) == 0) {
12188 vpp = hashvar("PS1=");
12189 vps1.next = *vpp;
12190 *vpp = &vps1;
12191 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12192 vps1.flags = VSTRFIXED|VTEXTFIXED;
12193 }
12194}
12195
12196/*
12197 * Set the value of a variable. The flags argument is ored with the
12198 * flags of the variable. If val is NULL, the variable is unset.
12199 */
12200
12201static void
12202setvar(name, val, flags)
12203 const char *name, *val;
12204 int flags;
12205{
12206 const char *p;
12207 int len;
12208 int namelen;
12209 char *nameeq;
12210 int isbad;
12211 int vallen = 0;
12212
12213 isbad = 0;
12214 p = name;
12215 if (! is_name(*p))
12216 isbad = 1;
12217 p++;
12218 for (;;) {
12219 if (! is_in_name(*p)) {
12220 if (*p == '\0' || *p == '=')
12221 break;
12222 isbad = 1;
12223 }
12224 p++;
12225 }
12226 namelen = p - name;
12227 if (isbad)
12228 error("%.*s: bad variable name", namelen, name);
12229 len = namelen + 2; /* 2 is space for '=' and '\0' */
12230 if (val == NULL) {
12231 flags |= VUNSET;
12232 } else {
12233 len += vallen = strlen(val);
12234 }
12235 INTOFF;
12236 nameeq = ckmalloc(len);
12237 memcpy(nameeq, name, namelen);
12238 nameeq[namelen] = '=';
12239 if (val) {
12240 memcpy(nameeq + namelen + 1, val, vallen + 1);
12241 } else {
12242 nameeq[namelen + 1] = '\0';
12243 }
12244 setvareq(nameeq, flags);
12245 INTON;
12246}
12247
12248
12249
12250/*
12251 * Same as setvar except that the variable and value are passed in
12252 * the first argument as name=value. Since the first argument will
12253 * be actually stored in the table, it should not be a string that
12254 * will go away.
12255 */
12256
12257static void
12258setvareq(s, flags)
12259 char *s;
12260 int flags;
12261{
12262 struct var *vp, **vpp;
12263
12264 vpp = hashvar(s);
12265 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12266 if ((vp = *findvar(vpp, s))) {
12267 if (vp->flags & VREADONLY) {
12268 size_t len = strchr(s, '=') - s;
12269 error("%.*s: is read only", len, s);
12270 }
12271 INTOFF;
12272
12273 if (vp->func && (flags & VNOFUNC) == 0)
12274 (*vp->func)(strchr(s, '=') + 1);
12275
12276 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12277 ckfree(vp->text);
12278
12279 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12280 vp->flags |= flags;
12281 vp->text = s;
12282
12283 /*
12284 * We could roll this to a function, to handle it as
12285 * a regular variable function callback, but why bother?
12286 */
12287 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12288 chkmail(1);
12289 INTON;
12290 return;
12291 }
12292 /* not found */
12293 vp = ckmalloc(sizeof (*vp));
12294 vp->flags = flags;
12295 vp->text = s;
12296 vp->next = *vpp;
12297 vp->func = NULL;
12298 *vpp = vp;
12299}
12300
12301
12302
12303/*
12304 * Process a linked list of variable assignments.
12305 */
12306
12307static void
12308listsetvar(mylist)
12309 struct strlist *mylist;
12310 {
12311 struct strlist *lp;
12312
12313 INTOFF;
12314 for (lp = mylist ; lp ; lp = lp->next) {
12315 setvareq(savestr(lp->text), 0);
12316 }
12317 INTON;
12318}
12319
12320
12321
12322/*
12323 * Find the value of a variable. Returns NULL if not set.
12324 */
12325
12326static const char *
12327lookupvar(name)
12328 const char *name;
12329 {
12330 struct var *v;
12331
12332 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12333 return strchr(v->text, '=') + 1;
12334 }
12335 return NULL;
12336}
12337
12338
12339
12340/*
12341 * Search the environment of a builtin command.
12342 */
12343
12344static const char *
12345bltinlookup(const char *name)
12346{
12347 const struct strlist *sp;
12348
12349 for (sp = cmdenviron ; sp ; sp = sp->next) {
12350 if (varequal(sp->text, name))
12351 return strchr(sp->text, '=') + 1;
12352 }
12353 return lookupvar(name);
12354}
12355
12356
12357
12358/*
12359 * Generate a list of exported variables. This routine is used to construct
12360 * the third argument to execve when executing a program.
12361 */
12362
12363static char **
12364environment() {
12365 int nenv;
12366 struct var **vpp;
12367 struct var *vp;
12368 char **env;
12369 char **ep;
12370
12371 nenv = 0;
12372 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12373 for (vp = *vpp ; vp ; vp = vp->next)
12374 if (vp->flags & VEXPORT)
12375 nenv++;
12376 }
12377 ep = env = stalloc((nenv + 1) * sizeof *env);
12378 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12379 for (vp = *vpp ; vp ; vp = vp->next)
12380 if (vp->flags & VEXPORT)
12381 *ep++ = vp->text;
12382 }
12383 *ep = NULL;
12384 return env;
12385}
12386
12387
12388/*
12389 * Called when a shell procedure is invoked to clear out nonexported
12390 * variables. It is also necessary to reallocate variables of with
12391 * VSTACK set since these are currently allocated on the stack.
12392 */
12393
12394static void
12395shprocvar(void) {
12396 struct var **vpp;
12397 struct var *vp, **prev;
12398
12399 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12400 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12401 if ((vp->flags & VEXPORT) == 0) {
12402 *prev = vp->next;
12403 if ((vp->flags & VTEXTFIXED) == 0)
12404 ckfree(vp->text);
12405 if ((vp->flags & VSTRFIXED) == 0)
12406 ckfree(vp);
12407 } else {
12408 if (vp->flags & VSTACK) {
12409 vp->text = savestr(vp->text);
12410 vp->flags &=~ VSTACK;
12411 }
12412 prev = &vp->next;
12413 }
12414 }
12415 }
12416 initvar();
12417}
12418
12419
12420
12421/*
12422 * Command to list all variables which are set. Currently this command
12423 * is invoked from the set command when the set command is called without
12424 * any variables.
12425 */
12426
12427static int
12428showvarscmd(argc, argv)
12429 int argc;
12430 char **argv;
12431{
12432 showvars(nullstr, VUNSET, VUNSET);
12433 return 0;
12434}
12435
12436
12437
12438/*
12439 * The export and readonly commands.
12440 */
12441
12442static int
12443exportcmd(argc, argv)
12444 int argc;
12445 char **argv;
12446{
12447 struct var *vp;
12448 char *name;
12449 const char *p;
12450 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12451 int pflag;
12452
12453 listsetvar(cmdenviron);
12454 pflag = (nextopt("p") == 'p');
12455 if (argc > 1 && !pflag) {
12456 while ((name = *argptr++) != NULL) {
12457 if ((p = strchr(name, '=')) != NULL) {
12458 p++;
12459 } else {
12460 if ((vp = *findvar(hashvar(name), name))) {
12461 vp->flags |= flag;
12462 goto found;
12463 }
12464 }
12465 setvar(name, p, flag);
12466found:;
12467 }
12468 } else {
12469 showvars(argv[0], flag, 0);
12470 }
12471 return 0;
12472}
12473
12474
12475/*
12476 * The "local" command.
12477 */
12478
12479/* funcnest nonzero if we are currently evaluating a function */
12480
12481static int
12482localcmd(argc, argv)
12483 int argc;
12484 char **argv;
12485{
12486 char *name;
12487
12488 if (! funcnest)
12489 error("Not in a function");
12490 while ((name = *argptr++) != NULL) {
12491 mklocal(name);
12492 }
12493 return 0;
12494}
12495
12496
12497/*
12498 * Make a variable a local variable. When a variable is made local, it's
12499 * value and flags are saved in a localvar structure. The saved values
12500 * will be restored when the shell function returns. We handle the name
12501 * "-" as a special case.
12502 */
12503
12504static void
12505mklocal(name)
12506 char *name;
12507 {
12508 struct localvar *lvp;
12509 struct var **vpp;
12510 struct var *vp;
12511
12512 INTOFF;
12513 lvp = ckmalloc(sizeof (struct localvar));
12514 if (name[0] == '-' && name[1] == '\0') {
12515 char *p;
12516 p = ckmalloc(sizeof optet_vals);
12517 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
12518 vp = NULL;
12519 } else {
12520 vpp = hashvar(name);
12521 vp = *findvar(vpp, name);
12522 if (vp == NULL) {
12523 if (strchr(name, '='))
12524 setvareq(savestr(name), VSTRFIXED);
12525 else
12526 setvar(name, NULL, VSTRFIXED);
12527 vp = *vpp; /* the new variable */
12528 lvp->text = NULL;
12529 lvp->flags = VUNSET;
12530 } else {
12531 lvp->text = vp->text;
12532 lvp->flags = vp->flags;
12533 vp->flags |= VSTRFIXED|VTEXTFIXED;
12534 if (strchr(name, '='))
12535 setvareq(savestr(name), 0);
12536 }
12537 }
12538 lvp->vp = vp;
12539 lvp->next = localvars;
12540 localvars = lvp;
12541 INTON;
12542}
12543
12544
12545/*
12546 * Called after a function returns.
12547 */
12548
12549static void
12550poplocalvars() {
12551 struct localvar *lvp;
12552 struct var *vp;
12553
12554 while ((lvp = localvars) != NULL) {
12555 localvars = lvp->next;
12556 vp = lvp->vp;
12557 if (vp == NULL) { /* $- saved */
12558 memcpy(optet_vals, lvp->text, sizeof optet_vals);
12559 ckfree(lvp->text);
12560 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12561 (void)unsetvar(vp->text);
12562 } else {
12563 if ((vp->flags & VTEXTFIXED) == 0)
12564 ckfree(vp->text);
12565 vp->flags = lvp->flags;
12566 vp->text = lvp->text;
12567 }
12568 ckfree(lvp);
12569 }
12570}
12571
12572
12573static int
12574setvarcmd(argc, argv)
12575 int argc;
12576 char **argv;
12577{
12578 if (argc <= 2)
12579 return unsetcmd(argc, argv);
12580 else if (argc == 3)
12581 setvar(argv[1], argv[2], 0);
12582 else
12583 error("List assignment not implemented");
12584 return 0;
12585}
12586
12587
12588/*
12589 * The unset builtin command. We unset the function before we unset the
12590 * variable to allow a function to be unset when there is a readonly variable
12591 * with the same name.
12592 */
12593
12594static int
12595unsetcmd(argc, argv)
12596 int argc;
12597 char **argv;
12598{
12599 char **ap;
12600 int i;
12601 int flg_func = 0;
12602 int flg_var = 0;
12603 int ret = 0;
12604
12605 while ((i = nextopt("vf")) != '\0') {
12606 if (i == 'f')
12607 flg_func = 1;
12608 else
12609 flg_var = 1;
12610 }
12611 if (flg_func == 0 && flg_var == 0)
12612 flg_var = 1;
12613
12614 for (ap = argptr; *ap ; ap++) {
12615 if (flg_func)
12616 unsetfunc(*ap);
12617 if (flg_var)
12618 ret |= unsetvar(*ap);
12619 }
12620 return ret;
12621}
12622
12623
12624/*
12625 * Unset the specified variable.
12626 */
12627
12628static int
12629unsetvar(const char *s)
12630{
12631 struct var **vpp;
12632 struct var *vp;
12633
12634 vpp = findvar(hashvar(s), s);
12635 vp = *vpp;
12636 if (vp) {
12637 if (vp->flags & VREADONLY)
12638 return (1);
12639 INTOFF;
12640 if (*(strchr(vp->text, '=') + 1) != '\0')
12641 setvar(s, nullstr, 0);
12642 vp->flags &= ~VEXPORT;
12643 vp->flags |= VUNSET;
12644 if ((vp->flags & VSTRFIXED) == 0) {
12645 if ((vp->flags & VTEXTFIXED) == 0)
12646 ckfree(vp->text);
12647 *vpp = vp->next;
12648 ckfree(vp);
12649 }
12650 INTON;
12651 return (0);
12652 }
12653
12654 return (0);
12655}
12656
12657
12658
12659/*
12660 * Find the appropriate entry in the hash table from the name.
12661 */
12662
12663static struct var **
12664hashvar(const char *p)
12665{
12666 unsigned int hashval;
12667
12668 hashval = ((unsigned char) *p) << 4;
12669 while (*p && *p != '=')
12670 hashval += (unsigned char) *p++;
12671 return &vartab[hashval % VTABSIZE];
12672}
12673
12674
12675
12676/*
12677 * Returns true if the two strings specify the same varable. The first
12678 * variable name is terminated by '='; the second may be terminated by
12679 * either '=' or '\0'.
12680 */
12681
12682static int
12683varequal(const char *p, const char *q)
12684{
12685 while (*p == *q++) {
12686 if (*p++ == '=')
12687 return 1;
12688 }
12689 if (*p == '=' && *(q - 1) == '\0')
12690 return 1;
12691 return 0;
12692}
12693
12694static void
12695showvars(const char *myprefix, int mask, int xor)
12696{
12697 struct var **vpp;
12698 struct var *vp;
12699 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12700
12701 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12702 for (vp = *vpp ; vp ; vp = vp->next) {
12703 if ((vp->flags & mask) ^ xor) {
12704 char *p;
12705 int len;
12706
12707 p = strchr(vp->text, '=') + 1;
12708 len = p - vp->text;
12709 p = single_quote(p);
12710
12711 printf("%s%s%.*s%s\n", myprefix, sep, len,
12712 vp->text, p);
12713 stunalloc(p);
12714 }
12715 }
12716 }
12717}
12718
12719static struct var **
12720findvar(struct var **vpp, const char *name)
12721{
12722 for (; *vpp; vpp = &(*vpp)->next) {
12723 if (varequal((*vpp)->text, name)) {
12724 break;
12725 }
12726 }
12727 return vpp;
12728}
12729
12730/*
12731 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12732 * This file contains code for the times builtin.
12733 * $Id: ash.c,v 1.28 2001/10/19 00:22:22 andersen Exp $
12734 */
12735static int timescmd (int argc, char **argv)
12736{
12737 struct tms buf;
12738 long int clk_tck = sysconf(_SC_CLK_TCK);
12739
12740 times(&buf);
12741 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12742 (int) (buf.tms_utime / clk_tck / 60),
12743 ((double) buf.tms_utime) / clk_tck,
12744 (int) (buf.tms_stime / clk_tck / 60),
12745 ((double) buf.tms_stime) / clk_tck,
12746 (int) (buf.tms_cutime / clk_tck / 60),
12747 ((double) buf.tms_cutime) / clk_tck,
12748 (int) (buf.tms_cstime / clk_tck / 60),
12749 ((double) buf.tms_cstime) / clk_tck);
12750 return 0;
12751}
12752
12753#ifdef ASH_MATH_SUPPORT
12754/* The let builtin. */
12755int letcmd(int argc, char **argv)
12756{
12757 int errcode;
12758 long result=0;
12759 if (argc == 2) {
12760 char *tmp, *expression, p[13];
12761 expression = strchr(argv[1], '=');
12762 if (!expression) {
12763 /* Cannot use 'error()' here, or the return code
12764 * will be incorrect */
12765 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12766 return 0;
12767 }
12768 *expression = '\0';
12769 tmp = ++expression;
12770 result = arith(tmp, &errcode);
12771 if (errcode < 0) {
12772 /* Cannot use 'error()' here, or the return code
12773 * will be incorrect */
12774 out2fmt("sh: let: ");
12775 if(errcode == -2)
12776 out2fmt("divide by zero");
12777 else
12778 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
12779 return 0;
12780 }
12781 snprintf(p, 12, "%ld", result);
12782 setvar(argv[1], savestr(p), 0);
12783 } else if (argc >= 3)
12784 synerror("invalid operand");
12785 return !result;
12786}
12787#endif
12788
12789
12790
12791/*-
12792 * Copyright (c) 1989, 1991, 1993, 1994
12793 * The Regents of the University of California. All rights reserved.
12794 *
12795 * This code is derived from software contributed to Berkeley by
12796 * Kenneth Almquist.
12797 *
12798 * Redistribution and use in source and binary forms, with or without
12799 * modification, are permitted provided that the following conditions
12800 * are met:
12801 * 1. Redistributions of source code must retain the above copyright
12802 * notice, this list of conditions and the following disclaimer.
12803 * 2. Redistributions in binary form must reproduce the above copyright
12804 * notice, this list of conditions and the following disclaimer in the
12805 * documentation and/or other materials provided with the distribution.
12806 *
12807 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12808 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
12809 *
12810 * 4. Neither the name of the University nor the names of its contributors
12811 * may be used to endorse or promote products derived from this software
12812 * without specific prior written permission.
12813 *
12814 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12815 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12816 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12817 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12818 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12819 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12820 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12821 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12822 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12823 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12824 * SUCH DAMAGE.
12825 */
diff --git a/basename.c b/basename.c
deleted file mode 100644
index c15afd533..000000000
--- a/basename.c
+++ /dev/null
@@ -1,52 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini basename implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24/* getopt not needed */
25
26#include <stdlib.h>
27#include "busybox.h"
28#include <string.h>
29
30extern int basename_main(int argc, char **argv)
31{
32 int m, n;
33 char *s;
34
35 if ((argc < 2) || (**(argv + 1) == '-')) {
36 show_usage();
37 }
38
39 argv++;
40
41 s = get_last_path_component(*argv);
42
43 if (argc>2) {
44 argv++;
45 n = strlen(*argv);
46 m = strlen(s);
47 if (m>n && strncmp(s+m-n, *argv, n)==0)
48 s[m-n] = '\0';
49 }
50 puts(s);
51 return EXIT_SUCCESS;
52}
diff --git a/bunzip2.c b/bunzip2.c
deleted file mode 100644
index 757654dab..000000000
--- a/bunzip2.c
+++ /dev/null
@@ -1,2340 +0,0 @@
1/* Modified for busybox by Glenn McGrath <bug1@optushome.com.au> */
2/*--
3 This file is a part of bzip2 and/or libbzip2, a program and
4 library for lossless, block-sorting data compression.
5
6 Copyright (C) 1996-2000 Julian R Seward. All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14
15 2. The origin of this software must not be misrepresented; you must
16 not claim that you wrote the original software. If you use this
17 software in a product, an acknowledgment in the product
18 documentation would be appreciated but is not required.
19
20 3. Altered source versions must be plainly marked as such, and must
21 not be misrepresented as being the original software.
22
23 4. The name of the author may not be used to endorse or promote
24 products derived from this software without specific prior written
25 permission.
26
27 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
28 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
31 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
33 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39 Julian Seward, Cambridge, UK.
40 jseward@acm.org
41 bzip2/libbzip2 version 1.0 of 21 March 2000
42
43 This program is based on (at least) the work of:
44 Mike Burrows
45 David Wheeler
46 Peter Fenwick
47 Alistair Moffat
48 Radford Neal
49 Ian H. Witten
50 Robert Sedgewick
51 Jon L. Bentley
52
53 For more information on these sources, see the manual.
54--*/
55
56#include <stdlib.h>
57#include <stdio.h>
58#include <string.h>
59#include <busybox.h>
60
61//#define TRUE 1
62//#define FALSE 0
63
64#define MTFA_SIZE 4096
65#define MTFL_SIZE 16
66#define BZ_N_GROUPS 6
67#define BZ_G_SIZE 50
68#define BZ_MAX_ALPHA_SIZE 258
69
70#define BZ_OK 0
71#define BZ_RUN_OK 1
72#define BZ_FLUSH_OK 2
73#define BZ_FINISH_OK 3
74#define BZ_STREAM_END 4
75#define BZ_SEQUENCE_ERROR (-1)
76#define BZ_PARAM_ERROR (-2)
77#define BZ_MEM_ERROR (-3)
78#define BZ_DATA_ERROR (-4)
79#define BZ_DATA_ERROR_MAGIC (-5)
80#define BZ_IO_ERROR (-6)
81#define BZ_UNEXPECTED_EOF (-7)
82#define BZ_OUTBUFF_FULL (-8)
83#define BZ_CONFIG_ERROR (-9)
84
85#define BZ_RUNA 0
86#define BZ_RUNB 1
87
88#define BZ_MAX_UNUSED 5000
89#define FILE_NAME_LEN 1034
90/*-- states for decompression. --*/
91
92#define BZ_X_IDLE 1
93#define BZ_X_OUTPUT 2
94
95#define BZ_X_MAGIC_1 10
96#define BZ_X_MAGIC_2 11
97#define BZ_X_MAGIC_3 12
98#define BZ_X_MAGIC_4 13
99#define BZ_X_BLKHDR_1 14
100#define BZ_X_BLKHDR_2 15
101#define BZ_X_BLKHDR_3 16
102#define BZ_X_BLKHDR_4 17
103#define BZ_X_BLKHDR_5 18
104#define BZ_X_BLKHDR_6 19
105#define BZ_X_BCRC_1 20
106#define BZ_X_BCRC_2 21
107#define BZ_X_BCRC_3 22
108#define BZ_X_BCRC_4 23
109#define BZ_X_RANDBIT 24
110#define BZ_X_ORIGPTR_1 25
111#define BZ_X_ORIGPTR_2 26
112#define BZ_X_ORIGPTR_3 27
113#define BZ_X_MAPPING_1 28
114#define BZ_X_MAPPING_2 29
115#define BZ_X_SELECTOR_1 30
116#define BZ_X_SELECTOR_2 31
117#define BZ_X_SELECTOR_3 32
118#define BZ_X_CODING_1 33
119#define BZ_X_CODING_2 34
120#define BZ_X_CODING_3 35
121#define BZ_X_MTF_1 36
122#define BZ_X_MTF_2 37
123#define BZ_X_MTF_3 38
124#define BZ_X_MTF_4 39
125#define BZ_X_MTF_5 40
126#define BZ_X_MTF_6 41
127#define BZ_X_ENDHDR_2 42
128#define BZ_X_ENDHDR_3 43
129#define BZ_X_ENDHDR_4 44
130#define BZ_X_ENDHDR_5 45
131#define BZ_X_ENDHDR_6 46
132#define BZ_X_CCRC_1 47
133#define BZ_X_CCRC_2 48
134#define BZ_X_CCRC_3 49
135#define BZ_X_CCRC_4 50
136
137#define BZ_MAX_CODE_LEN 23
138#define BZ_VERSION "1.0.1, 23-June-2000"
139#define OM_TEST 3
140#define SM_F2F 3
141
142typedef struct {
143 char *next_in;
144 unsigned int avail_in;
145 unsigned int total_in_lo32;
146 unsigned int total_in_hi32;
147
148 char *next_out;
149 unsigned int avail_out;
150 unsigned int total_out_lo32;
151 unsigned int total_out_hi32;
152
153 void *state;
154
155 void *(*bzalloc)(void *,int,int);
156 void (*bzfree)(void *,void *);
157 void *opaque;
158} bz_stream;
159
160typedef struct {
161 bz_stream strm;
162 FILE *handle;
163 unsigned char initialisedOk;
164 unsigned char writing;
165 char buf[BZ_MAX_UNUSED];
166 int lastErr;
167 int bufN;
168} bzFile;
169
170/*-- Structure holding all the decompression-side stuff. --*/
171typedef struct {
172 /* pointer back to the struct bz_stream */
173 bz_stream* strm;
174
175 /* state indicator for this stream */
176 int state;
177
178 /* for doing the final run-length decoding */
179 unsigned char state_out_ch;
180 int state_out_len;
181 unsigned char blockRandomised;
182 int rNToGo;
183 int rTPos;
184
185 /* the buffer for bit stream reading */
186 unsigned int bsBuff;
187 int bsLive;
188
189 /* misc administratium */
190 int blockSize100k;
191 unsigned char smallDecompress;
192 int currBlockNo;
193 int verbosity;
194
195 /* for undoing the Burrows-Wheeler transform */
196 int origPtr;
197 unsigned int tPos;
198 int k0;
199 int unzftab[256];
200 int nblock_used;
201 int cftab[257];
202 int cftabCopy[257];
203
204 /* for undoing the Burrows-Wheeler transform (FAST) */
205 unsigned int *tt;
206
207 /* for undoing the Burrows-Wheeler transform (SMALL) */
208 unsigned short *ll16;
209 unsigned char *ll4;
210
211 /* stored and calculated CRCs */
212 unsigned int storedBlockCRC;
213 unsigned int storedCombinedCRC;
214 unsigned int calculatedBlockCRC;
215 unsigned int calculatedCombinedCRC;
216
217 /* map of bytes used in block */
218 int nInUse;
219 unsigned char inUse[256];
220 unsigned char inUse16[16];
221 unsigned char seqToUnseq[256];
222
223 /* for decoding the MTF values */
224 unsigned char mtfa [MTFA_SIZE];
225 unsigned char selector [2 + (900000 / BZ_G_SIZE)];
226 unsigned char selectorMtf[2 + (900000 / BZ_G_SIZE)];
227 unsigned char len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
228 int mtfbase[256 / MTFL_SIZE];
229
230 int limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
231 int base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
232 int perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
233 int minLens[BZ_N_GROUPS];
234
235 /* save area for scalars in the main decompress code */
236 int save_i;
237 int save_j;
238 int save_t;
239 int save_alphaSize;
240 int save_nGroups;
241 int save_nSelectors;
242 int save_EOB;
243 int save_groupNo;
244 int save_groupPos;
245 int save_nextSym;
246 int save_nblockMAX;
247 int save_nblock;
248 int save_es;
249 int save_N;
250 int save_curr;
251 int save_zt;
252 int save_zn;
253 int save_zvec;
254 int save_zj;
255 int save_gSel;
256 int save_gMinlen;
257 int *save_gLimit;
258 int *save_gBase;
259 int *save_gPerm;
260} DState;
261
262int BZ2_rNums[512];
263//int verbosity_level;
264unsigned char smallMode;
265unsigned char noisy;
266char *progName;
267char inName[FILE_NAME_LEN];
268char outName[FILE_NAME_LEN];
269int srcMode;
270int opMode;
271unsigned char deleteOutputOnInterrupt;
272FILE *outputHandleJustInCase;
273int numFileNames;
274int numFilesProcessed;
275int exitValue;
276
277unsigned int BZ2_crc32Table[256] = {
278
279 /*-- Ugly, innit? --*/
280
281 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
282 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
283 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
284 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
285 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
286 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
287 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
288 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
289 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
290 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
291 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
292 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
293 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
294 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
295 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
296 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
297 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
298 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
299 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
300 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
301 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
302 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
303 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
304 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
305 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
306 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
307 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
308 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
309 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
310 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
311 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
312 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
313 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
314 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
315 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
316 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
317 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
318 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
319 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
320 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
321 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
322 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
323 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
324 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
325 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
326 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
327 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
328 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
329 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
330 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
331 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
332 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
333 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
334 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
335 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
336 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
337 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
338 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
339 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
340 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
341 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
342 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
343 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
344 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
345};
346
347void bz_rand_udp_mask(DState *s)
348{
349 if (s->rNToGo == 0) {
350 s->rNToGo = BZ2_rNums[s->rTPos];
351 s->rTPos++;
352 if (s->rTPos == 512) {
353 s->rTPos = 0;
354 }
355 }
356 s->rNToGo--;
357}
358
359static unsigned char myfeof(FILE *f)
360{
361 int c = fgetc(f);
362 if (c == EOF) {
363 return(TRUE);
364 }
365 ungetc(c, f);
366 return(FALSE);
367}
368
369static void cleanUpAndFail(int ec)
370{
371 int retVal;
372
373 if ((srcMode == SM_F2F) && (opMode != OM_TEST) && deleteOutputOnInterrupt) {
374 if (noisy) {
375 error_msg("%s: Deleting output file %s, if it exists.\n", progName, outName);
376 }
377 if (outputHandleJustInCase != NULL) {
378 fclose(outputHandleJustInCase);
379 }
380 retVal = remove(outName);
381 if (retVal != 0) {
382 error_msg("%s: WARNING: deletion of output file (apparently) failed.\n", progName);
383 }
384 }
385 if (noisy && (numFileNames > 0) && (numFilesProcessed < numFileNames)) {
386 error_msg("%s: WARNING: some files have not been processed:\n"
387 "\t%d specified on command line, %d not processed yet.\n\n",
388 progName, numFileNames, numFileNames - numFilesProcessed );
389 }
390
391 exit(ec);
392}
393
394
395void panic(char *s)
396{
397 error_msg("\n%s: PANIC -- internal consistency error:\n"
398 "\t%s\n"
399 "\tThis is a BUG. Please report it to me at:\n"
400 "\tjseward@acm.org\n",
401 progName, s);
402 cleanUpAndFail( 3 );
403}
404
405void BZ2_hbCreateDecodeTables(int *limit, int *base, int *perm, unsigned char *length, int minLen, int maxLen, int alphaSize )
406{
407 int pp, i, j, vec;
408
409 pp = 0;
410 for (i = minLen; i <= maxLen; i++) {
411 for (j = 0; j < alphaSize; j++) {
412 if (length[j] == i) {
413 perm[pp] = j;
414 pp++;
415 }
416 }
417 }
418
419 for (i = 0; i < BZ_MAX_CODE_LEN; i++) {
420 base[i] = 0;
421 }
422
423 for (i = 0; i < alphaSize; i++) {
424 base[length[i]+1]++;
425 }
426
427 for (i = 1; i < BZ_MAX_CODE_LEN; i++) {
428 base[i] += base[i-1];
429 }
430
431 for (i = 0; i < BZ_MAX_CODE_LEN; i++) {
432 limit[i] = 0;
433 }
434 vec = 0;
435
436 for (i = minLen; i <= maxLen; i++) {
437 vec += (base[i+1] - base[i]);
438 limit[i] = vec-1;
439 vec <<= 1;
440 }
441 for (i = minLen + 1; i <= maxLen; i++) {
442 base[i] = ((limit[i-1] + 1) << 1) - base[i];
443 }
444}
445
446int bz_get_small(DState *s)
447{
448 int cccc;
449 int nb, na, mid;
450 nb = 0;
451 na = 256;
452 do {
453 mid = (nb + na) >> 1;
454 if (s->tPos >= s->cftab[mid]) {
455 nb = mid;
456 } else {
457 na = mid;
458 }
459 }
460 while (na - nb != 1);
461 cccc = nb;
462 s->tPos = (((unsigned int)s->ll16[s->tPos]) |
463 (((((unsigned int)(s->ll4[(s->tPos) >> 1])) >>
464 (((s->tPos) << 2) & 0x4)) & 0xF) << 16));
465 return(cccc);
466}
467
468void assert_h(int errcode)
469{
470 error_msg_and_die("\n\nbzip2/libbzip2: internal error number %d.\n"
471 "This is a bug in bzip2/libbzip2, %s.\n"
472 "Please report it to me at: jseward@acm.org. If this happened\n"
473 "when you were using some program which uses libbzip2 as a\n"
474 "component, you should also report this bug to the author(s)\n"
475 "of that program. Please make an effort to report this bug;\n"
476 "timely and accurate bug reports eventually lead to higher\n"
477 "quality software. Thanks. Julian Seward, 21 March 2000.\n\n",
478 errcode, BZ_VERSION);
479}
480
481static int get_bits(DState *s, int *vvv, char nnn)
482{
483 while (1) {
484 if (s->bsLive >= nnn) {
485 *vvv = (s->bsBuff >> (s->bsLive-nnn)) & ((1 << nnn)-1);
486 s->bsLive -= nnn;
487 break;
488 }
489 if (s->strm->avail_in == 0) {
490 return(FALSE);
491 }
492 s->bsBuff = (s->bsBuff << 8) | ((unsigned int) (*((unsigned char*)(s->strm->next_in))));
493 s->bsLive += 8;
494 s->strm->next_in++;
495 s->strm->avail_in--;
496 s->strm->total_in_lo32++;
497 if (s->strm->total_in_lo32 == 0) {
498 s->strm->total_in_hi32++;
499 }
500 }
501 return(TRUE);
502}
503
504int bz_get_fast(DState *s)
505{
506 int cccc;
507 s->tPos = s->tt[s->tPos];
508 cccc = (unsigned char)(s->tPos & 0xff);
509 s->tPos >>= 8;
510 return(cccc);
511}
512
513/*---------------------------------------------------*/
514int BZ2_decompress(DState *s)
515{
516 int uc = 0;
517 int retVal;
518 int minLen, maxLen;
519 bz_stream *strm = s->strm;
520
521 /* stuff that needs to be saved/restored */
522 int i;
523 int j;
524 int t;
525 int alphaSize;
526 int nGroups;
527 int nSelectors;
528 int EOB;
529 int groupNo;
530 int groupPos;
531 int nextSym;
532 int nblockMAX;
533 int nblock;
534 int es;
535 int N;
536 int curr;
537 int zt;
538 int zn;
539 int zvec;
540 int zj;
541 int gSel;
542 int gMinlen;
543 int *gLimit;
544 int *gBase;
545 int *gPerm;
546 int switch_val;
547
548 int get_mtf_val_init(void)
549 {
550 if (groupPos == 0) {
551 groupNo++;
552 if (groupNo >= nSelectors) {
553 retVal = BZ_DATA_ERROR;
554 return(FALSE);
555 }
556 groupPos = BZ_G_SIZE;
557 gSel = s->selector[groupNo];
558 gMinlen = s->minLens[gSel];
559 gLimit = &(s->limit[gSel][0]);
560 gPerm = &(s->perm[gSel][0]);
561 gBase = &(s->base[gSel][0]);
562 }
563 groupPos--;
564 zn = gMinlen;
565 return(TRUE);
566 }
567
568 if (s->state == BZ_X_MAGIC_1) {
569 /*initialise the save area*/
570 s->save_i = 0;
571 s->save_j = 0;
572 s->save_t = 0;
573 s->save_alphaSize = 0;
574 s->save_nGroups = 0;
575 s->save_nSelectors = 0;
576 s->save_EOB = 0;
577 s->save_groupNo = 0;
578 s->save_groupPos = 0;
579 s->save_nextSym = 0;
580 s->save_nblockMAX = 0;
581 s->save_nblock = 0;
582 s->save_es = 0;
583 s->save_N = 0;
584 s->save_curr = 0;
585 s->save_zt = 0;
586 s->save_zn = 0;
587 s->save_zvec = 0;
588 s->save_zj = 0;
589 s->save_gSel = 0;
590 s->save_gMinlen = 0;
591 s->save_gLimit = NULL;
592 s->save_gBase = NULL;
593 s->save_gPerm = NULL;
594 }
595
596 /*restore from the save area*/
597 i = s->save_i;
598 j = s->save_j;
599 t = s->save_t;
600 alphaSize = s->save_alphaSize;
601 nGroups = s->save_nGroups;
602 nSelectors = s->save_nSelectors;
603 EOB = s->save_EOB;
604 groupNo = s->save_groupNo;
605 groupPos = s->save_groupPos;
606 nextSym = s->save_nextSym;
607 nblockMAX = s->save_nblockMAX;
608 nblock = s->save_nblock;
609 es = s->save_es;
610 N = s->save_N;
611 curr = s->save_curr;
612 zt = s->save_zt;
613 zn = s->save_zn;
614 zvec = s->save_zvec;
615 zj = s->save_zj;
616 gSel = s->save_gSel;
617 gMinlen = s->save_gMinlen;
618 gLimit = s->save_gLimit;
619 gBase = s->save_gBase;
620 gPerm = s->save_gPerm;
621
622 retVal = BZ_OK;
623 switch_val = s->state;
624 switch (switch_val) {
625 case BZ_X_MAGIC_1:
626 s->state = BZ_X_MAGIC_1;
627 if (get_bits(s, &uc, 8) == FALSE) {
628 retVal = BZ_OK;
629 goto save_state_and_return;
630 }
631 if (uc != 'B') {
632 retVal = BZ_DATA_ERROR_MAGIC;
633 goto save_state_and_return;
634 }
635
636 case BZ_X_MAGIC_2:
637 s->state = BZ_X_MAGIC_2;
638 if (get_bits(s, &uc, 8) == FALSE) {
639 retVal = BZ_OK;
640 goto save_state_and_return;
641 }
642 if (uc != 'Z') {
643 retVal = BZ_DATA_ERROR_MAGIC;
644 goto save_state_and_return;
645 }
646
647 case BZ_X_MAGIC_3:
648 s->state = BZ_X_MAGIC_3;
649 if (get_bits(s, &uc, 8) == FALSE) {
650 retVal = BZ_OK;
651 goto save_state_and_return;
652 }
653 if (uc != 'h') {
654 retVal = BZ_DATA_ERROR_MAGIC;
655 goto save_state_and_return;
656 }
657
658 case BZ_X_MAGIC_4:
659 s->state = BZ_X_MAGIC_4;
660 if (get_bits(s, &s->blockSize100k, 8) == FALSE) {
661 retVal = BZ_OK;
662 goto save_state_and_return;
663 }
664 if ((s->blockSize100k < '1') || (s->blockSize100k > '9')) {
665 retVal = BZ_DATA_ERROR_MAGIC;
666 goto save_state_and_return;
667 }
668 s->blockSize100k -= '0';
669
670 if (s->smallDecompress) {
671 s->ll16 = (strm->bzalloc)(strm->opaque, s->blockSize100k * 100000 * sizeof(unsigned short), 1);
672 s->ll4 = (strm->bzalloc)(strm->opaque, ((1 + s->blockSize100k * 100000) >> 1) * sizeof(unsigned char), 1);
673
674 if (s->ll16 == NULL || s->ll4 == NULL) {
675 retVal = BZ_MEM_ERROR;
676 goto save_state_and_return;
677 }
678 } else {
679 s->tt = (strm->bzalloc)(strm->opaque, s->blockSize100k * 100000 * sizeof(int), 1);
680 if (s->tt == NULL) {
681 retVal = BZ_MEM_ERROR;
682 goto save_state_and_return;
683 }
684 }
685
686 case BZ_X_BLKHDR_1:
687 s->state = BZ_X_BLKHDR_1;
688 if (get_bits(s, &uc, 8) == FALSE) {
689 retVal = BZ_OK;
690 goto save_state_and_return;
691 }
692
693 if (uc == 0x17) {
694 goto endhdr_2;
695 }
696 if (uc != 0x31) {
697 retVal = BZ_DATA_ERROR;
698 goto save_state_and_return;
699 }
700
701 case BZ_X_BLKHDR_2:
702 s->state = BZ_X_BLKHDR_2;
703 if (get_bits(s, &uc, 8) == FALSE) {
704 retVal = BZ_OK;
705 goto save_state_and_return;
706 }
707 if (uc != 0x41) {
708 retVal = BZ_DATA_ERROR;
709 goto save_state_and_return;
710 }
711
712 case BZ_X_BLKHDR_3:
713 s->state = BZ_X_BLKHDR_3;
714 if (get_bits(s, &uc, 8) == FALSE) {
715 retVal = BZ_OK;
716 goto save_state_and_return;
717 }
718 if (uc != 0x59) {
719 retVal = BZ_DATA_ERROR;
720 goto save_state_and_return;
721 }
722
723 case BZ_X_BLKHDR_4:
724 s->state = BZ_X_BLKHDR_4;
725 if (get_bits(s, &uc, 8) == FALSE) {
726 retVal = BZ_OK;
727 goto save_state_and_return;
728 }
729 if (uc != 0x26) {
730 retVal = BZ_DATA_ERROR;
731 goto save_state_and_return;
732 }
733
734 case BZ_X_BLKHDR_5:
735 s->state = BZ_X_BLKHDR_5;
736 if (get_bits(s, &uc, 8) == FALSE) {
737 retVal = BZ_OK;
738 goto save_state_and_return;
739 }
740 if (uc != 0x53) {
741 retVal = BZ_DATA_ERROR;
742 goto save_state_and_return;
743 }
744
745 case BZ_X_BLKHDR_6:
746 s->state = BZ_X_BLKHDR_6;
747 if (get_bits(s, &uc, 8) == FALSE) {
748 retVal = BZ_OK;
749 goto save_state_and_return;
750 }
751 if (uc != 0x59) {
752 retVal = BZ_DATA_ERROR;
753 goto save_state_and_return;
754 }
755
756 s->currBlockNo++;
757 if (s->verbosity >= 2) {
758 error_msg("\n [%d: huff+mtf ", s->currBlockNo);
759 }
760 s->storedBlockCRC = 0;
761
762 case BZ_X_BCRC_1:
763 s->state = BZ_X_BCRC_1;
764 if (get_bits(s, &uc, 8) == FALSE) {
765 retVal = BZ_OK;
766 goto save_state_and_return;
767 }
768 s->storedBlockCRC = (s->storedBlockCRC << 8) | ((unsigned int)uc);
769
770 case BZ_X_BCRC_2:
771 s->state = BZ_X_BCRC_2;
772 if (get_bits(s, &uc, 8) == FALSE) {
773 retVal = BZ_OK;
774 goto save_state_and_return;
775 }
776 s->storedBlockCRC = (s->storedBlockCRC << 8) | ((unsigned int)uc);
777
778 case BZ_X_BCRC_3:
779 s->state = BZ_X_BCRC_3;
780 if (get_bits(s, &uc, 8) == FALSE) {
781 retVal = BZ_OK;
782 goto save_state_and_return;
783 }
784 s->storedBlockCRC = (s->storedBlockCRC << 8) | ((unsigned int)uc);
785
786 case BZ_X_BCRC_4:
787 s->state = BZ_X_BCRC_4;
788 if (get_bits(s, &uc, 8) == FALSE) {
789 retVal = BZ_OK;
790 goto save_state_and_return;
791 }
792 s->storedBlockCRC = (s->storedBlockCRC << 8) | ((unsigned int)uc);
793
794 case BZ_X_RANDBIT:
795 s->state = BZ_X_RANDBIT;
796 {
797 int tmp = s->blockRandomised;
798 const int ret = get_bits(s, &tmp, 1);
799 s->blockRandomised = tmp;
800 if (ret == FALSE) {
801 retVal = BZ_OK;
802 goto save_state_and_return;
803 }
804 }
805
806 s->origPtr = 0;
807
808 case BZ_X_ORIGPTR_1:
809 s->state = BZ_X_ORIGPTR_1;
810 if (get_bits(s, &uc, 8) == FALSE) {
811 retVal = BZ_OK;
812 goto save_state_and_return;
813 }
814 s->origPtr = (s->origPtr << 8) | ((int)uc);
815
816 case BZ_X_ORIGPTR_2:
817 s->state = BZ_X_ORIGPTR_2;
818 if (get_bits(s, &uc, 8) == FALSE) {
819 retVal = BZ_OK;
820 goto save_state_and_return;
821 }
822 s->origPtr = (s->origPtr << 8) | ((int)uc);
823
824 case BZ_X_ORIGPTR_3:
825 s->state = BZ_X_ORIGPTR_3;
826 if (get_bits(s, &uc, 8) == FALSE) {
827 retVal = BZ_OK;
828 goto save_state_and_return;
829 }
830 s->origPtr = (s->origPtr << 8) | ((int)uc);
831
832 if (s->origPtr < 0) {
833 retVal = BZ_DATA_ERROR;
834 goto save_state_and_return;
835 }
836 if (s->origPtr > 10 + 100000*s->blockSize100k) {
837 retVal = BZ_DATA_ERROR;
838 goto save_state_and_return;
839 }
840
841 /*--- Receive the mapping table ---*/
842 case BZ_X_MAPPING_1:
843 for (i = 0; i < 16; i++) {
844 s->state = BZ_X_MAPPING_1;
845 if (get_bits(s, &uc, 1) == FALSE) {
846 retVal = BZ_OK;
847 goto save_state_and_return;
848 }
849 if (uc == 1) {
850 s->inUse16[i] = TRUE;
851 } else {
852 s->inUse16[i] = FALSE;
853 }
854 }
855
856 for (i = 0; i < 256; i++) {
857 s->inUse[i] = FALSE;
858 }
859
860 for (i = 0; i < 16; i++) {
861 if (s->inUse16[i]) {
862 for (j = 0; j < 16; j++) {
863 case BZ_X_MAPPING_2:
864 s->state = BZ_X_MAPPING_2;
865 if (get_bits(s, &uc, 1) == FALSE) {
866 retVal = BZ_OK;
867 goto save_state_and_return;
868 }
869 if (uc == 1) {
870 s->inUse[i * 16 + j] = TRUE;
871 }
872 }
873 }
874 }
875
876 s->nInUse = 0;
877 for (i = 0; i < 256; i++) {
878 if (s->inUse[i]) {
879 s->seqToUnseq[s->nInUse] = i;
880 s->nInUse++;
881 }
882 }
883 if (s->nInUse == 0) {
884 retVal = BZ_DATA_ERROR;
885 goto save_state_and_return;
886 }
887 alphaSize = s->nInUse+2;
888
889 /*--- Now the selectors ---*/
890 case BZ_X_SELECTOR_1:
891 s->state = BZ_X_SELECTOR_1;
892 if (get_bits(s, &nGroups, 3) == FALSE) {
893 retVal = BZ_OK;
894 goto save_state_and_return;
895 }
896 if (nGroups < 2 || nGroups > 6) {
897 retVal = BZ_DATA_ERROR;
898 goto save_state_and_return;
899 }
900
901 case BZ_X_SELECTOR_2:
902 s->state = BZ_X_SELECTOR_2;
903 if (get_bits(s, &nSelectors, 15) == FALSE) {
904 retVal = BZ_OK;
905 goto save_state_and_return;
906 }
907 if (nSelectors < 1) {
908 retVal = BZ_DATA_ERROR;
909 goto save_state_and_return;
910 }
911
912
913
914 for (i = 0; i < nSelectors; i++) {
915 j = 0;
916 while (1) {
917 case BZ_X_SELECTOR_3:
918 s->state = BZ_X_SELECTOR_3;
919 if (get_bits(s, &uc, 1) == FALSE) {
920 retVal = BZ_OK;
921 goto save_state_and_return;
922 }
923 if (uc == 0) {
924 break;
925 }
926 j++;
927 if (j >= nGroups) {
928 retVal = BZ_DATA_ERROR;
929 goto save_state_and_return;
930 }
931 }
932 s->selectorMtf[i] = j;
933 }
934
935 /*--- Undo the MTF values for the selectors. ---*/
936 {
937 unsigned char pos[BZ_N_GROUPS], tmp, v;
938 for (v = 0; v < nGroups; v++) {
939 pos[v] = v;
940 }
941 for (i = 0; i < nSelectors; i++) {
942 v = s->selectorMtf[i];
943 tmp = pos[v];
944 while (v > 0) {
945 pos[v] = pos[v-1];
946 v--;
947 }
948 pos[0] = tmp;
949 s->selector[i] = tmp;
950 }
951 }
952
953 /*--- Now the coding tables ---*/
954 for (t = 0; t < nGroups; t++) {
955 case BZ_X_CODING_1:
956 s->state = BZ_X_CODING_1;
957 if (get_bits(s, &curr, 5) == FALSE) {
958 retVal = BZ_OK;
959 goto save_state_and_return;
960 }
961 for (i = 0; i < alphaSize; i++) {
962 while (TRUE) {
963 if (curr < 1 || curr > 20) {
964 retVal = BZ_DATA_ERROR;
965 goto save_state_and_return;
966 }
967
968 case BZ_X_CODING_2:
969 s->state = BZ_X_CODING_2;
970 if (get_bits(s, &uc, 1) == FALSE) {
971 retVal = BZ_OK;
972 goto save_state_and_return;
973 }
974 if (uc == 0) {
975 break;
976 }
977
978 case BZ_X_CODING_3:
979 s->state = BZ_X_CODING_3;
980 if (get_bits(s, &uc, 1) == FALSE) {
981 retVal = BZ_OK;
982 goto save_state_and_return;
983 }
984 if (uc == 0) {
985 curr++;
986 } else {
987 curr--;
988 }
989 }
990 s->len[t][i] = curr;
991 }
992 }
993
994 /*--- Create the Huffman decoding tables ---*/
995 for (t = 0; t < nGroups; t++) {
996 minLen = 32;
997 maxLen = 0;
998 for (i = 0; i < alphaSize; i++) {
999 if (s->len[t][i] > maxLen) {
1000 maxLen = s->len[t][i];
1001 }
1002 if (s->len[t][i] < minLen) {
1003 minLen = s->len[t][i];
1004 }
1005 }
1006
1007 BZ2_hbCreateDecodeTables (
1008 &(s->limit[t][0]),
1009 &(s->base[t][0]),
1010 &(s->perm[t][0]),
1011 &(s->len[t][0]),
1012 minLen, maxLen, alphaSize
1013 );
1014
1015
1016 s->minLens[t] = minLen;
1017 }
1018
1019 /*--- Now the MTF values ---*/
1020
1021 EOB = s->nInUse+1;
1022 nblockMAX = 100000 * s->blockSize100k;
1023 groupNo = -1;
1024 groupPos = 0;
1025
1026 for (i = 0; i <= 255; i++) {
1027 s->unzftab[i] = 0;
1028 }
1029 /*-- MTF init --*/
1030 {
1031 int ii, jj, kk;
1032 kk = MTFA_SIZE-1;
1033 for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
1034 for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
1035 s->mtfa[kk] = (unsigned char)(ii * MTFL_SIZE + jj);
1036 kk--;
1037 }
1038 s->mtfbase[ii] = kk + 1;
1039 }
1040 }
1041 /*-- end MTF init --*/
1042
1043 nblock = 0;
1044
1045 if (get_mtf_val_init() == FALSE) {
1046 goto save_state_and_return;
1047 }
1048 case BZ_X_MTF_1:
1049 s->state = BZ_X_MTF_1;
1050 if (get_bits(s, &zvec, zn) == FALSE) {
1051 retVal = BZ_OK;
1052 goto save_state_and_return;
1053 }
1054 while (1) {
1055 if (zn > 20 /* the longest code */) {
1056 retVal = BZ_DATA_ERROR;
1057 goto save_state_and_return;
1058 }
1059 if (zvec <= gLimit[zn]) {
1060 break;
1061 }
1062 zn++;
1063
1064 case BZ_X_MTF_2:
1065 s->state = BZ_X_MTF_2;
1066 if (get_bits(s, &zj, 1) == FALSE) {
1067 retVal = BZ_OK;
1068 goto save_state_and_return;
1069 }
1070 zvec = (zvec << 1) | zj;
1071 }
1072 if (zvec - gBase[zn] < 0 || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) {
1073 retVal = BZ_DATA_ERROR;
1074 goto save_state_and_return;
1075 }
1076 nextSym = gPerm[zvec - gBase[zn]];
1077
1078 while (1) {
1079 if (nextSym == EOB) {
1080 break;
1081 }
1082
1083 if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
1084 es = -1;
1085 N = 1;
1086 do {
1087 if (nextSym == BZ_RUNA) {
1088 es = es + (0+1) * N;
1089 } else {
1090 if (nextSym == BZ_RUNB) {
1091 es = es + (1+1) * N;
1092 }
1093 }
1094 N = N * 2;
1095 if (get_mtf_val_init() == FALSE) {
1096 goto save_state_and_return;
1097 }
1098 case BZ_X_MTF_3:
1099 s->state = BZ_X_MTF_3;
1100 if (get_bits(s, &zvec, zn) == FALSE) {
1101 retVal = BZ_OK;
1102 goto save_state_and_return;
1103 }
1104 while (1) {
1105 if (zn > 20 /* the longest code */) {
1106 retVal = BZ_DATA_ERROR;
1107 goto save_state_and_return;
1108 }
1109 if (zvec <= gLimit[zn]) {
1110 break;
1111 }
1112 zn++;
1113
1114 case BZ_X_MTF_4:
1115 s->state = BZ_X_MTF_4;
1116 if (get_bits(s, &zj, 1) == FALSE) {
1117 retVal = BZ_OK;
1118 goto save_state_and_return;
1119 }
1120 zvec = (zvec << 1) | zj;
1121 }
1122 if (zvec - gBase[zn] < 0 || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) {
1123 retVal = BZ_DATA_ERROR;
1124 goto save_state_and_return;
1125
1126 }
1127 nextSym = gPerm[zvec - gBase[zn]];
1128 }
1129 while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
1130
1131 es++;
1132 uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
1133 s->unzftab[uc] += es;
1134
1135 if (s->smallDecompress) {
1136 while (es > 0) {
1137 if (nblock >= nblockMAX) {
1138 retVal = BZ_DATA_ERROR;
1139 goto save_state_and_return;
1140 }
1141 s->ll16[nblock] = (unsigned short)uc;
1142 nblock++;
1143 es--;
1144 }
1145 } else {
1146 while (es > 0) {
1147 if (nblock >= nblockMAX) {
1148 retVal = BZ_DATA_ERROR;
1149 goto save_state_and_return;
1150 }
1151 s->tt[nblock] = (unsigned int)uc;
1152 nblock++;
1153 es--;
1154 }
1155 }
1156 continue;
1157 } else {
1158 if (nblock >= nblockMAX) {
1159 retVal = BZ_DATA_ERROR;
1160 goto save_state_and_return;
1161 }
1162 /*-- uc = MTF ( nextSym-1 ) --*/
1163 {
1164 int ii, jj, kk, pp, lno, off;
1165 unsigned int nn;
1166 nn = (unsigned int)(nextSym - 1);
1167
1168 if (nn < MTFL_SIZE) {
1169 /* avoid general-case expense */
1170 pp = s->mtfbase[0];
1171 uc = s->mtfa[pp+nn];
1172 while (nn > 3) {
1173 int z = pp+nn;
1174 s->mtfa[(z) ] = s->mtfa[(z)-1];
1175 s->mtfa[(z)-1] = s->mtfa[(z)-2];
1176 s->mtfa[(z)-2] = s->mtfa[(z)-3];
1177 s->mtfa[(z)-3] = s->mtfa[(z)-4];
1178 nn -= 4;
1179 }
1180 while (nn > 0) {
1181 s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
1182 }
1183 s->mtfa[pp] = uc;
1184 } else {
1185 /* general case */
1186 lno = nn / MTFL_SIZE;
1187 off = nn % MTFL_SIZE;
1188 pp = s->mtfbase[lno] + off;
1189 uc = s->mtfa[pp];
1190 while (pp > s->mtfbase[lno]) {
1191 s->mtfa[pp] = s->mtfa[pp-1];
1192 pp--;
1193 }
1194 s->mtfbase[lno]++;
1195 while (lno > 0) {
1196 s->mtfbase[lno]--;
1197 s->mtfa[s->mtfbase[lno]] = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
1198 lno--;
1199 }
1200 s->mtfbase[0]--;
1201 s->mtfa[s->mtfbase[0]] = uc;
1202 if (s->mtfbase[0] == 0) {
1203 kk = MTFA_SIZE-1;
1204 for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
1205 for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
1206 s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
1207 kk--;
1208 }
1209 s->mtfbase[ii] = kk + 1;
1210 }
1211 }
1212 }
1213 }
1214 /*-- end uc = MTF ( nextSym-1 ) --*/
1215
1216 s->unzftab[s->seqToUnseq[uc]]++;
1217 if (s->smallDecompress) {
1218 s->ll16[nblock] = (unsigned short)(s->seqToUnseq[uc]);
1219 } else {
1220 s->tt[nblock] = (unsigned int)(s->seqToUnseq[uc]);
1221 }
1222 nblock++;
1223
1224 if (get_mtf_val_init() == FALSE) {
1225 goto save_state_and_return;
1226 }
1227 case BZ_X_MTF_5:
1228 s->state = BZ_X_MTF_5;
1229 if (get_bits(s, &zvec, zn) == FALSE) {
1230 retVal = BZ_OK;
1231 goto save_state_and_return;
1232 }
1233 while (1) {
1234 if (zn > 20 /* the longest code */) {
1235 retVal = BZ_DATA_ERROR;
1236 goto save_state_and_return;
1237 }
1238 if (zvec <= gLimit[zn]) {
1239 break;
1240 }
1241 zn++;
1242
1243 case BZ_X_MTF_6:
1244 s->state = BZ_X_MTF_6;
1245 if (get_bits(s, &zj, 1) == FALSE) {
1246 retVal = BZ_OK;
1247 goto save_state_and_return;
1248 }
1249 zvec = (zvec << 1) | zj;
1250 }
1251 if (zvec - gBase[zn] < 0 || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) {
1252 retVal = BZ_DATA_ERROR;
1253 goto save_state_and_return;
1254 }
1255 nextSym = gPerm[zvec - gBase[zn]];
1256 continue;
1257 }
1258 }
1259
1260 /* Now we know what nblock is, we can do a better sanity
1261 check on s->origPtr.
1262 */
1263 if (s->origPtr < 0 || s->origPtr >= nblock) {
1264 retVal = BZ_DATA_ERROR;
1265 goto save_state_and_return;
1266 }
1267 s->state_out_len = 0;
1268 s->state_out_ch = 0;
1269 s->calculatedBlockCRC = 0xffffffffL;
1270 s->state = BZ_X_OUTPUT;
1271 if (s->verbosity >= 2) {
1272 error_msg("rt+rld");
1273 }
1274
1275 /*-- Set up cftab to facilitate generation of T^(-1) --*/
1276 s->cftab[0] = 0;
1277 for (i = 1; i <= 256; i++) {
1278 s->cftab[i] = s->unzftab[i-1];
1279 }
1280 for (i = 1; i <= 256; i++) {
1281 s->cftab[i] += s->cftab[i-1];
1282 }
1283
1284 if (s->smallDecompress) {
1285
1286 /*-- Make a copy of cftab, used in generation of T --*/
1287 for (i = 0; i <= 256; i++) {
1288 s->cftabCopy[i] = s->cftab[i];
1289 }
1290
1291 /*-- compute the T vector --*/
1292 for (i = 0; i < nblock; i++) {
1293 uc = (unsigned char)(s->ll16[i]);
1294 s->ll16[i] = (unsigned short)(s->cftabCopy[uc] & 0x0000ffff);
1295 if (((i) & 0x1) == 0) {
1296 s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (s->cftabCopy[uc] >> 16);
1297 } else {
1298 s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((s->cftabCopy[uc] >> 16) << 4);
1299 }
1300 s->cftabCopy[uc]++;
1301 }
1302
1303 /*-- Compute T^(-1) by pointer reversal on T --*/
1304 i = s->origPtr;
1305 j = (((unsigned int)s->ll16[i]) |
1306 (((((unsigned int)(s->ll4[(i) >> 1])) >>
1307 (((i) << 2) & 0x4)) & 0xF) << 16));
1308
1309 do {
1310 const int tmp = (((unsigned int)s->ll16[j]) |
1311 (((((unsigned int)(s->ll4[(j) >> 1])) >>
1312 (((j) << 2) & 0x4)) & 0xF) << 16));
1313
1314 s->ll16[j] = (unsigned short)(i & 0x0000ffff);
1315 if (((j) & 0x1) == 0) {
1316 s->ll4[(j) >> 1] = (s->ll4[(j) >> 1] & 0xf0) | (i >> 16);
1317 } else {
1318 s->ll4[(j) >> 1] = (s->ll4[(j) >> 1] & 0x0f) | ((i >> 16) << 4);
1319 }
1320 i = j;
1321 j = tmp;
1322 }
1323 while (i != s->origPtr);
1324 s->tPos = s->origPtr;
1325 s->nblock_used = 0;
1326 if (s->blockRandomised) {
1327 s->rNToGo = 0;
1328 s->rTPos = 0;
1329 s->k0 = bz_get_small(s);
1330 s->nblock_used++;
1331 bz_rand_udp_mask(s);
1332 s->k0 ^= ((s->rNToGo == 1) ? 1 : 0);
1333 } else {
1334 s->k0 = bz_get_small(s);
1335 s->nblock_used++;
1336 }
1337 } else {
1338 /*-- compute the T^(-1) vector --*/
1339 for (i = 0; i < nblock; i++) {
1340 uc = (unsigned char)(s->tt[i] & 0xff);
1341 s->tt[s->cftab[uc]] |= (i << 8);
1342 s->cftab[uc]++;
1343 }
1344
1345 s->tPos = s->tt[s->origPtr] >> 8;
1346 s->nblock_used = 0;
1347 if (s->blockRandomised) {
1348 s->rNToGo = 0;
1349 s->rTPos = 0;
1350 s->k0 = bz_get_fast(s);
1351
1352 s->nblock_used++;
1353 bz_rand_udp_mask(s);
1354 s->k0 ^= ((s->rNToGo == 1) ? 1 : 0);
1355 } else {
1356 s->k0 = bz_get_fast(s);
1357 s->nblock_used++;
1358 }
1359 }
1360
1361 retVal = BZ_OK;
1362 goto save_state_and_return;
1363
1364endhdr_2:
1365 case BZ_X_ENDHDR_2:
1366 s->state = BZ_X_ENDHDR_2;
1367 if (get_bits(s, &uc, 8) == FALSE) {
1368 retVal = BZ_OK;
1369 goto save_state_and_return;
1370 }
1371 if (uc != 0x72) {
1372 retVal = BZ_DATA_ERROR;
1373 goto save_state_and_return;
1374 }
1375
1376 case BZ_X_ENDHDR_3:
1377 s->state = BZ_X_ENDHDR_3;
1378 if (get_bits(s, &uc, 8) == FALSE) {
1379 retVal = BZ_OK;
1380 goto save_state_and_return;
1381 }
1382 if (uc != 0x45) {
1383 retVal = BZ_DATA_ERROR;
1384 goto save_state_and_return;
1385 }
1386
1387 case BZ_X_ENDHDR_4:
1388 s->state = BZ_X_ENDHDR_4;
1389 if (get_bits(s, &uc, 8) == FALSE) {
1390 retVal = BZ_OK;
1391 goto save_state_and_return;
1392 }
1393 if (uc != 0x38) {
1394 retVal = BZ_DATA_ERROR;
1395 goto save_state_and_return;
1396 }
1397
1398 case BZ_X_ENDHDR_5:
1399 s->state = BZ_X_ENDHDR_5;
1400 if (get_bits(s, &uc, 8) == FALSE) {
1401 retVal = BZ_OK;
1402 goto save_state_and_return;
1403 }
1404 if (uc != 0x50) {
1405 retVal = BZ_DATA_ERROR;
1406 goto save_state_and_return;
1407 }
1408
1409 case BZ_X_ENDHDR_6:
1410 s->state = BZ_X_ENDHDR_6;
1411 if (get_bits(s, &uc, 8) == FALSE) {
1412 retVal = BZ_OK;
1413 goto save_state_and_return;
1414 }
1415 if (uc != 0x90) {
1416 retVal = BZ_DATA_ERROR;
1417 goto save_state_and_return;
1418 }
1419 s->storedCombinedCRC = 0;
1420
1421 case BZ_X_CCRC_1:
1422 s->state = BZ_X_CCRC_1;
1423 if (get_bits(s, &uc, 8) == FALSE) {
1424 retVal = BZ_OK;
1425 goto save_state_and_return;
1426 }
1427 s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((unsigned int)uc);
1428 case BZ_X_CCRC_2:
1429 s->state = BZ_X_CCRC_2;
1430 if (get_bits(s, &uc, 8) == FALSE) {
1431 retVal = BZ_OK;
1432 goto save_state_and_return;
1433 }
1434 s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((unsigned int)uc);
1435
1436 case BZ_X_CCRC_3:
1437 s->state = BZ_X_CCRC_3;
1438 if (get_bits(s, &uc, 8) == FALSE) {
1439 retVal = BZ_OK;
1440 goto save_state_and_return;
1441 }
1442 s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((unsigned int)uc);
1443
1444 case BZ_X_CCRC_4:
1445 s->state = BZ_X_CCRC_4;
1446 if (get_bits(s, &uc, 8) == FALSE) {
1447 retVal = BZ_OK;
1448 goto save_state_and_return;
1449 }
1450 s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((unsigned int)uc);
1451
1452 s->state = BZ_X_IDLE;
1453 retVal = BZ_STREAM_END;
1454 goto save_state_and_return;
1455
1456default:
1457 printf("switch val is %d\n", switch_val);
1458 assert_h(4001);
1459 }
1460
1461 assert_h(4002);
1462
1463save_state_and_return:
1464 s->save_i = i;
1465 s->save_j = j;
1466 s->save_t = t;
1467 s->save_alphaSize = alphaSize;
1468 s->save_nGroups = nGroups;
1469 s->save_nSelectors = nSelectors;
1470 s->save_EOB = EOB;
1471 s->save_groupNo = groupNo;
1472 s->save_groupPos = groupPos;
1473 s->save_nextSym = nextSym;
1474 s->save_nblockMAX = nblockMAX;
1475 s->save_nblock = nblock;
1476 s->save_es = es;
1477 s->save_N = N;
1478 s->save_curr = curr;
1479 s->save_zt = zt;
1480 s->save_zn = zn;
1481 s->save_zvec = zvec;
1482 s->save_zj = zj;
1483 s->save_gSel = gSel;
1484 s->save_gMinlen = gMinlen;
1485 s->save_gLimit = gLimit;
1486 s->save_gBase = gBase;
1487 s->save_gPerm = gPerm;
1488
1489 return retVal;
1490}
1491
1492static void *default_bzalloc(void *opaque, int items, int size)
1493{
1494 void *v = xmalloc(items *size);
1495 return v;
1496}
1497
1498static void default_bzfree(void *opaque, void *addr)
1499{
1500 if (addr != NULL) {
1501 free(addr);
1502 }
1503}
1504
1505//int BZ2_bzDecompressInit(bz_stream* strm, int verbosity_level, int small)
1506int BZ2_bzDecompressInit(bz_stream* strm, int small)
1507{
1508 DState* s;
1509
1510 if (sizeof(int) != 4) {
1511 return BZ_CONFIG_ERROR;
1512 }
1513 if (sizeof(short) != 2) {
1514 return BZ_CONFIG_ERROR;
1515 }
1516 if (sizeof(char) != 1) {
1517 return BZ_CONFIG_ERROR;
1518 }
1519 if (strm == NULL) {
1520 return BZ_PARAM_ERROR;
1521 }
1522 if (small != 0 && small != 1) {
1523 return BZ_PARAM_ERROR;
1524 }
1525// if (verbosity_level < 0 || verbosity_level > 4) {
1526// return BZ_PARAM_ERROR;
1527// }
1528 if (strm->bzalloc == NULL) {
1529 strm->bzalloc = default_bzalloc;
1530 }
1531 if (strm->bzfree == NULL) {
1532 strm->bzfree = default_bzfree;
1533 }
1534 s = (strm->bzalloc)(strm->opaque, sizeof(DState), 1);
1535 if (s == NULL) {
1536 return BZ_MEM_ERROR;
1537 }
1538 s->strm = strm;
1539 strm->state = s;
1540 s->state = BZ_X_MAGIC_1;
1541 s->bsLive = 0;
1542 s->bsBuff = 0;
1543 s->calculatedCombinedCRC = 0;
1544 strm->total_in_lo32 = 0;
1545 strm->total_in_hi32 = 0;
1546 strm->total_out_lo32 = 0;
1547 strm->total_out_hi32 = 0;
1548 s->smallDecompress = (unsigned char)small;
1549 s->ll4 = NULL;
1550 s->ll16 = NULL;
1551 s->tt = NULL;
1552 s->currBlockNo = 0;
1553// s->verbosity = verbosity_level;
1554
1555 return BZ_OK;
1556}
1557
1558void bz_seterr(int eee, int *bzerror, bzFile **bzf)
1559{
1560 if (bzerror != NULL) {
1561 *bzerror = eee;
1562 }
1563 if (*bzf != NULL) {
1564 (*bzf)->lastErr = eee;
1565 }
1566}
1567
1568void BZ2_bzReadClose(int *bzerror, void *b)
1569{
1570 bzFile* bzf = (bzFile*)b;
1571
1572 bz_seterr(BZ_OK, bzerror, &bzf);
1573 if (bzf == NULL) {
1574 bz_seterr(BZ_OK, bzerror, &bzf);
1575 return;
1576 }
1577
1578 if (bzf->writing) {
1579 bz_seterr(BZ_SEQUENCE_ERROR, bzerror, &bzf);
1580 return;
1581 }
1582
1583 if (bzf->initialisedOk) {
1584 bz_stream *strm = &(bzf->strm);
1585 DState *s;
1586 if (strm == NULL) {
1587 return;
1588 }
1589 s = strm->state;
1590 if ((s == NULL) || (s->strm != strm)) {
1591 return;
1592 }
1593 if (s->tt != NULL) {
1594 (strm->bzfree)(strm->opaque,(s->tt));
1595 }
1596 if (s->ll16 != NULL) {
1597 (strm->bzfree)(strm->opaque,(s->ll16));
1598 }
1599 if (s->ll4 != NULL) {
1600 (strm->bzfree)(strm->opaque,(s->ll4));
1601 }
1602 (strm->bzfree)(strm->opaque,(strm->state));
1603 strm->state = NULL;
1604 return;
1605 }
1606 free(bzf);
1607}
1608
1609static void unRLE_obuf_to_output_FAST(DState *s)
1610{
1611 unsigned char k1;
1612
1613 if (s->blockRandomised) {
1614 while (1) {
1615 /* try to finish existing run */
1616 while (1) {
1617 if (s->strm->avail_out == 0) {
1618 return;
1619 }
1620 if (s->state_out_len == 0) {
1621 break;
1622 }
1623 *((unsigned char *)(s->strm->next_out)) = s->state_out_ch;
1624 s->calculatedBlockCRC = (s->calculatedBlockCRC << 8) ^
1625 BZ2_crc32Table[(s->calculatedBlockCRC >> 24) ^
1626 ((unsigned char)s->state_out_ch)];
1627 s->state_out_len--;
1628 s->strm->next_out++;
1629 s->strm->avail_out--;
1630 s->strm->total_out_lo32++;
1631 if (s->strm->total_out_lo32 == 0) {
1632 s->strm->total_out_hi32++;
1633 }
1634 }
1635
1636 /* can a new run be started? */
1637 if (s->nblock_used == s->save_nblock+1) {
1638 return;
1639 }
1640 s->state_out_len = 1;
1641 s->state_out_ch = s->k0;
1642 k1 = bz_get_fast(s);
1643 bz_rand_udp_mask(s);
1644 k1 ^= ((s->rNToGo == 1) ? 1 : 0);
1645 s->nblock_used++;
1646 if (s->nblock_used == s->save_nblock+1) {
1647 continue;
1648 }
1649 if (k1 != s->k0) {
1650 s->k0 = k1;
1651 continue;
1652 }
1653
1654 s->state_out_len = 2;
1655 k1 = bz_get_fast(s);
1656 bz_rand_udp_mask(s);
1657 k1 ^= ((s->rNToGo == 1) ? 1 : 0);
1658 s->nblock_used++;
1659 if (s->nblock_used == s->save_nblock+1) {
1660 continue;
1661 }
1662 if (k1 != s->k0) {
1663 s->k0 = k1;
1664 continue;
1665 }
1666 s->state_out_len = 3;
1667 k1 = bz_get_fast(s);
1668 bz_rand_udp_mask(s);
1669 k1 ^= ((s->rNToGo == 1) ? 1 : 0);
1670 s->nblock_used++;
1671 if (s->nblock_used == s->save_nblock+1) {
1672 continue;
1673 }
1674 if (k1 != s->k0) {
1675 s->k0 = k1;
1676 continue;
1677 }
1678
1679 k1 = bz_get_fast(s);
1680 bz_rand_udp_mask(s);
1681 k1 ^= ((s->rNToGo == 1) ? 1 : 0);
1682 s->nblock_used++;
1683 s->state_out_len = ((int)k1) + 4;
1684 s->k0 = bz_get_fast(s);
1685 bz_rand_udp_mask(s);
1686 s->k0 ^= ((s->rNToGo == 1) ? 1 : 0);
1687 s->nblock_used++;
1688 }
1689 } else {
1690 /* restore */
1691 unsigned int c_calculatedBlockCRC = s->calculatedBlockCRC;
1692 unsigned char c_state_out_ch = s->state_out_ch;
1693 int c_state_out_len = s->state_out_len;
1694 int c_nblock_used = s->nblock_used;
1695 int c_k0 = s->k0;
1696 unsigned int *c_tt = s->tt;
1697 unsigned int c_tPos = s->tPos;
1698 char *cs_next_out = s->strm->next_out;
1699 unsigned int cs_avail_out = s->strm->avail_out;
1700 /* end restore */
1701
1702 unsigned int avail_out_INIT = cs_avail_out;
1703 int s_save_nblockPP = s->save_nblock+1;
1704 unsigned int total_out_lo32_old;
1705
1706 while (1) {
1707 /* try to finish existing run */
1708 if (c_state_out_len > 0) {
1709 while (TRUE) {
1710 if (cs_avail_out == 0) {
1711 goto return_notr;
1712 }
1713 if (c_state_out_len == 1) {
1714 break;
1715 }
1716 *((unsigned char *)(cs_next_out)) = c_state_out_ch;
1717 c_calculatedBlockCRC = (c_calculatedBlockCRC << 8) ^
1718 BZ2_crc32Table[(c_calculatedBlockCRC >> 24) ^
1719 ((unsigned char)c_state_out_ch)];
1720 c_state_out_len--;
1721 cs_next_out++;
1722 cs_avail_out--;
1723 }
1724s_state_out_len_eq_one:
1725 {
1726 if (cs_avail_out == 0) {
1727 c_state_out_len = 1;
1728 goto return_notr;
1729 }
1730 *((unsigned char *)(cs_next_out)) = c_state_out_ch;
1731 c_calculatedBlockCRC = (c_calculatedBlockCRC << 8) ^
1732 BZ2_crc32Table[(c_calculatedBlockCRC >> 24) ^
1733 ((unsigned char)c_state_out_ch)];
1734 cs_next_out++;
1735 cs_avail_out--;
1736 }
1737 }
1738 /* can a new run be started? */
1739 if (c_nblock_used == s_save_nblockPP) {
1740 c_state_out_len = 0; goto return_notr;
1741 }
1742 c_state_out_ch = c_k0;
1743 c_tPos = c_tt[c_tPos];
1744 k1 = (unsigned char)(c_tPos & 0xff);
1745 c_tPos >>= 8;
1746
1747 c_nblock_used++;
1748
1749 if (k1 != c_k0) {
1750 c_k0 = k1;
1751 goto s_state_out_len_eq_one;
1752 }
1753
1754 if (c_nblock_used == s_save_nblockPP) {
1755 goto s_state_out_len_eq_one;
1756 }
1757
1758 c_state_out_len = 2;
1759 c_tPos = c_tt[c_tPos];
1760 k1 = (unsigned char)(c_tPos & 0xff);
1761 c_tPos >>= 8;
1762
1763 c_nblock_used++;
1764 if (c_nblock_used == s_save_nblockPP) {
1765 continue;
1766 }
1767 if (k1 != c_k0) {
1768 c_k0 = k1;
1769 continue;
1770 }
1771
1772 c_state_out_len = 3;
1773 c_tPos = c_tt[c_tPos];
1774 k1 = (unsigned char)(c_tPos & 0xff);
1775 c_tPos >>= 8;
1776
1777 c_nblock_used++;
1778 if (c_nblock_used == s_save_nblockPP) {
1779 continue;
1780 }
1781 if (k1 != c_k0) {
1782 c_k0 = k1;
1783 continue;
1784 }
1785
1786 c_tPos = c_tt[c_tPos];
1787 k1 = (unsigned char)(c_tPos & 0xff);
1788 c_tPos >>= 8;
1789
1790 c_nblock_used++;
1791 c_state_out_len = ((int)k1) + 4;
1792
1793 c_tPos = c_tt[c_tPos];
1794 c_k0 = (unsigned char)(c_tPos & 0xff);
1795 c_tPos >>= 8;
1796
1797 c_nblock_used++;
1798 }
1799
1800return_notr:
1801 total_out_lo32_old = s->strm->total_out_lo32;
1802 s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
1803 if (s->strm->total_out_lo32 < total_out_lo32_old) {
1804 s->strm->total_out_hi32++;
1805 }
1806
1807 /* save */
1808 s->calculatedBlockCRC = c_calculatedBlockCRC;
1809 s->state_out_ch = c_state_out_ch;
1810 s->state_out_len = c_state_out_len;
1811 s->nblock_used = c_nblock_used;
1812 s->k0 = c_k0;
1813 s->tt = c_tt;
1814 s->tPos = c_tPos;
1815 s->strm->next_out = cs_next_out;
1816 s->strm->avail_out = cs_avail_out;
1817 /* end save */
1818 }
1819}
1820
1821static void unRLE_obuf_to_output_SMALL(DState *s)
1822{
1823 unsigned char k1;
1824
1825 if (s->blockRandomised) {
1826 while (1) {
1827 /* try to finish existing run */
1828 while (1) {
1829 if (s->strm->avail_out == 0) {
1830 return;
1831 }
1832 if (s->state_out_len == 0) {
1833 break;
1834 }
1835 *((unsigned char *)(s->strm->next_out)) = s->state_out_ch;
1836 s->calculatedBlockCRC = (s->calculatedBlockCRC << 8) ^
1837 BZ2_crc32Table[(s->calculatedBlockCRC >> 24) ^
1838 ((unsigned char)s->state_out_ch)];
1839 s->state_out_len--;
1840 s->strm->next_out++;
1841 s->strm->avail_out--;
1842 s->strm->total_out_lo32++;
1843 if (s->strm->total_out_lo32 == 0) {
1844 s->strm->total_out_hi32++;
1845 }
1846 }
1847
1848 /* can a new run be started? */
1849 if (s->nblock_used == s->save_nblock+1) {
1850 return;
1851 }
1852
1853 s->state_out_len = 1;
1854 s->state_out_ch = s->k0;
1855 k1 = bz_get_small(s);
1856 bz_rand_udp_mask(s);
1857 k1 ^= ((s->rNToGo == 1) ? 1 : 0);
1858 s->nblock_used++;
1859 if (s->nblock_used == s->save_nblock+1) {
1860 continue;
1861 }
1862 if (k1 != s->k0) {
1863 s->k0 = k1;
1864 continue;
1865 }
1866
1867 s->state_out_len = 2;
1868 k1 = bz_get_small(s);
1869 bz_rand_udp_mask(s);
1870 k1 ^= ((s->rNToGo == 1) ? 1 : 0);
1871 s->nblock_used++;
1872 if (s->nblock_used == s->save_nblock+1) {
1873 continue;
1874 }
1875 if (k1 != s->k0) {
1876 s->k0 = k1;
1877 continue;
1878 }
1879
1880 s->state_out_len = 3;
1881 k1 = bz_get_small(s);
1882 bz_rand_udp_mask(s);
1883 k1 ^= ((s->rNToGo == 1) ? 1 : 0);
1884 s->nblock_used++;
1885 if (s->nblock_used == s->save_nblock+1) {
1886 continue;
1887 }
1888 if (k1 != s->k0) {
1889 s->k0 = k1;
1890 continue;
1891 }
1892 k1 = bz_get_small(s);
1893 bz_rand_udp_mask(s);
1894 k1 ^= ((s->rNToGo == 1) ? 1 : 0);
1895 s->nblock_used++;
1896 s->state_out_len = ((int)k1) + 4;
1897 s->k0 = bz_get_small(s);
1898 bz_rand_udp_mask(s);
1899 s->k0 ^= ((s->rNToGo == 1) ? 1 : 0);
1900 s->nblock_used++;
1901 }
1902 } else {
1903 while (1) {
1904 /* try to finish existing run */
1905 while (1) {
1906 if (s->strm->avail_out == 0) {
1907 return;
1908 }
1909 if (s->state_out_len == 0) {
1910 break;
1911 }
1912 *((unsigned char *)(s->strm->next_out)) = s->state_out_ch;
1913 s->calculatedBlockCRC = (s->calculatedBlockCRC << 8) ^
1914 BZ2_crc32Table[(s->calculatedBlockCRC >> 24) ^
1915 ((unsigned char)s->state_out_ch)];
1916 s->state_out_len--;
1917 s->strm->next_out++;
1918 s->strm->avail_out--;
1919 s->strm->total_out_lo32++;
1920 if (s->strm->total_out_lo32 == 0) {
1921 s->strm->total_out_hi32++;
1922 }
1923 }
1924
1925 /* can a new run be started? */
1926 if (s->nblock_used == s->save_nblock+1) {
1927 return;
1928 }
1929
1930 s->state_out_len = 1;
1931 s->state_out_ch = s->k0;
1932 k1 = bz_get_small(s);
1933 s->nblock_used++;
1934 if (s->nblock_used == s->save_nblock+1) {
1935 continue;
1936 }
1937 if (k1 != s->k0) {
1938 s->k0 = k1;
1939 continue;
1940 }
1941
1942 s->state_out_len = 2;
1943 k1 = bz_get_small(s);
1944 s->nblock_used++;
1945 if (s->nblock_used == s->save_nblock+1) {
1946 continue;
1947 }
1948 if (k1 != s->k0) {
1949 s->k0 = k1;
1950 continue;
1951 }
1952
1953 s->state_out_len = 3;
1954 k1 = bz_get_small(s);
1955 s->nblock_used++;
1956 if (s->nblock_used == s->save_nblock+1) {
1957 continue;
1958 }
1959 if (k1 != s->k0) {
1960 s->k0 = k1;
1961 continue;
1962 }
1963
1964 k1 = bz_get_small(s);
1965 s->nblock_used++;
1966 s->state_out_len = ((int)k1) + 4;
1967 s->k0 = bz_get_small(s);
1968 s->nblock_used++;
1969 }
1970 }
1971}
1972
1973int BZ2_bzDecompress(bz_stream *strm)
1974{
1975 DState* s;
1976 if (strm == NULL) {
1977 return BZ_PARAM_ERROR;
1978 }
1979 s = strm->state;
1980 if (s == NULL) {
1981 return BZ_PARAM_ERROR;
1982 }
1983 if (s->strm != strm) {
1984 return BZ_PARAM_ERROR;
1985 }
1986
1987 while (1) {
1988 if (s->state == BZ_X_IDLE) {
1989 return BZ_SEQUENCE_ERROR;
1990 }
1991 if (s->state == BZ_X_OUTPUT) {
1992 if (s->smallDecompress) {
1993 unRLE_obuf_to_output_SMALL(s);
1994 } else {
1995 unRLE_obuf_to_output_FAST(s);
1996 }
1997 if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
1998 s->calculatedBlockCRC = ~(s->calculatedBlockCRC);
1999 if (s->verbosity >= 3) {
2000 error_msg("{0x%x, 0x%x}", s->storedBlockCRC, s->calculatedBlockCRC);
2001 }
2002 if (s->verbosity >= 2) {
2003 error_msg("]");
2004 }
2005 if (s->calculatedBlockCRC != s->storedBlockCRC) {
2006 return BZ_DATA_ERROR;
2007 }
2008 s->calculatedCombinedCRC = (s->calculatedCombinedCRC << 1) | (s->calculatedCombinedCRC >> 31);
2009 s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
2010 s->state = BZ_X_BLKHDR_1;
2011 } else {
2012 return BZ_OK;
2013 }
2014 }
2015 if (s->state >= BZ_X_MAGIC_1) {
2016 int r = BZ2_decompress(s);
2017 if (r == BZ_STREAM_END) {
2018 if (s->verbosity >= 3) {
2019 error_msg("\n combined CRCs: stored = 0x%x, computed = 0x%x",
2020 s->storedCombinedCRC, s->calculatedCombinedCRC );
2021 }
2022 if (s->calculatedCombinedCRC != s->storedCombinedCRC) {
2023 return BZ_DATA_ERROR;
2024 }
2025 return r;
2026 }
2027 if (s->state != BZ_X_OUTPUT) {
2028 return r;
2029 }
2030 }
2031 }
2032
2033 assert_h(6001);
2034
2035 return(0); /*NOTREACHED*/
2036}
2037
2038int BZ2_bzRead(int *bzerror, void *b, void *buf, int len)
2039{
2040 int n, ret;
2041 bzFile *bzf = (bzFile*)b;
2042
2043 bz_seterr(BZ_OK, bzerror, &bzf);
2044
2045 if (bzf == NULL || buf == NULL || len < 0) {
2046 bz_seterr(BZ_PARAM_ERROR, bzerror, &bzf);
2047 return 0;
2048 }
2049
2050 if (bzf->writing) {
2051 bz_seterr(BZ_SEQUENCE_ERROR, bzerror, &bzf);
2052 return 0;
2053 }
2054
2055 if (len == 0) {
2056 bz_seterr(BZ_OK, bzerror, &bzf);
2057 return 0;
2058 }
2059
2060 bzf->strm.avail_out = len;
2061 bzf->strm.next_out = buf;
2062
2063 while (1) {
2064 if (ferror(bzf->handle)) {
2065 bz_seterr(BZ_IO_ERROR, bzerror, &bzf);
2066 return 0;
2067 }
2068 if ((bzf->strm.avail_in == 0) && !myfeof(bzf->handle)) {
2069 n = fread(bzf->buf, sizeof(unsigned char), BZ_MAX_UNUSED, bzf->handle);
2070 if (ferror(bzf->handle)) {
2071 bz_seterr(BZ_IO_ERROR, bzerror, &bzf);
2072 return 0;
2073 }
2074 bzf->bufN = n;
2075 bzf->strm.avail_in = bzf->bufN;
2076 bzf->strm.next_in = bzf->buf;
2077 }
2078
2079 ret = BZ2_bzDecompress(&(bzf->strm));
2080
2081 if ((ret != BZ_OK) && (ret != BZ_STREAM_END)) {
2082 bz_seterr(ret, bzerror, &bzf);
2083 return 0;
2084 }
2085
2086 if ((ret == BZ_OK) && myfeof(bzf->handle) &&
2087 (bzf->strm.avail_in == 0) && (bzf->strm.avail_out > 0)) {
2088 bz_seterr(BZ_UNEXPECTED_EOF, bzerror, &bzf);
2089 return(0);
2090 }
2091
2092 if (ret == BZ_STREAM_END) {
2093 bz_seterr(BZ_STREAM_END, bzerror, &bzf);
2094 return(len - bzf->strm.avail_out);
2095 }
2096 if (bzf->strm.avail_out == 0) {
2097 bz_seterr(BZ_OK, bzerror, &bzf);
2098 return(len);
2099 }
2100 }
2101 return(0); /*not reached*/
2102}
2103
2104void BZ2_bzReadGetUnused(int *bzerror, void *b, void **unused, int *nUnused)
2105{
2106 bzFile *bzf = (bzFile*)b;
2107 if (bzf == NULL) {
2108 bz_seterr(BZ_PARAM_ERROR, bzerror, &bzf);
2109 return;
2110 }
2111 if (bzf->lastErr != BZ_STREAM_END) {
2112 bz_seterr(BZ_SEQUENCE_ERROR, bzerror, &bzf);
2113 return;
2114 }
2115 if (unused == NULL || nUnused == NULL) {
2116 bz_seterr(BZ_PARAM_ERROR, bzerror, &bzf);
2117 return;
2118 }
2119
2120 bz_seterr(BZ_OK, bzerror, &bzf);
2121 *nUnused = bzf->strm.avail_in;
2122 *unused = bzf->strm.next_in;
2123}
2124
2125void *BZ2_bzReadOpen(int *bzerror, FILE *f, int small, void *unused, int nUnused)
2126{
2127 bzFile *bzf = NULL;
2128 int ret;
2129
2130 bz_seterr(BZ_OK, bzerror, &bzf);
2131
2132 if (f == NULL || (small != 0 && small != 1) ||
2133 (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)) ||
2134// (verbosity_level < 0 || verbosity_level > 4) ||
2135 (unused == NULL && nUnused != 0)) {
2136 bz_seterr(BZ_PARAM_ERROR, bzerror, &bzf);
2137 return NULL;
2138 }
2139
2140 if (ferror(f)) {
2141 bz_seterr(BZ_IO_ERROR, bzerror, &bzf);
2142 return NULL;
2143 }
2144
2145 bzf = xmalloc(sizeof(bzFile));
2146 if (bzf == NULL) {
2147 bz_seterr(BZ_MEM_ERROR, bzerror, &bzf);
2148 return NULL;
2149 }
2150 bz_seterr(BZ_OK, bzerror, &bzf);
2151
2152 bzf->initialisedOk = FALSE;
2153 bzf->handle = f;
2154 bzf->bufN = 0;
2155 bzf->writing = FALSE;
2156 bzf->strm.bzalloc = NULL;
2157 bzf->strm.bzfree = NULL;
2158 bzf->strm.opaque = NULL;
2159
2160 while (nUnused > 0) {
2161 bzf->buf[bzf->bufN] = *((unsigned char *)(unused)); bzf->bufN++;
2162 unused = ((void *)( 1 + ((unsigned char *)(unused)) ));
2163 nUnused--;
2164 }
2165
2166 ret = BZ2_bzDecompressInit(&(bzf->strm), small);
2167 if (ret != BZ_OK) {
2168 bz_seterr(ret, bzerror, &bzf);
2169 free(bzf);
2170 return NULL;
2171 }
2172
2173 bzf->strm.avail_in = bzf->bufN;
2174 bzf->strm.next_in = bzf->buf;
2175
2176 bzf->initialisedOk = TRUE;
2177 return bzf;
2178}
2179
2180static unsigned char uncompressStream(FILE *zStream, FILE *stream)
2181{
2182 unsigned char unused[BZ_MAX_UNUSED];
2183 unsigned char *unusedTmp;
2184 unsigned char obuf[5000];
2185 void *bzf = NULL;
2186 int bzerr_dummy;
2187 int bzerr;
2188 int nread;
2189 int nUnused;
2190 int streamNo;
2191 int ret;
2192 int i;
2193
2194 nUnused = 0;
2195 streamNo = 0;
2196
2197 if (ferror(stream)) {
2198 goto errhandler_io;
2199 }
2200 if (ferror(zStream)) {
2201 goto errhandler_io;
2202 }
2203
2204 while(1) {
2205 bzf = BZ2_bzReadOpen(&bzerr, zStream, (int)smallMode, unused, nUnused);
2206 if (bzf == NULL || bzerr != BZ_OK) {
2207 goto errhandler;
2208 }
2209 streamNo++;
2210
2211 while (bzerr == BZ_OK) {
2212 nread = BZ2_bzRead(&bzerr, bzf, obuf, 5000);
2213 if (bzerr == BZ_DATA_ERROR_MAGIC) {
2214 goto errhandler;
2215 }
2216 if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0) {
2217 fwrite(obuf, sizeof(unsigned char), nread, stream);
2218 }
2219 if (ferror(stream)) {
2220 goto errhandler_io;
2221 }
2222 }
2223 if (bzerr != BZ_STREAM_END) {
2224 goto errhandler;
2225 }
2226 BZ2_bzReadGetUnused(&bzerr, bzf, (void **)(&unusedTmp), &nUnused);
2227 if (bzerr != BZ_OK) {
2228 panic("decompress:bzReadGetUnused");
2229 }
2230 for (i = 0; i < nUnused; i++) {
2231 unused[i] = unusedTmp[i];
2232 }
2233 BZ2_bzReadClose(&bzerr, bzf);
2234 if (bzerr != BZ_OK) {
2235 panic("decompress:bzReadGetUnused");
2236 }
2237 if ((nUnused == 0) && myfeof(zStream)) {
2238 break;
2239 }
2240 }
2241
2242 if (ferror(zStream)) {
2243 goto errhandler_io;
2244 }
2245 ret = fclose(zStream);
2246 if (ret == EOF) {
2247 goto errhandler_io;
2248 }
2249 if (ferror(stream)) {
2250 goto errhandler_io;
2251 }
2252 ret = fflush(stream);
2253 if (ret != 0) {
2254 goto errhandler_io;
2255 }
2256 if (stream != stdout) {
2257 ret = fclose(stream);
2258 if (ret == EOF) {
2259 goto errhandler_io;
2260 }
2261 }
2262// if (verbosity_level >= 2) {
2263// fprintf(stderr,"\n ");
2264// }
2265 return TRUE;
2266
2267errhandler:
2268 BZ2_bzReadClose ( &bzerr_dummy, bzf );
2269 switch (bzerr) {
2270 case BZ_CONFIG_ERROR:
2271 error_msg("bzip2: I'm not configured correctly for this platform!\n"
2272 "\tI require Int32, Int16 and Char to have sizes\n"
2273 "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
2274 "\tProbably you can fix this by defining them correctly,\n"
2275 "\tand recompiling. Bye!\n" );
2276 exit(3);
2277 case BZ_IO_ERROR:
2278errhandler_io:
2279 error_msg("\n%s: I/O or other error, bailing out. "
2280 "Possible reason follows.\n", progName);
2281 perror(progName);
2282 cleanUpAndFail(1);
2283 case BZ_DATA_ERROR:
2284 error_msg("\n%s: Data integrity error when decompressing.\n", progName);
2285 cleanUpAndFail(2);
2286 case BZ_MEM_ERROR:
2287 error_msg("\n%s: couldn't allocate enough memory\n", progName);
2288 cleanUpAndFail(1);
2289 case BZ_UNEXPECTED_EOF:
2290 error_msg("\n%s: Compressed file ends unexpectedly;\n\t"
2291 "perhaps it is corrupted? *Possible* reason follows.\n", progName);
2292 perror(progName);
2293 cleanUpAndFail(2);
2294 case BZ_DATA_ERROR_MAGIC:
2295 if (zStream != stdin) {
2296 fclose(zStream);
2297 }
2298 if (stream != stdout) {
2299 fclose(stream);
2300 }
2301 if (streamNo == 1) {
2302 return FALSE;
2303 } else {
2304 if (noisy) {
2305 error_msg("\n%s: %s: trailing garbage after EOF ignored\n", progName, inName );
2306 }
2307 return TRUE;
2308 }
2309 default:
2310 panic ( "decompress:unexpected error" );
2311 }
2312
2313 panic("decompress:end");
2314 return(TRUE); /*notreached*/
2315}
2316
2317int bunzip2_main(int argc, char **argv)
2318{
2319 FILE *src_stream;
2320 FILE *dst_stream;
2321 char *save_name;
2322 char *save_name_ptr;
2323 if (argc != 2) {
2324 show_usage();
2325 }
2326 src_stream = xfopen(argv[1], "r");
2327 save_name = strdup(argv[1]);
2328 save_name_ptr = strrchr(save_name, '.');
2329 if (save_name_ptr == NULL) {
2330 return(FALSE);
2331 }
2332 if (strcmp(save_name_ptr, ".bz2") != 0) {
2333 error_msg("Invalid extension, expected .bz2");
2334 }
2335 *save_name_ptr = '\0';
2336 dst_stream = xfopen(save_name, "w");
2337 uncompressStream(src_stream, dst_stream);
2338
2339 return(TRUE);
2340}
diff --git a/busybox.c b/busybox.c
deleted file mode 100644
index 33efb5d84..000000000
--- a/busybox.c
+++ /dev/null
@@ -1,181 +0,0 @@
1/* vi: set sw=4 ts=4: */
2#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
5#include <errno.h>
6#include <stdlib.h>
7#include "busybox.h"
8#ifdef BB_LOCALE_SUPPORT
9#include <locale.h>
10#endif
11
12int been_there_done_that = 0; /* Also used in applets.c */
13const char *applet_name;
14
15#ifdef BB_FEATURE_INSTALLER
16/*
17 * directory table
18 * this should be consistent w/ the enum, busybox.h::Location,
19 * or else...
20 */
21static char* install_dir[] = {
22 "/",
23 "/bin",
24 "/sbin",
25 "/usr/bin",
26 "/usr/sbin",
27};
28
29/* abstract link() */
30typedef int (*__link_f)(const char *, const char *);
31
32/*
33 * Where in the filesystem is this busybox?
34 * [return]
35 * malloc'd string w/ full pathname of busybox's location
36 * NULL on failure
37 */
38static char *busybox_fullpath()
39{
40 return xreadlink("/proc/self/exe");
41}
42
43/* create (sym)links for each applet */
44static void install_links(const char *busybox, int use_symbolic_links)
45{
46 __link_f Link = link;
47
48 char *fpc;
49 int i;
50 int rc;
51
52 if (use_symbolic_links)
53 Link = symlink;
54
55 for (i = 0; applets[i].name != NULL; i++) {
56 fpc = concat_path_file(
57 install_dir[applets[i].location], applets[i].name);
58 rc = Link(busybox, fpc);
59 if (rc!=0 && errno!=EEXIST) {
60 perror_msg("%s", fpc);
61 }
62 free(fpc);
63 }
64}
65
66#endif /* BB_FEATURE_INSTALLER */
67
68int main(int argc, char **argv)
69{
70 const char *s;
71
72 applet_name = argv[0];
73
74 if (applet_name[0] == '-')
75 applet_name++;
76
77 for (s = applet_name; *s != '\0';) {
78 if (*s++ == '/')
79 applet_name = s;
80 }
81
82#ifdef BB_LOCALE_SUPPORT
83#ifdef BB_INIT
84 if(getpid()!=1) /* Do not set locale for `init' */
85#endif
86 {
87 setlocale(LC_ALL, "");
88 }
89#endif
90
91 run_applet_by_name(applet_name, argc, argv);
92 error_msg_and_die("applet not found");
93}
94
95
96int busybox_main(int argc, char **argv)
97{
98 int col = 0, len, i;
99
100#ifdef BB_FEATURE_INSTALLER
101 /*
102 * This style of argument parsing doesn't scale well
103 * in the event that busybox starts wanting more --options.
104 * If someone has a cleaner approach, by all means implement it.
105 */
106 if (argc > 1 && (strcmp(argv[1], "--install") == 0)) {
107 int use_symbolic_links = 0;
108 int rc = 0;
109 char *busybox;
110
111 /* to use symlinks, or not to use symlinks... */
112 if (argc > 2) {
113 if ((strcmp(argv[2], "-s") == 0)) {
114 use_symbolic_links = 1;
115 }
116 }
117
118 /* link */
119 busybox = busybox_fullpath();
120 if (busybox) {
121 install_links(busybox, use_symbolic_links);
122 free(busybox);
123 } else {
124 rc = 1;
125 }
126 return rc;
127 }
128#endif /* BB_FEATURE_INSTALLER */
129
130 argc--;
131
132 /* If we've already been here once, exit now */
133 if (been_there_done_that == 1 || argc < 1) {
134 const struct BB_applet *a = applets;
135
136 fprintf(stderr, "%s\n\n"
137 "Usage: busybox [function] [arguments]...\n"
138 " or: [function] [arguments]...\n\n"
139 "\tBusyBox is a multi-call binary that combines many common Unix\n"
140 "\tutilities into a single executable. Most people will create a\n"
141 "\tlink to busybox for each function they wish to use, and BusyBox\n"
142 "\twill act like whatever it was invoked as.\n"
143 "\nCurrently defined functions:\n", full_version);
144
145 while (a->name != 0) {
146 col +=
147 fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "),
148 (a++)->name);
149 if (col > 60 && a->name != 0) {
150 fprintf(stderr, ",\n");
151 col = 0;
152 }
153 }
154 fprintf(stderr, "\n\n");
155 exit(0);
156 }
157
158 /* Flag that we've been here already */
159 been_there_done_that = 1;
160
161 /* Move the command line down a notch */
162 len = argv[argc] + strlen(argv[argc]) - argv[1];
163 memmove(argv[0], argv[1], len);
164 memset(argv[0] + len, 0, argv[1] - argv[0]);
165
166 /* Fix up the argv pointers */
167 len = argv[1] - argv[0];
168 memmove(argv, argv + 1, sizeof(char *) * (argc + 1));
169 for (i = 0; i < argc; i++)
170 argv[i] -= len;
171
172 return (main(argc, argv));
173}
174
175/*
176Local Variables:
177c-file-style: "linux"
178c-basic-offset: 4
179tab-width: 4
180End:
181*/
diff --git a/busybox.h b/busybox.h
deleted file mode 100644
index f79dac8c8..000000000
--- a/busybox.h
+++ /dev/null
@@ -1,106 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Busybox main internal header file
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
21 * Permission has been granted to redistribute this code under the GPL.
22 *
23 */
24#ifndef _BB_INTERNAL_H_
25#define _BB_INTERNAL_H_ 1
26
27#include "Config.h"
28
29#include <stdio.h>
30#include <stdarg.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33
34#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")"
35
36#ifdef DMALLOC
37#include "dmalloc.h"
38#endif
39
40#include <features.h>
41
42
43enum Location {
44 _BB_DIR_ROOT = 0,
45 _BB_DIR_BIN,
46 _BB_DIR_SBIN,
47 _BB_DIR_USR_BIN,
48 _BB_DIR_USR_SBIN
49};
50
51struct BB_applet {
52 const char* name;
53 int (*main)(int argc, char** argv);
54 enum Location location;
55};
56/* From busybox.c */
57extern const struct BB_applet applets[];
58
59/* Automagically pull in all the applet function prototypes and
60 * applet usage strings. These are all of the form:
61 * extern int foo_main(int argc, char **argv);
62 * extern const char foo_usage[];
63 * These are all autogenerated from the set of currently defined applets.
64 */
65#define PROTOTYPES
66#include "applets.h"
67#undef PROTOTYPES
68
69#ifdef BB_FEATURE_BUFFERS_GO_ON_STACK
70#define RESERVE_BB_BUFFER(buffer,len) char buffer[len]
71#define RESERVE_BB_UBUFFER(buffer,len) unsigned char buffer[len]
72#define RELEASE_BB_BUFFER(buffer) ((void)0)
73#else
74#ifdef BB_FEATURE_BUFFERS_GO_IN_BSS
75#define RESERVE_BB_BUFFER(buffer,len) static char buffer[len]
76#define RESERVE_BB_UBUFFER(buffer,len) static unsigned char buffer[len]
77#define RELEASE_BB_BUFFER(buffer) ((void)0)
78#else
79#define RESERVE_BB_BUFFER(buffer,len) char *buffer=xmalloc(len)
80#define RESERVE_BB_UBUFFER(buffer,len) unsigned char *buffer=xmalloc(len)
81#define RELEASE_BB_BUFFER(buffer) free (buffer)
82#endif
83#endif
84
85
86/* Bit map related macros -- libc5 doens't provide these... sigh. */
87#ifndef setbit
88#define NBBY CHAR_BIT
89#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
90#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
91#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
92#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
93#endif
94
95#ifndef RB_POWER_OFF
96/* Stop system and switch power off if possible. */
97#define RB_POWER_OFF 0x4321fedc
98#endif
99
100
101/* Pull in the utility routines from libbb */
102#include "libbb/libbb.h"
103
104
105
106#endif /* _BB_INTERNAL_H_ */
diff --git a/busybox.mkll b/busybox.mkll
deleted file mode 100755
index 4e15e1611..000000000
--- a/busybox.mkll
+++ /dev/null
@@ -1,24 +0,0 @@
1#!/bin/sh
2# Make busybox links list file.
3
4# input $1: full path to Config.h
5# input $2: full path to applets.h
6# output (stdout): list of pathnames that should be linked to busybox
7
8# Maintainer: Larry Doolittle <ldoolitt@recycle.lbl.gov>
9
10export LC_ALL=POSIX
11export LC_CTYPE=POSIX
12
13CONFIG_H=${1:-Config.h}
14APPLETS_H=${2:-applets.h}
15gcc -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H |
16 awk '/^[ \t]*LINK/{
17 dir=substr($2,8)
18 gsub("_","/",dir)
19 if(dir=="/ROOT") dir=""
20 file=$3
21 gsub("\"","",file)
22 if (file=="busybox") next
23 print tolower(dir) "/" file
24 }'
diff --git a/busybox.sh b/busybox.sh
deleted file mode 100755
index 9ab0f4bdb..000000000
--- a/busybox.sh
+++ /dev/null
@@ -1,16 +0,0 @@
1#!/bin/sh
2
3export LC_ALL=POSIX
4export LC_CTYPE=POSIX
5
6RAW=` \
7 $CC -E -dM ${1:-Config.h} | \
8 sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1.c/gp;' \
9 | tr A-Z a-z | sort
10`
11test "${RAW}" != "" || exit
12if [ -d "$BB_SRC_DIR" ]; then cd $BB_SRC_DIR; fi
13# By running $RAW through "ls", we avoid listing
14# source files that don't exist.
15ls $RAW 2>/dev/null | tr '\n' ' '
16
diff --git a/busybox.spec b/busybox.spec
deleted file mode 100644
index cce20583e..000000000
--- a/busybox.spec
+++ /dev/null
@@ -1,44 +0,0 @@
1%define name busybox
2%define epoch 0
3%define version 0.61.pre
4%define release %(date -I | sed -e 's/-/_/g')
5%define serial 1
6
7Name: %{name}
8#Epoch: %{epoch}
9Version: %{version}
10Release: %{release}
11Serial: %{serial}
12Copyright: GPL
13Group: System/Utilities
14Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary.
15URL: http://busybox.lineo.com/
16Source: ftp://oss.lineo.com/busybox/%{name}-%{version}.tar.gz
17Buildroot: /var/tmp/%{name}-%{version}
18Packager : Erik Andersen <andersen@lineo.com>
19
20%Description
21BusyBox combines tiny versions of many common UNIX utilities into a single
22small executable. It provides minimalist replacements for most of the utilities
23you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
24tar, etc. BusyBox provides a fairly complete POSIX environment for any small
25or emdedded system. The utilities in BusyBox generally have fewer options then
26their full featured GNU cousins; however, the options that are provided behave
27very much like their GNU counterparts.
28
29%Prep
30%setup -q -n %{name}-%{version}
31
32%Build
33make
34
35%Install
36rm -rf $RPM_BUILD_ROOT
37make PREFIX=$RPM_BUILD_ROOT install
38
39%Clean
40rm -rf $RPM_BUILD_ROOT
41
42%Files
43%defattr(-,root,root)
44/
diff --git a/cat.c b/cat.c
deleted file mode 100644
index aa8528d6a..000000000
--- a/cat.c
+++ /dev/null
@@ -1,53 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini Cat implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <stdlib.h>
25#include <string.h>
26#include "busybox.h"
27
28extern int cat_main(int argc, char **argv)
29{
30 int status = EXIT_SUCCESS;
31
32 if (argc == 1) {
33 print_file(stdin);
34 return status;
35 }
36
37 while (--argc > 0) {
38 if(!(strcmp(*++argv, "-"))) {
39 print_file(stdin);
40 } else if (print_file_by_name(*argv) == FALSE) {
41 status = EXIT_FAILURE;
42 }
43 }
44 return status;
45}
46
47/*
48Local Variables:
49c-file-style: "linux"
50c-basic-offset: 4
51tab-width: 4
52End:
53*/
diff --git a/chgrp.c b/chgrp.c
deleted file mode 100644
index fbc1036a8..000000000
--- a/chgrp.c
+++ /dev/null
@@ -1,91 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini chown/chmod/chgrp implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include "busybox.h"
30
31/* Don't use lchown for libc5 or glibc older then 2.1.x */
32#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
33#define lchown chown
34#endif
35
36
37static long gid;
38
39static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
40{
41 if (lchown(fileName, statbuf->st_uid, (gid == -1) ? statbuf->st_gid : gid) == 0) {
42 return (TRUE);
43 }
44 perror(fileName);
45 return (FALSE);
46}
47
48int chgrp_main(int argc, char **argv)
49{
50 int opt;
51 int recursiveFlag = FALSE;
52 char *p=NULL;
53
54 /* do normal option parsing */
55 while ((opt = getopt(argc, argv, "R")) > 0) {
56 switch (opt) {
57 case 'R':
58 recursiveFlag = TRUE;
59 break;
60 default:
61 show_usage();
62 }
63 }
64
65 if (argc > optind && argc > 2 && argv[optind]) {
66 /* Find the selected group */
67 gid = strtoul(argv[optind], &p, 10); /* maybe it's already numeric */
68 if (argv[optind] == p)
69 gid = my_getgrnam(argv[optind]);
70 } else {
71 error_msg_and_die(too_few_args);
72 }
73
74 /* Ok, ready to do the deed now */
75 while (++optind < argc) {
76 if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE,
77 fileAction, fileAction, NULL) == FALSE) {
78 return EXIT_FAILURE;
79 }
80 }
81 return EXIT_SUCCESS;
82
83}
84
85/*
86Local Variables:
87c-file-style: "linux"
88c-basic-offset: 4
89tab-width: 4
90End:
91*/
diff --git a/chmod.c b/chmod.c
deleted file mode 100644
index 9139b3f4d..000000000
--- a/chmod.c
+++ /dev/null
@@ -1,85 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini chown/chmod/chgrp implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include <getopt.h>
30#include "busybox.h"
31
32static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
33{
34 if (!parse_mode((char *)junk, &(statbuf->st_mode)))
35 error_msg_and_die("internal error");
36 if (chmod(fileName, statbuf->st_mode) == 0)
37 return (TRUE);
38 perror(fileName);
39 return (FALSE);
40}
41
42int chmod_main(int argc, char **argv)
43{
44 int i;
45 int opt;
46 int recursiveFlag = FALSE;
47
48 /* do normal option parsing */
49 while ((opt = getopt(argc, argv, "R")) > 0) {
50 switch (opt) {
51 case 'R':
52 recursiveFlag = TRUE;
53 break;
54 default:
55 show_usage();
56 }
57 }
58
59 if (argc > optind && argc > 2 && argv[optind]) {
60 /* Parse the specified mode */
61 mode_t mode;
62 if (parse_mode(argv[optind], &mode) == FALSE) {
63 error_msg_and_die( "unknown mode: %s", argv[optind]);
64 }
65 } else {
66 error_msg_and_die(too_few_args);
67 }
68
69 /* Ok, ready to do the deed now */
70 for (i = optind + 1; i < argc; i++) {
71 if (recursive_action (argv[i], recursiveFlag, FALSE, FALSE, fileAction,
72 fileAction, argv[optind]) == FALSE) {
73 return EXIT_FAILURE;
74 }
75 }
76 return EXIT_SUCCESS;
77}
78
79/*
80Local Variables:
81c-file-style: "linux"
82c-basic-offset: 4
83tab-width: 4
84End:
85*/
diff --git a/chown.c b/chown.c
deleted file mode 100644
index d1e52deda..000000000
--- a/chown.c
+++ /dev/null
@@ -1,113 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini chown/chmod/chgrp implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include "busybox.h"
30
31/* Don't use lchown for libc5 or glibc older then 2.1.x */
32#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
33#define lchown chown
34#endif
35
36static long uid;
37static long gid;
38
39static int (*chown_func)(const char *, __uid_t, __gid_t) = chown;
40
41static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
42{
43 if (chown_func(fileName, uid, (gid == -1) ? statbuf->st_gid : gid) == 0) {
44 return (TRUE);
45 }
46 perror(fileName);
47 return (FALSE);
48}
49
50int chown_main(int argc, char **argv)
51{
52 int opt;
53 int recursiveFlag = FALSE,
54 noderefFlag = FALSE;
55 char *groupName=NULL;
56 char *p=NULL;
57
58 /* do normal option parsing */
59 while ((opt = getopt(argc, argv, "Rh")) > 0) {
60 switch (opt) {
61 case 'R':
62 recursiveFlag = TRUE;
63 break;
64 case 'h':
65 noderefFlag = TRUE;
66 break;
67 default:
68 show_usage();
69 }
70 }
71
72 if (noderefFlag) chown_func = lchown;
73
74 if (argc > optind && argc > 2 && argv[optind]) {
75 /* First, check if there is a group name here */
76 groupName = strchr(argv[optind], '.');
77 if (groupName == NULL)
78 groupName = strchr(argv[optind], ':');
79 if (groupName) {
80 *groupName++ = '\0';
81 gid = strtoul(groupName, &p, 10);
82 if (groupName == p)
83 gid = my_getgrnam(groupName);
84 } else {
85 gid = -1;
86 }
87 /* Now check for the username */
88 uid = strtoul(argv[optind], &p, 10); /* Is is numeric? */
89 if (argv[optind] == p) {
90 uid = my_getpwnam(argv[optind]);
91 }
92 } else {
93 error_msg_and_die(too_few_args);
94 }
95
96 /* Ok, ready to do the deed now */
97 while (++optind < argc) {
98 if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE,
99 fileAction, fileAction, NULL) == FALSE) {
100 return EXIT_FAILURE;
101 }
102 }
103 return EXIT_SUCCESS;
104
105}
106
107/*
108Local Variables:
109c-file-style: "linux"
110c-basic-offset: 4
111tab-width: 4
112End:
113*/
diff --git a/chroot.c b/chroot.c
deleted file mode 100644
index de6a2ea50..000000000
--- a/chroot.c
+++ /dev/null
@@ -1,75 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini chroot implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <errno.h>
29#include "busybox.h"
30
31int chroot_main(int argc, char **argv)
32{
33 char *prog;
34
35 if ((argc < 2) || (**(argv + 1) == '-')) {
36 show_usage();
37 }
38 argc--;
39 argv++;
40
41 if (chroot(*argv) || (chdir("/"))) {
42 perror_msg_and_die("cannot change root directory to %s", *argv);
43 }
44
45 argc--;
46 argv++;
47 if (argc >= 1) {
48 prog = *argv;
49 execvp(*argv, argv);
50 } else {
51#if defined shell_main && defined BB_FEATURE_SH_STANDALONE_SHELL
52 char shell[] = "/bin/sh";
53 char *shell_argv[2] = { shell, NULL };
54 applet_name = shell;
55 shell_main(1, shell_argv);
56 return EXIT_SUCCESS;
57#else
58 prog = getenv("SHELL");
59 if (!prog)
60 prog = "/bin/sh";
61 execlp(prog, prog, NULL);
62#endif
63 }
64 perror_msg_and_die("cannot execute %s", prog);
65
66}
67
68
69/*
70Local Variables:
71c-file-style: "linux"
72c-basic-offset: 4
73tab-width: 4
74End:
75*/
diff --git a/chvt.c b/chvt.c
deleted file mode 100644
index c76e9c780..000000000
--- a/chvt.c
+++ /dev/null
@@ -1,43 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * chvt.c - aeb - 940227 - Change virtual terminal
4 *
5 * busyboxed by Erik Andersen
6 */
7
8/* getopt not needed */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <fcntl.h>
13#include <sys/types.h>
14#include <sys/ioctl.h>
15#include "busybox.h"
16
17/* From <linux/vt.h> */
18static const int VT_ACTIVATE = 0x5606; /* make vt active */
19static const int VT_WAITACTIVE = 0x5607; /* wait for vt active */
20
21int chvt_main(int argc, char **argv)
22{
23 int fd, num;
24
25 if ((argc != 2) || (**(argv + 1) == '-'))
26 show_usage();
27 fd = get_console_fd("/dev/console");
28 num = atoi(argv[1]);
29 if (ioctl(fd, VT_ACTIVATE, num))
30 perror_msg_and_die("VT_ACTIVATE");
31 if (ioctl(fd, VT_WAITACTIVE, num))
32 perror_msg_and_die("VT_WAITACTIVE");
33 return EXIT_SUCCESS;
34}
35
36
37/*
38Local Variables:
39c-file-style: "linux"
40c-basic-offset: 4
41tab-width: 4
42End:
43*/
diff --git a/clear.c b/clear.c
deleted file mode 100644
index 503bafa16..000000000
--- a/clear.c
+++ /dev/null
@@ -1,34 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini clear implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include "busybox.h"
28
29
30extern int clear_main(int argc, char **argv)
31{
32 printf("\033[H\033[J");
33 return EXIT_SUCCESS;
34}
diff --git a/cmdedit.c b/cmdedit.c
deleted file mode 100644
index 16ec2f823..000000000
--- a/cmdedit.c
+++ /dev/null
@@ -1,1521 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Termios command line History and Editting.
4 *
5 * Copyright (c) 1986-2001 may safely be consumed by a BSD or GPL license.
6 * Written by: Vladimir Oleynik <dzo@simtreas.ru>
7 *
8 * Used ideas:
9 * Adam Rogoyski <rogoyski@cs.utexas.edu>
10 * Dave Cinege <dcinege@psychosis.com>
11 * Jakub Jelinek (c) 1995
12 * Erik Andersen <andersee@debian.org> (Majorly adjusted for busybox)
13 *
14 * This code is 'as is' with no warranty.
15 *
16 *
17 */
18
19/*
20 Usage and Known bugs:
21 Terminal key codes are not extensive, and more will probably
22 need to be added. This version was created on Debian GNU/Linux 2.x.
23 Delete, Backspace, Home, End, and the arrow keys were tested
24 to work in an Xterm and console. Ctrl-A also works as Home.
25 Ctrl-E also works as End.
26
27 Small bugs (simple effect):
28 - not true viewing if terminal size (x*y symbols) less
29 size (prompt + editor`s line + 2 symbols)
30 - not true viewing if length prompt less terminal width
31 */
32
33
34#include <stdio.h>
35#include <errno.h>
36#include <unistd.h>
37#include <stdlib.h>
38#include <string.h>
39#include <sys/ioctl.h>
40#include <ctype.h>
41#include <signal.h>
42#include <limits.h>
43
44#include "busybox.h"
45
46#ifdef BB_LOCALE_SUPPORT
47#define Isprint(c) isprint((c))
48#else
49#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') )
50#endif
51
52#ifndef TEST
53
54#define D(x)
55
56#else
57
58#define BB_FEATURE_COMMAND_EDITING
59#define BB_FEATURE_COMMAND_TAB_COMPLETION
60#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
61#define BB_FEATURE_NONPRINTABLE_INVERSE_PUT
62#define BB_FEATURE_CLEAN_UP
63
64#define D(x) x
65
66#endif /* TEST */
67
68#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
69#include <dirent.h>
70#include <sys/stat.h>
71#endif
72
73#ifdef BB_FEATURE_COMMAND_EDITING
74
75#ifndef BB_FEATURE_COMMAND_TAB_COMPLETION
76#undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
77#endif
78
79#if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(BB_FEATURE_SH_FANCY_PROMPT)
80#define BB_FEATURE_GETUSERNAME_AND_HOMEDIR
81#endif
82
83#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
84# ifndef TEST
85# include "pwd_grp/pwd.h"
86# else
87# include <pwd.h>
88# endif /* TEST */
89#endif /* advanced FEATURES */
90
91
92
93struct history {
94 char *s;
95 struct history *p;
96 struct history *n;
97};
98
99/* Maximum length of the linked list for the command line history */
100static const int MAX_HISTORY = 15;
101
102/* First element in command line list */
103static struct history *his_front = NULL;
104
105/* Last element in command line list */
106static struct history *his_end = NULL;
107
108
109#include <termios.h>
110#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
111#define getTermSettings(fd,argp) tcgetattr(fd, argp);
112
113/* Current termio and the previous termio before starting sh */
114static struct termios initial_settings, new_settings;
115
116
117static
118volatile int cmdedit_termw = 80; /* actual terminal width */
119static int history_counter = 0; /* Number of commands in history list */
120static
121volatile int handlers_sets = 0; /* Set next bites: */
122
123enum {
124 SET_ATEXIT = 1, /* when atexit() has been called
125 and get euid,uid,gid to fast compare */
126 SET_WCHG_HANDLERS = 2, /* winchg signal handler */
127 SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */
128};
129
130
131static int cmdedit_x; /* real x terminal position */
132static int cmdedit_y; /* pseudoreal y terminal position */
133static int cmdedit_prmt_len; /* lenght prompt without colores string */
134
135static int cursor; /* required global for signal handler */
136static int len; /* --- "" - - "" - -"- --""-- --""--- */
137static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */
138static
139#ifndef BB_FEATURE_SH_FANCY_PROMPT
140 const
141#endif
142char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */
143
144#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
145static char *user_buf = "";
146static char *home_pwd_buf = "";
147static int my_euid;
148#endif
149
150#ifdef BB_FEATURE_SH_FANCY_PROMPT
151static char *hostname_buf = "";
152static int num_ok_lines = 1;
153#endif
154
155
156#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
157
158#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
159static int my_euid;
160#endif
161
162static int my_uid;
163static int my_gid;
164
165#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
166
167/* It seems that libc5 doesn't know what a sighandler_t is... */
168#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
169typedef void (*sighandler_t) (int);
170#endif
171
172static void cmdedit_setwidth(int w, int redraw_flg);
173
174static void win_changed(int nsig)
175{
176 struct winsize win = { 0, 0, 0, 0 };
177 static sighandler_t previous_SIGWINCH_handler; /* for reset */
178
179 /* emulate || signal call */
180 if (nsig == -SIGWINCH || nsig == SIGWINCH) {
181 ioctl(0, TIOCGWINSZ, &win);
182 if (win.ws_col > 0) {
183 cmdedit_setwidth(win.ws_col, nsig == SIGWINCH);
184 }
185 }
186 /* Unix not all standart in recall signal */
187
188 if (nsig == -SIGWINCH) /* save previous handler */
189 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
190 else if (nsig == SIGWINCH) /* signaled called handler */
191 signal(SIGWINCH, win_changed); /* set for next call */
192 else /* nsig == 0 */
193 /* set previous handler */
194 signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */
195}
196
197static void cmdedit_reset_term(void)
198{
199 if ((handlers_sets & SET_RESET_TERM) != 0) {
200/* sparc and other have broken termios support: use old termio handling. */
201 setTermSettings(fileno(stdin), (void *) &initial_settings);
202 handlers_sets &= ~SET_RESET_TERM;
203 }
204 if ((handlers_sets & SET_WCHG_HANDLERS) != 0) {
205 /* reset SIGWINCH handler to previous (default) */
206 win_changed(0);
207 handlers_sets &= ~SET_WCHG_HANDLERS;
208 }
209 fflush(stdout);
210#ifdef BB_FEATURE_CLEAN_UP
211 if (his_front) {
212 struct history *n;
213
214 while (his_front != his_end) {
215 n = his_front->n;
216 free(his_front->s);
217 free(his_front);
218 his_front = n;
219 }
220 }
221#endif
222}
223
224
225/* special for recount position for scroll and remove terminal margin effect */
226static void cmdedit_set_out_char(int next_char)
227{
228
229 int c = (int)((unsigned char) command_ps[cursor]);
230
231 if (c == 0)
232 c = ' '; /* destroy end char? */
233#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
234 if (!Isprint(c)) { /* Inverse put non-printable characters */
235 if (c >= 128)
236 c -= 128;
237 if (c < ' ')
238 c += '@';
239 if (c == 127)
240 c = '?';
241 printf("\033[7m%c\033[0m", c);
242 } else
243#endif
244 putchar(c);
245 if (++cmdedit_x >= cmdedit_termw) {
246 /* terminal is scrolled down */
247 cmdedit_y++;
248 cmdedit_x = 0;
249
250 if (!next_char)
251 next_char = ' ';
252 /* destroy "(auto)margin" */
253 putchar(next_char);
254 putchar('\b');
255 }
256 cursor++;
257}
258
259/* Move to end line. Bonus: rewrite line from cursor */
260static void input_end(void)
261{
262 while (cursor < len)
263 cmdedit_set_out_char(0);
264}
265
266/* Go to the next line */
267static void goto_new_line(void)
268{
269 input_end();
270 if (cmdedit_x)
271 putchar('\n');
272}
273
274
275static inline void out1str(const char *s)
276{
277 fputs(s, stdout);
278}
279static inline void beep(void)
280{
281 putchar('\007');
282}
283
284/* Move back one charactor */
285/* special for slow terminal */
286static void input_backward(int num)
287{
288 if (num > cursor)
289 num = cursor;
290 cursor -= num; /* new cursor (in command, not terminal) */
291
292 if (cmdedit_x >= num) { /* no to up line */
293 cmdedit_x -= num;
294 if (num < 4)
295 while (num-- > 0)
296 putchar('\b');
297
298 else
299 printf("\033[%dD", num);
300 } else {
301 int count_y;
302
303 if (cmdedit_x) {
304 putchar('\r'); /* back to first terminal pos. */
305 num -= cmdedit_x; /* set previous backward */
306 }
307 count_y = 1 + num / cmdedit_termw;
308 printf("\033[%dA", count_y);
309 cmdedit_y -= count_y;
310 /* require forward after uping */
311 cmdedit_x = cmdedit_termw * count_y - num;
312 printf("\033[%dC", cmdedit_x); /* set term cursor */
313 }
314}
315
316static void put_prompt(void)
317{
318 out1str(cmdedit_prompt);
319 cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */
320 cursor = 0;
321 cmdedit_y = 0; /* new quasireal y */
322}
323
324#ifndef BB_FEATURE_SH_FANCY_PROMPT
325static void parse_prompt(const char *prmt_ptr)
326{
327 cmdedit_prompt = prmt_ptr;
328 cmdedit_prmt_len = strlen(prmt_ptr);
329 put_prompt();
330}
331#else
332static void parse_prompt(const char *prmt_ptr)
333{
334 int prmt_len = 0;
335 int sub_len = 0;
336 char flg_not_length = '[';
337 char *prmt_mem_ptr = xcalloc(1, 1);
338 char *pwd_buf = xgetcwd(0);
339 char buf2[PATH_MAX + 1];
340 char buf[2];
341 char c;
342 char *pbuf;
343
344 if (!pwd_buf) {
345 pwd_buf=(char *)unknown;
346 }
347
348 while (*prmt_ptr) {
349 pbuf = buf;
350 pbuf[1] = 0;
351 c = *prmt_ptr++;
352 if (c == '\\') {
353 const char *cp = prmt_ptr;
354 int l;
355
356 c = process_escape_sequence(&prmt_ptr);
357 if(prmt_ptr==cp) {
358 if (*cp == 0)
359 break;
360 c = *prmt_ptr++;
361 switch (c) {
362#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
363 case 'u':
364 pbuf = user_buf;
365 break;
366#endif
367 case 'h':
368 pbuf = hostname_buf;
369 if (*pbuf == 0) {
370 pbuf = xcalloc(256, 1);
371 if (gethostname(pbuf, 255) < 0) {
372 strcpy(pbuf, "?");
373 } else {
374 char *s = strchr(pbuf, '.');
375
376 if (s)
377 *s = 0;
378 }
379 hostname_buf = pbuf;
380 }
381 break;
382 case '$':
383 c = my_euid == 0 ? '#' : '$';
384 break;
385#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
386 case 'w':
387 pbuf = pwd_buf;
388 l = strlen(home_pwd_buf);
389 if (home_pwd_buf[0] != 0 &&
390 strncmp(home_pwd_buf, pbuf, l) == 0 &&
391 (pbuf[l]=='/' || pbuf[l]=='\0') &&
392 strlen(pwd_buf+l)<PATH_MAX) {
393 pbuf = buf2;
394 *pbuf = '~';
395 strcpy(pbuf+1, pwd_buf+l);
396 }
397 break;
398#endif
399 case 'W':
400 pbuf = pwd_buf;
401 cp = strrchr(pbuf,'/');
402 if ( (cp != NULL) && (cp != pbuf) )
403 pbuf += (cp-pbuf)+1;
404 break;
405 case '!':
406 snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
407 break;
408 case 'e': case 'E': /* \e \E = \033 */
409 c = '\033';
410 break;
411 case 'x': case 'X':
412 for (l = 0; l < 3;) {
413 int h;
414 buf2[l++] = *prmt_ptr;
415 buf2[l] = 0;
416 h = strtol(buf2, &pbuf, 16);
417 if (h > UCHAR_MAX || (pbuf - buf2) < l) {
418 l--;
419 break;
420 }
421 prmt_ptr++;
422 }
423 buf2[l] = 0;
424 c = (char)strtol(buf2, 0, 16);
425 if(c==0)
426 c = '?';
427 pbuf = buf;
428 break;
429 case '[': case ']':
430 if (c == flg_not_length) {
431 flg_not_length = flg_not_length == '[' ? ']' : '[';
432 continue;
433 }
434 break;
435 }
436 }
437 }
438 if(pbuf == buf)
439 *pbuf = c;
440 prmt_len += strlen(pbuf);
441 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
442 if (flg_not_length == ']')
443 sub_len++;
444 }
445 if(pwd_buf!=(char *)unknown)
446 free(pwd_buf);
447 cmdedit_prompt = prmt_mem_ptr;
448 cmdedit_prmt_len = prmt_len - sub_len;
449 put_prompt();
450}
451#endif
452
453
454/* draw promt, editor line, and clear tail */
455static void redraw(int y, int back_cursor)
456{
457 if (y > 0) /* up to start y */
458 printf("\033[%dA", y);
459 putchar('\r');
460 put_prompt();
461 input_end(); /* rewrite */
462 printf("\033[J"); /* destroy tail after cursor */
463 input_backward(back_cursor);
464}
465
466/* Delete the char in front of the cursor */
467static void input_delete(void)
468{
469 int j = cursor;
470
471 if (j == len)
472 return;
473
474 strcpy(command_ps + j, command_ps + j + 1);
475 len--;
476 input_end(); /* rewtite new line */
477 cmdedit_set_out_char(0); /* destroy end char */
478 input_backward(cursor - j); /* back to old pos cursor */
479}
480
481/* Delete the char in back of the cursor */
482static void input_backspace(void)
483{
484 if (cursor > 0) {
485 input_backward(1);
486 input_delete();
487 }
488}
489
490
491/* Move forward one charactor */
492static void input_forward(void)
493{
494 if (cursor < len)
495 cmdedit_set_out_char(command_ps[cursor + 1]);
496}
497
498
499static void cmdedit_setwidth(int w, int redraw_flg)
500{
501 cmdedit_termw = cmdedit_prmt_len + 2;
502 if (w <= cmdedit_termw) {
503 cmdedit_termw = cmdedit_termw % w;
504 }
505 if (w > cmdedit_termw) {
506 cmdedit_termw = w;
507
508 if (redraw_flg) {
509 /* new y for current cursor */
510 int new_y = (cursor + cmdedit_prmt_len) / w;
511
512 /* redraw */
513 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
514 fflush(stdout);
515 }
516 }
517}
518
519static void cmdedit_init(void)
520{
521 cmdedit_prmt_len = 0;
522 if ((handlers_sets & SET_WCHG_HANDLERS) == 0) {
523 /* emulate usage handler to set handler and call yours work */
524 win_changed(-SIGWINCH);
525 handlers_sets |= SET_WCHG_HANDLERS;
526 }
527
528 if ((handlers_sets & SET_ATEXIT) == 0) {
529#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
530 struct passwd *entry;
531
532 my_euid = geteuid();
533 entry = getpwuid(my_euid);
534 if (entry) {
535 user_buf = xstrdup(entry->pw_name);
536 home_pwd_buf = xstrdup(entry->pw_dir);
537 }
538#endif
539
540#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
541
542#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
543 my_euid = geteuid();
544#endif
545 my_uid = getuid();
546 my_gid = getgid();
547#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
548 handlers_sets |= SET_ATEXIT;
549 atexit(cmdedit_reset_term); /* be sure to do this only once */
550 }
551}
552
553#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
554
555static int is_execute(const struct stat *st)
556{
557 if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) ||
558 (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) ||
559 (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) ||
560 (st->st_mode & S_IXOTH)) return TRUE;
561 return FALSE;
562}
563
564#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
565
566static char **username_tab_completion(char *ud, int *num_matches)
567{
568 struct passwd *entry;
569 int userlen;
570 char *temp;
571
572
573 ud++; /* ~user/... to user/... */
574 userlen = strlen(ud);
575
576 if (num_matches == 0) { /* "~/..." or "~user/..." */
577 char *sav_ud = ud - 1;
578 char *home = 0;
579
580 if (*ud == '/') { /* "~/..." */
581 home = home_pwd_buf;
582 } else {
583 /* "~user/..." */
584 temp = strchr(ud, '/');
585 *temp = 0; /* ~user\0 */
586 entry = getpwnam(ud);
587 *temp = '/'; /* restore ~user/... */
588 ud = temp;
589 if (entry)
590 home = entry->pw_dir;
591 }
592 if (home) {
593 if ((userlen + strlen(home) + 1) < BUFSIZ) {
594 char temp2[BUFSIZ]; /* argument size */
595
596 /* /home/user/... */
597 sprintf(temp2, "%s%s", home, ud);
598 strcpy(sav_ud, temp2);
599 }
600 }
601 return 0; /* void, result save to argument :-) */
602 } else {
603 /* "~[^/]*" */
604 char **matches = (char **) NULL;
605 int nm = 0;
606
607 setpwent();
608
609 while ((entry = getpwent()) != NULL) {
610 /* Null usernames should result in all users as possible completions. */
611 if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
612
613 temp = xmalloc(3 + strlen(entry->pw_name));
614 sprintf(temp, "~%s/", entry->pw_name);
615 matches = xrealloc(matches, (nm + 1) * sizeof(char *));
616
617 matches[nm++] = temp;
618 }
619 }
620
621 endpwent();
622 (*num_matches) = nm;
623 return (matches);
624 }
625}
626#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */
627
628enum {
629 FIND_EXE_ONLY = 0,
630 FIND_DIR_ONLY = 1,
631 FIND_FILE_ONLY = 2,
632};
633
634static int path_parse(char ***p, int flags)
635{
636 int npth;
637 char *tmp;
638 char *pth;
639
640 /* if not setenv PATH variable, to search cur dir "." */
641 if (flags != FIND_EXE_ONLY || (pth = getenv("PATH")) == 0 ||
642 /* PATH=<empty> or PATH=:<empty> */
643 *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) {
644 return 1;
645 }
646
647 tmp = pth;
648 npth = 0;
649
650 for (;;) {
651 npth++; /* count words is + 1 count ':' */
652 tmp = strchr(tmp, ':');
653 if (tmp) {
654 if (*++tmp == 0)
655 break; /* :<empty> */
656 } else
657 break;
658 }
659
660 *p = xmalloc(npth * sizeof(char *));
661
662 tmp = pth;
663 (*p)[0] = xstrdup(tmp);
664 npth = 1; /* count words is + 1 count ':' */
665
666 for (;;) {
667 tmp = strchr(tmp, ':');
668 if (tmp) {
669 (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */
670 if (*++tmp == 0)
671 break; /* :<empty> */
672 } else
673 break;
674 (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */
675 }
676
677 return npth;
678}
679
680static char *add_quote_for_spec_chars(char *found)
681{
682 int l = 0;
683 char *s = xmalloc((strlen(found) + 1) * 2);
684
685 while (*found) {
686 if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
687 s[l++] = '\\';
688 s[l++] = *found++;
689 }
690 s[l] = 0;
691 return s;
692}
693
694static char **exe_n_cwd_tab_completion(char *command, int *num_matches,
695 int type)
696{
697
698 char **matches = 0;
699 DIR *dir;
700 struct dirent *next;
701 char dirbuf[BUFSIZ];
702 int nm = *num_matches;
703 struct stat st;
704 char *path1[1];
705 char **paths = path1;
706 int npaths;
707 int i;
708 char *found;
709 char *pfind = strrchr(command, '/');
710
711 path1[0] = ".";
712
713 if (pfind == NULL) {
714 /* no dir, if flags==EXE_ONLY - get paths, else "." */
715 npaths = path_parse(&paths, type);
716 pfind = command;
717 } else {
718 /* with dir */
719 /* save for change */
720 strcpy(dirbuf, command);
721 /* set dir only */
722 dirbuf[(pfind - command) + 1] = 0;
723#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
724 if (dirbuf[0] == '~') /* ~/... or ~user/... */
725 username_tab_completion(dirbuf, 0);
726#endif
727 /* "strip" dirname in command */
728 pfind++;
729
730 paths[0] = dirbuf;
731 npaths = 1; /* only 1 dir */
732 }
733
734 for (i = 0; i < npaths; i++) {
735
736 dir = opendir(paths[i]);
737 if (!dir) /* Don't print an error */
738 continue;
739
740 while ((next = readdir(dir)) != NULL) {
741 char *str_found = next->d_name;
742
743 /* matched ? */
744 if (strncmp(str_found, pfind, strlen(pfind)))
745 continue;
746 /* not see .name without .match */
747 if (*str_found == '.' && *pfind == 0) {
748 if (*paths[i] == '/' && paths[i][1] == 0
749 && str_found[1] == 0) str_found = ""; /* only "/" */
750 else
751 continue;
752 }
753 found = concat_path_file(paths[i], str_found);
754 /* hmm, remover in progress? */
755 if (stat(found, &st) < 0)
756 goto cont;
757 /* find with dirs ? */
758 if (paths[i] != dirbuf)
759 strcpy(found, next->d_name); /* only name */
760 if (S_ISDIR(st.st_mode)) {
761 /* name is directory */
762 str_found = found;
763 found = concat_path_file(found, "");
764 free(str_found);
765 str_found = add_quote_for_spec_chars(found);
766 } else {
767 /* not put found file if search only dirs for cd */
768 if (type == FIND_DIR_ONLY)
769 goto cont;
770 str_found = add_quote_for_spec_chars(found);
771 if (type == FIND_FILE_ONLY ||
772 (type == FIND_EXE_ONLY && is_execute(&st) == TRUE))
773 strcat(str_found, " ");
774 }
775 /* Add it to the list */
776 matches = xrealloc(matches, (nm + 1) * sizeof(char *));
777
778 matches[nm++] = str_found;
779cont:
780 free(found);
781 }
782 closedir(dir);
783 }
784 if (paths != path1) {
785 free(paths[0]); /* allocated memory only in first member */
786 free(paths);
787 }
788 *num_matches = nm;
789 return (matches);
790}
791
792static int match_compare(const void *a, const void *b)
793{
794 return strcmp(*(char **) a, *(char **) b);
795}
796
797
798
799#define QUOT (UCHAR_MAX+1)
800
801#define collapse_pos(is, in) { \
802 memcpy(int_buf+is, int_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); \
803 memcpy(pos_buf+is, pos_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); }
804
805static int find_match(char *matchBuf, int *len_with_quotes)
806{
807 int i, j;
808 int command_mode;
809 int c, c2;
810 int int_buf[BUFSIZ + 1];
811 int pos_buf[BUFSIZ + 1];
812
813 /* set to integer dimension characters and own positions */
814 for (i = 0;; i++) {
815 int_buf[i] = (int) ((unsigned char) matchBuf[i]);
816 if (int_buf[i] == 0) {
817 pos_buf[i] = -1; /* indicator end line */
818 break;
819 } else
820 pos_buf[i] = i;
821 }
822
823 /* mask \+symbol and convert '\t' to ' ' */
824 for (i = j = 0; matchBuf[i]; i++, j++)
825 if (matchBuf[i] == '\\') {
826 collapse_pos(j, j + 1);
827 int_buf[j] |= QUOT;
828 i++;
829#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
830 if (matchBuf[i] == '\t') /* algorithm equivalent */
831 int_buf[j] = ' ' | QUOT;
832#endif
833 }
834#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
835 else if (matchBuf[i] == '\t')
836 int_buf[j] = ' ';
837#endif
838
839 /* mask "symbols" or 'symbols' */
840 c2 = 0;
841 for (i = 0; int_buf[i]; i++) {
842 c = int_buf[i];
843 if (c == '\'' || c == '"') {
844 if (c2 == 0)
845 c2 = c;
846 else {
847 if (c == c2)
848 c2 = 0;
849 else
850 int_buf[i] |= QUOT;
851 }
852 } else if (c2 != 0 && c != '$')
853 int_buf[i] |= QUOT;
854 }
855
856 /* skip commands with arguments if line have commands delimiters */
857 /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
858 for (i = 0; int_buf[i]; i++) {
859 c = int_buf[i];
860 c2 = int_buf[i + 1];
861 j = i ? int_buf[i - 1] : -1;
862 command_mode = 0;
863 if (c == ';' || c == '&' || c == '|') {
864 command_mode = 1 + (c == c2);
865 if (c == '&') {
866 if (j == '>' || j == '<')
867 command_mode = 0;
868 } else if (c == '|' && j == '>')
869 command_mode = 0;
870 }
871 if (command_mode) {
872 collapse_pos(0, i + command_mode);
873 i = -1; /* hack incremet */
874 }
875 }
876 /* collapse `command...` */
877 for (i = 0; int_buf[i]; i++)
878 if (int_buf[i] == '`') {
879 for (j = i + 1; int_buf[j]; j++)
880 if (int_buf[j] == '`') {
881 collapse_pos(i, j + 1);
882 j = 0;
883 break;
884 }
885 if (j) {
886 /* not found close ` - command mode, collapse all previous */
887 collapse_pos(0, i + 1);
888 break;
889 } else
890 i--; /* hack incremet */
891 }
892
893 /* collapse (command...(command...)...) or {command...{command...}...} */
894 c = 0; /* "recursive" level */
895 c2 = 0;
896 for (i = 0; int_buf[i]; i++)
897 if (int_buf[i] == '(' || int_buf[i] == '{') {
898 if (int_buf[i] == '(')
899 c++;
900 else
901 c2++;
902 collapse_pos(0, i + 1);
903 i = -1; /* hack incremet */
904 }
905 for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
906 if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
907 if (int_buf[i] == ')')
908 c--;
909 else
910 c2--;
911 collapse_pos(0, i + 1);
912 i = -1; /* hack incremet */
913 }
914
915 /* skip first not quote space */
916 for (i = 0; int_buf[i]; i++)
917 if (int_buf[i] != ' ')
918 break;
919 if (i)
920 collapse_pos(0, i);
921
922 /* set find mode for completion */
923 command_mode = FIND_EXE_ONLY;
924 for (i = 0; int_buf[i]; i++)
925 if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
926 if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
927 && matchBuf[pos_buf[0]]=='c'
928 && matchBuf[pos_buf[1]]=='d' )
929 command_mode = FIND_DIR_ONLY;
930 else {
931 command_mode = FIND_FILE_ONLY;
932 break;
933 }
934 }
935 /* "strlen" */
936 for (i = 0; int_buf[i]; i++);
937 /* find last word */
938 for (--i; i >= 0; i--) {
939 c = int_buf[i];
940 if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
941 collapse_pos(0, i + 1);
942 break;
943 }
944 }
945 /* skip first not quoted '\'' or '"' */
946 for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++);
947 /* collapse quote or unquote // or /~ */
948 while ((int_buf[i] & ~QUOT) == '/' &&
949 ((int_buf[i + 1] & ~QUOT) == '/'
950 || (int_buf[i + 1] & ~QUOT) == '~')) {
951 i++;
952 }
953
954 /* set only match and destroy quotes */
955 j = 0;
956 for (c = 0; pos_buf[i] >= 0; i++) {
957 matchBuf[c++] = matchBuf[pos_buf[i]];
958 j = pos_buf[i] + 1;
959 }
960 matchBuf[c] = 0;
961 /* old lenght matchBuf with quotes symbols */
962 *len_with_quotes = j ? j - pos_buf[0] : 0;
963
964 return command_mode;
965}
966
967
968static void input_tab(int *lastWasTab)
969{
970 /* Do TAB completion */
971 static int num_matches;
972 static char **matches;
973
974 if (lastWasTab == 0) { /* free all memory */
975 if (matches) {
976 while (num_matches > 0)
977 free(matches[--num_matches]);
978 free(matches);
979 matches = (char **) NULL;
980 }
981 return;
982 }
983 if (*lastWasTab == FALSE) {
984
985 char *tmp;
986 int len_found;
987 char matchBuf[BUFSIZ];
988 int find_type;
989 int recalc_pos;
990
991 *lastWasTab = TRUE; /* flop trigger */
992
993 /* Make a local copy of the string -- up
994 * to the position of the cursor */
995 tmp = strncpy(matchBuf, command_ps, cursor);
996 tmp[cursor] = 0;
997
998 find_type = find_match(matchBuf, &recalc_pos);
999
1000 /* Free up any memory already allocated */
1001 input_tab(0);
1002
1003#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
1004 /* If the word starts with `~' and there is no slash in the word,
1005 * then try completing this word as a username. */
1006
1007 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
1008 matches = username_tab_completion(matchBuf, &num_matches);
1009#endif
1010 /* Try to match any executable in our path and everything
1011 * in the current working directory that matches. */
1012 if (!matches)
1013 matches =
1014 exe_n_cwd_tab_completion(matchBuf,
1015 &num_matches, find_type);
1016 /* Remove duplicate found */
1017 if(matches) {
1018 int i, j;
1019 /* bubble */
1020 for(i=0; i<(num_matches-1); i++)
1021 for(j=i+1; j<num_matches; j++)
1022 if(matches[i]!=0 && matches[j]!=0 &&
1023 strcmp(matches[i], matches[j])==0) {
1024 free(matches[j]);
1025 matches[j]=0;
1026 }
1027 j=num_matches;
1028 num_matches = 0;
1029 for(i=0; i<j; i++)
1030 if(matches[i]) {
1031 if(!strcmp(matches[i], "./"))
1032 matches[i][1]=0;
1033 else if(!strcmp(matches[i], "../"))
1034 matches[i][2]=0;
1035 matches[num_matches++]=matches[i];
1036 }
1037 }
1038 /* Did we find exactly one match? */
1039 if (!matches || num_matches > 1) {
1040 char *tmp1;
1041
1042 beep();
1043 if (!matches)
1044 return; /* not found */
1045 /* sort */
1046 qsort(matches, num_matches, sizeof(char *), match_compare);
1047
1048 /* find minimal match */
1049 tmp = xstrdup(matches[0]);
1050 for (tmp1 = tmp; *tmp1; tmp1++)
1051 for (len_found = 1; len_found < num_matches; len_found++)
1052 if (matches[len_found][(tmp1 - tmp)] != *tmp1) {
1053 *tmp1 = 0;
1054 break;
1055 }
1056 if (*tmp == 0) { /* have unique */
1057 free(tmp);
1058 return;
1059 }
1060 } else { /* one match */
1061 tmp = matches[0];
1062 /* for next completion current found */
1063 *lastWasTab = FALSE;
1064 }
1065
1066 len_found = strlen(tmp);
1067 /* have space to placed match? */
1068 if ((len_found - strlen(matchBuf) + len) < BUFSIZ) {
1069
1070 /* before word for match */
1071 command_ps[cursor - recalc_pos] = 0;
1072 /* save tail line */
1073 strcpy(matchBuf, command_ps + cursor);
1074 /* add match */
1075 strcat(command_ps, tmp);
1076 /* add tail */
1077 strcat(command_ps, matchBuf);
1078 /* back to begin word for match */
1079 input_backward(recalc_pos);
1080 /* new pos */
1081 recalc_pos = cursor + len_found;
1082 /* new len */
1083 len = strlen(command_ps);
1084 /* write out the matched command */
1085 redraw(cmdedit_y, len - recalc_pos);
1086 }
1087 if (tmp != matches[0])
1088 free(tmp);
1089 } else {
1090 /* Ok -- the last char was a TAB. Since they
1091 * just hit TAB again, print a list of all the
1092 * available choices... */
1093 if (matches && num_matches > 0) {
1094 int i, col, l;
1095 int sav_cursor = cursor; /* change goto_new_line() */
1096
1097 /* Go to the next line */
1098 goto_new_line();
1099 for (i = 0, col = 0; i < num_matches; i++) {
1100 l = strlen(matches[i]);
1101 if (l < 14)
1102 l = 14;
1103 printf("%-14s ", matches[i]);
1104 if ((l += 2) > 16)
1105 while (l % 16) {
1106 putchar(' ');
1107 l++;
1108 }
1109 col += l;
1110 col -= (col / cmdedit_termw) * cmdedit_termw;
1111 if (col > 60 && matches[i + 1] != NULL) {
1112 putchar('\n');
1113 col = 0;
1114 }
1115 }
1116 /* Go to the next line and rewrite */
1117 putchar('\n');
1118 redraw(0, len - sav_cursor);
1119 }
1120 }
1121}
1122#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
1123
1124static void get_previous_history(struct history **hp, struct history *p)
1125{
1126 if ((*hp)->s)
1127 free((*hp)->s);
1128 (*hp)->s = xstrdup(command_ps);
1129 *hp = p;
1130}
1131
1132static inline void get_next_history(struct history **hp)
1133{
1134 get_previous_history(hp, (*hp)->n);
1135}
1136
1137enum {
1138 ESC = 27,
1139 DEL = 127,
1140};
1141
1142
1143/*
1144 * This function is used to grab a character buffer
1145 * from the input file descriptor and allows you to
1146 * a string with full command editing (sortof like
1147 * a mini readline).
1148 *
1149 * The following standard commands are not implemented:
1150 * ESC-b -- Move back one word
1151 * ESC-f -- Move forward one word
1152 * ESC-d -- Delete back one word
1153 * ESC-h -- Delete forward one word
1154 * CTL-t -- Transpose two characters
1155 *
1156 * Furthermore, the "vi" command editing keys are not implemented.
1157 *
1158 */
1159
1160
1161int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1162{
1163
1164 int break_out = 0;
1165 int lastWasTab = FALSE;
1166 unsigned char c = 0;
1167 struct history *hp = his_end;
1168
1169 /* prepare before init handlers */
1170 cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */
1171 len = 0;
1172 command_ps = command;
1173
1174 getTermSettings(0, (void *) &initial_settings);
1175 memcpy(&new_settings, &initial_settings, sizeof(struct termios));
1176 new_settings.c_lflag &= ~ICANON; /* unbuffered input */
1177 /* Turn off echoing and CTRL-C, so we can trap it */
1178 new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
1179#ifndef linux
1180 /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
1181 new_settings.c_cc[VMIN] = 1;
1182 new_settings.c_cc[VTIME] = 0;
1183 /* Turn off CTRL-C, so we can trap it */
1184# ifndef _POSIX_VDISABLE
1185# define _POSIX_VDISABLE '\0'
1186# endif
1187 new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
1188#endif
1189 command[0] = 0;
1190
1191 setTermSettings(0, (void *) &new_settings);
1192 handlers_sets |= SET_RESET_TERM;
1193
1194 /* Now initialize things */
1195 cmdedit_init();
1196 /* Print out the command prompt */
1197 parse_prompt(prompt);
1198
1199 while (1) {
1200
1201 fflush(stdout); /* buffered out to fast */
1202
1203 if (safe_read(0, &c, 1) < 1)
1204 /* if we can't read input then exit */
1205 goto prepare_to_die;
1206
1207 switch (c) {
1208 case '\n':
1209 case '\r':
1210 /* Enter */
1211 goto_new_line();
1212 break_out = 1;
1213 break;
1214 case 1:
1215 /* Control-a -- Beginning of line */
1216 input_backward(cursor);
1217 break;
1218 case 2:
1219 /* Control-b -- Move back one character */
1220 input_backward(1);
1221 break;
1222 case 3:
1223 /* Control-c -- stop gathering input */
1224 goto_new_line();
1225 command[0] = 0;
1226 len = 0;
1227 lastWasTab = FALSE;
1228 put_prompt();
1229 break;
1230 case 4:
1231 /* Control-d -- Delete one character, or exit
1232 * if the len=0 and no chars to delete */
1233 if (len == 0) {
1234prepare_to_die:
1235#if !defined(BB_ASH)
1236 printf("exit");
1237 goto_new_line();
1238 /* cmdedit_reset_term() called in atexit */
1239 exit(EXIT_SUCCESS);
1240#else
1241 break_out = -1; /* for control stoped jobs */
1242 break;
1243#endif
1244 } else {
1245 input_delete();
1246 }
1247 break;
1248 case 5:
1249 /* Control-e -- End of line */
1250 input_end();
1251 break;
1252 case 6:
1253 /* Control-f -- Move forward one character */
1254 input_forward();
1255 break;
1256 case '\b':
1257 case DEL:
1258 /* Control-h and DEL */
1259 input_backspace();
1260 break;
1261 case '\t':
1262#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
1263 input_tab(&lastWasTab);
1264#endif
1265 break;
1266 case 14:
1267 /* Control-n -- Get next command in history */
1268 if (hp && hp->n && hp->n->s) {
1269 get_next_history(&hp);
1270 goto rewrite_line;
1271 } else {
1272 beep();
1273 }
1274 break;
1275 case 16:
1276 /* Control-p -- Get previous command from history */
1277 if (hp && hp->p) {
1278 get_previous_history(&hp, hp->p);
1279 goto rewrite_line;
1280 } else {
1281 beep();
1282 }
1283 break;
1284 case 21:
1285 /* Control-U -- Clear line before cursor */
1286 if (cursor) {
1287 strcpy(command, command + cursor);
1288 redraw(cmdedit_y, len -= cursor);
1289 }
1290 break;
1291
1292 case ESC:{
1293 /* escape sequence follows */
1294 if (safe_read(0, &c, 1) < 1)
1295 goto prepare_to_die;
1296 /* different vt100 emulations */
1297 if (c == '[' || c == 'O') {
1298 if (safe_read(0, &c, 1) < 1)
1299 goto prepare_to_die;
1300 }
1301 switch (c) {
1302#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
1303 case '\t': /* Alt-Tab */
1304
1305 input_tab(&lastWasTab);
1306 break;
1307#endif
1308 case 'A':
1309 /* Up Arrow -- Get previous command from history */
1310 if (hp && hp->p) {
1311 get_previous_history(&hp, hp->p);
1312 goto rewrite_line;
1313 } else {
1314 beep();
1315 }
1316 break;
1317 case 'B':
1318 /* Down Arrow -- Get next command in history */
1319 if (hp && hp->n && hp->n->s) {
1320 get_next_history(&hp);
1321 goto rewrite_line;
1322 } else {
1323 beep();
1324 }
1325 break;
1326
1327 /* Rewrite the line with the selected history item */
1328 rewrite_line:
1329 /* change command */
1330 len = strlen(strcpy(command, hp->s));
1331 /* redraw and go to end line */
1332 redraw(cmdedit_y, 0);
1333 break;
1334 case 'C':
1335 /* Right Arrow -- Move forward one character */
1336 input_forward();
1337 break;
1338 case 'D':
1339 /* Left Arrow -- Move back one character */
1340 input_backward(1);
1341 break;
1342 case '3':
1343 /* Delete */
1344 input_delete();
1345 break;
1346 case '1':
1347 case 'H':
1348 /* Home (Ctrl-A) */
1349 input_backward(cursor);
1350 break;
1351 case '4':
1352 case 'F':
1353 /* End (Ctrl-E) */
1354 input_end();
1355 break;
1356 default:
1357 if (!(c >= '1' && c <= '9'))
1358 c = 0;
1359 beep();
1360 }
1361 if (c >= '1' && c <= '9')
1362 do
1363 if (safe_read(0, &c, 1) < 1)
1364 goto prepare_to_die;
1365 while (c != '~');
1366 break;
1367 }
1368
1369 default: /* If it's regular input, do the normal thing */
1370#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
1371 /* Control-V -- Add non-printable symbol */
1372 if (c == 22) {
1373 if (safe_read(0, &c, 1) < 1)
1374 goto prepare_to_die;
1375 if (c == 0) {
1376 beep();
1377 break;
1378 }
1379 } else
1380#endif
1381 if (!Isprint(c)) /* Skip non-printable characters */
1382 break;
1383
1384 if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */
1385 break;
1386
1387 len++;
1388
1389 if (cursor == (len - 1)) { /* Append if at the end of the line */
1390 *(command + cursor) = c;
1391 *(command + cursor + 1) = 0;
1392 cmdedit_set_out_char(0);
1393 } else { /* Insert otherwise */
1394 int sc = cursor;
1395
1396 memmove(command + sc + 1, command + sc, len - sc);
1397 *(command + sc) = c;
1398 sc++;
1399 /* rewrite from cursor */
1400 input_end();
1401 /* to prev x pos + 1 */
1402 input_backward(cursor - sc);
1403 }
1404
1405 break;
1406 }
1407 if (break_out) /* Enter is the command terminator, no more input. */
1408 break;
1409
1410 if (c != '\t')
1411 lastWasTab = FALSE;
1412 }
1413
1414 setTermSettings(0, (void *) &initial_settings);
1415 handlers_sets &= ~SET_RESET_TERM;
1416
1417 /* Handle command history log */
1418 if (len) { /* no put empty line */
1419
1420 struct history *h = his_end;
1421 char *ss;
1422
1423 ss = xstrdup(command); /* duplicate */
1424
1425 if (h == 0) {
1426 /* No previous history -- this memory is never freed */
1427 h = his_front = xmalloc(sizeof(struct history));
1428 h->n = xmalloc(sizeof(struct history));
1429
1430 h->p = NULL;
1431 h->s = ss;
1432 h->n->p = h;
1433 h->n->n = NULL;
1434 h->n->s = NULL;
1435 his_end = h->n;
1436 history_counter++;
1437 } else {
1438 /* Add a new history command -- this memory is never freed */
1439 h->n = xmalloc(sizeof(struct history));
1440
1441 h->n->p = h;
1442 h->n->n = NULL;
1443 h->n->s = NULL;
1444 h->s = ss;
1445 his_end = h->n;
1446
1447 /* After max history, remove the oldest command */
1448 if (history_counter >= MAX_HISTORY) {
1449
1450 struct history *p = his_front->n;
1451
1452 p->p = NULL;
1453 free(his_front->s);
1454 free(his_front);
1455 his_front = p;
1456 } else {
1457 history_counter++;
1458 }
1459 }
1460#if defined(BB_FEATURE_SH_FANCY_PROMPT)
1461 num_ok_lines++;
1462#endif
1463 }
1464 if(break_out>0) {
1465 command[len++] = '\n'; /* set '\n' */
1466 command[len] = 0;
1467 }
1468#if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION)
1469 input_tab(0); /* strong free */
1470#endif
1471#if defined(BB_FEATURE_SH_FANCY_PROMPT)
1472 free(cmdedit_prompt);
1473#endif
1474 cmdedit_reset_term();
1475 return len;
1476}
1477
1478
1479
1480#endif /* BB_FEATURE_COMMAND_EDITING */
1481
1482
1483#ifdef TEST
1484
1485const char *applet_name = "debug stuff usage";
1486const char *memory_exhausted = "Memory exhausted";
1487
1488#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
1489#include <locale.h>
1490#endif
1491
1492int main(int argc, char **argv)
1493{
1494 char buff[BUFSIZ];
1495 char *prompt =
1496#if defined(BB_FEATURE_SH_FANCY_PROMPT)
1497 "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\
1498\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \
1499\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
1500#else
1501 "% ";
1502#endif
1503
1504#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
1505 setlocale(LC_ALL, "");
1506#endif
1507 while(1) {
1508 int l;
1509 cmdedit_read_input(prompt, buff);
1510 l = strlen(buff);
1511 if(l==0)
1512 break;
1513 if(l > 0 && buff[l-1] == '\n')
1514 buff[l-1] = 0;
1515 printf("*** cmdedit_read_input() returned line =%s=\n", buff);
1516 }
1517 printf("*** cmdedit_read_input() detect ^C\n");
1518 return 0;
1519}
1520
1521#endif /* TEST */
diff --git a/cmdedit.h b/cmdedit.h
deleted file mode 100644
index 83893572a..000000000
--- a/cmdedit.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef CMDEDIT_H
2#define CMDEDIT_H
3
4int cmdedit_read_input(char* promptStr, char* command);
5
6#endif /* CMDEDIT_H */
diff --git a/cmp.c b/cmp.c
deleted file mode 100644
index 6d579461d..000000000
--- a/cmp.c
+++ /dev/null
@@ -1,80 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini cmp implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <string.h>
27#include <errno.h>
28#include <stdlib.h>
29#include <getopt.h>
30#include "busybox.h"
31
32int cmp_main(int argc, char **argv)
33{
34 FILE *fp1 = NULL, *fp2 = stdin;
35 char *filename1, *filename2 = "-";
36 int c, c1, c2, char_pos = 1, line_pos = 1, silent = FALSE;
37
38 while ((c = getopt(argc, argv, "s")) != EOF) {
39 switch (c) {
40 case 's':
41 silent = TRUE;
42 break;
43 default:
44 show_usage();
45 }
46 }
47
48 filename1 = argv[optind];
49 switch (argc - optind) {
50 case 2:
51 fp2 = xfopen(filename2 = argv[optind + 1], "r");
52 case 1:
53 fp1 = xfopen(filename1, "r");
54 break;
55 default:
56 show_usage();
57 }
58
59 do {
60 c1 = fgetc(fp1);
61 c2 = fgetc(fp2);
62 if (c1 != c2) {
63 if (silent)
64 return EXIT_FAILURE;
65 if (c1 == EOF)
66 printf("EOF on %s\n", filename1);
67 else if (c2 == EOF)
68 printf("EOF on %s\n", filename2);
69 else
70 printf("%s %s differ: char %d, line %d\n", filename1, filename2,
71 char_pos, line_pos);
72 return EXIT_FAILURE;
73 }
74 char_pos++;
75 if (c1 == '\n')
76 line_pos++;
77 } while (c1 != EOF);
78
79 return EXIT_SUCCESS;
80}
diff --git a/console-tools/Makefile b/console-tools/Makefile
new file mode 100644
index 000000000..a67e4bb7b
--- /dev/null
+++ b/console-tools/Makefile
@@ -0,0 +1,43 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := console-tools.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27obj-$(CONFIG_CHVT) += chvt.o
28obj-$(CONFIG_CLEAR) += clear.o
29obj-$(CONFIG_DEALLOCVT) += deallocvt.o
30obj-$(CONFIG_DUMPKMAP) += dumpkmap.o
31obj-$(CONFIG_LOADACM) += loadacm.o
32obj-$(CONFIG_LOADFONT) += loadfont.o
33obj-$(CONFIG_LOADKMAP) += loadkmap.o
34obj-$(CONFIG_RESET) += reset.o
35obj-$(CONFIG_SETKEYCODES) += setkeycodes.o
36
37
38# Hand off to toplevel Rules.mak
39include $(TOPDIR)/Rules.mak
40
41clean:
42 rm -f $(L_TARGET) *.o core
43
diff --git a/console-tools/clear.c b/console-tools/clear.c
index 503bafa16..55e02e3d8 100644
--- a/console-tools/clear.c
+++ b/console-tools/clear.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Mini clear implementation for busybox 3 * Mini clear implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/console-tools/config.in b/console-tools/config.in
new file mode 100644
index 000000000..53d5ac6b4
--- /dev/null
+++ b/console-tools/config.in
@@ -0,0 +1,18 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Console Utilities'
8bool 'chvt' CONFIG_CHVT
9bool 'clear' CONFIG_CLEAR
10bool 'deallocvt' CONFIG_DEALLOCVT
11bool 'dumpkmap' CONFIG_DUMPKMAP
12bool 'loadacm' CONFIG_LOADACM
13bool 'loadfont' CONFIG_LOADFONT
14bool 'loadkmap' CONFIG_LOADKMAP
15bool 'reset' CONFIG_RESET
16bool 'setkeycodes' CONFIG_SETKEYCODES
17
18endmenu
diff --git a/console-tools/reset.c b/console-tools/reset.c
index 755c4c335..84cbb447a 100644
--- a/console-tools/reset.c
+++ b/console-tools/reset.c
@@ -2,10 +2,9 @@
2/* 2/*
3 * Mini reset implementation for busybox 3 * Mini reset implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 7 * Written by Erik Andersen and Kent Robotti <robotti@metconnect.com>
8 * and Kent Robotti <robotti@metconnect.com>
9 * 8 *
10 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/basename.c b/coreutils/basename.c
index c15afd533..bdbcec17a 100644
--- a/coreutils/basename.c
+++ b/coreutils/basename.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini basename implementation for busybox 3 * Mini basename implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/cat.c b/coreutils/cat.c
index aa8528d6a..820b6342e 100644
--- a/coreutils/cat.c
+++ b/coreutils/cat.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini Cat implementation for busybox 3 * Mini Cat implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/chgrp.c b/coreutils/chgrp.c
index fbc1036a8..43ffeb7e6 100644
--- a/coreutils/chgrp.c
+++ b/coreutils/chgrp.c
@@ -1,10 +1,9 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * Mini chown/chmod/chgrp implementation for busybox 3 * Mini chgrp implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/chmod.c b/coreutils/chmod.c
index 9139b3f4d..53230b568 100644
--- a/coreutils/chmod.c
+++ b/coreutils/chmod.c
@@ -1,10 +1,9 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * Mini chown/chmod/chgrp implementation for busybox 3 * Mini chmod implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/chown.c b/coreutils/chown.c
index d1e52deda..c1b992c37 100644
--- a/coreutils/chown.c
+++ b/coreutils/chown.c
@@ -1,10 +1,9 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * Mini chown/chmod/chgrp implementation for busybox 3 * Mini chown implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/chroot.c b/coreutils/chroot.c
index de6a2ea50..ba3e5f864 100644
--- a/coreutils/chroot.c
+++ b/coreutils/chroot.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Mini chroot implementation for busybox 3 * Mini chroot implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -48,7 +47,7 @@ int chroot_main(int argc, char **argv)
48 prog = *argv; 47 prog = *argv;
49 execvp(*argv, argv); 48 execvp(*argv, argv);
50 } else { 49 } else {
51#if defined shell_main && defined BB_FEATURE_SH_STANDALONE_SHELL 50#if defined shell_main && defined CONFIG_FEATURE_SH_STANDALONE_SHELL
52 char shell[] = "/bin/sh"; 51 char shell[] = "/bin/sh";
53 char *shell_argv[2] = { shell, NULL }; 52 char *shell_argv[2] = { shell, NULL };
54 applet_name = shell; 53 applet_name = shell;
diff --git a/coreutils/cmp.c b/coreutils/cmp.c
index 6d579461d..07bf3be92 100644
--- a/coreutils/cmp.c
+++ b/coreutils/cmp.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Mini cmp implementation for busybox 3 * Mini cmp implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 2000,2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/df.c b/coreutils/df.c
index 8cb13fa6d..0e9e5d61a 100644
--- a/coreutils/df.c
+++ b/coreutils/df.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini df implementation for busybox 3 * Mini df implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * based on original code by (I think) Bruce Perens <bruce@pixar.com>. 7 * based on original code by (I think) Bruce Perens <bruce@pixar.com>.
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
@@ -31,7 +31,7 @@
31#include "busybox.h" 31#include "busybox.h"
32 32
33extern const char mtab_file[]; /* Defined in utility.c */ 33extern const char mtab_file[]; /* Defined in utility.c */
34#ifdef BB_FEATURE_HUMAN_READABLE 34#ifdef CONFIG_FEATURE_HUMAN_READABLE
35static unsigned long df_disp_hr = KILOBYTE; 35static unsigned long df_disp_hr = KILOBYTE;
36#endif 36#endif
37 37
@@ -61,7 +61,7 @@ static int do_df(char *device, const char *mount_point)
61 if(device==NULL) 61 if(device==NULL)
62 return FALSE; 62 return FALSE;
63 } 63 }
64#ifdef BB_FEATURE_HUMAN_READABLE 64#ifdef CONFIG_FEATURE_HUMAN_READABLE
65 printf("%-20s %9s ", device, 65 printf("%-20s %9s ", device,
66 make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr)); 66 make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr));
67 67
@@ -92,13 +92,13 @@ extern int df_main(int argc, char **argv)
92 char disp_units_hdr[80] = "1k-blocks"; /* default display is kilobytes */ 92 char disp_units_hdr[80] = "1k-blocks"; /* default display is kilobytes */
93 93
94 while ((opt = getopt(argc, argv, "k" 94 while ((opt = getopt(argc, argv, "k"
95#ifdef BB_FEATURE_HUMAN_READABLE 95#ifdef CONFIG_FEATURE_HUMAN_READABLE
96 "hm" 96 "hm"
97#endif 97#endif
98)) > 0) 98)) > 0)
99 { 99 {
100 switch (opt) { 100 switch (opt) {
101#ifdef BB_FEATURE_HUMAN_READABLE 101#ifdef CONFIG_FEATURE_HUMAN_READABLE
102 case 'h': 102 case 'h':
103 df_disp_hr = 0; 103 df_disp_hr = 0;
104 strcpy(disp_units_hdr, " Size"); 104 strcpy(disp_units_hdr, " Size");
diff --git a/coreutils/dirname.c b/coreutils/dirname.c
index b534e6950..387233789 100644
--- a/coreutils/dirname.c
+++ b/coreutils/dirname.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini dirname implementation for busybox 3 * Mini dirname implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/du.c b/coreutils/du.c
index fb649aee5..c378837d0 100644
--- a/coreutils/du.c
+++ b/coreutils/du.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Mini du implementation for busybox 3 * Mini du implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000,2001 by Lineo, inc. and John Beppu
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7 * Written by John Beppu <beppu@lineo.com>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -33,7 +32,7 @@
33#include "busybox.h" 32#include "busybox.h"
34 33
35 34
36#ifdef BB_FEATURE_HUMAN_READABLE 35#ifdef CONFIG_FEATURE_HUMAN_READABLE
37static unsigned long disp_hr = KILOBYTE; 36static unsigned long disp_hr = KILOBYTE;
38#endif 37#endif
39 38
@@ -46,7 +45,7 @@ static Display *print;
46 45
47static void print_normal(long size, char *filename) 46static void print_normal(long size, char *filename)
48{ 47{
49#ifdef BB_FEATURE_HUMAN_READABLE 48#ifdef CONFIG_FEATURE_HUMAN_READABLE
50 printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename); 49 printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename);
51#else 50#else
52 printf("%ld\t%s\n", size, filename); 51 printf("%ld\t%s\n", size, filename);
@@ -207,7 +206,7 @@ int du_main(int argc, char **argv)
207 206
208 /* parse argv[] */ 207 /* parse argv[] */
209 while ((c = getopt(argc, argv, "sl" 208 while ((c = getopt(argc, argv, "sl"
210#ifdef BB_FEATURE_HUMAN_READABLE 209#ifdef CONFIG_FEATURE_HUMAN_READABLE
211"hm" 210"hm"
212#endif 211#endif
213"k")) != EOF) { 212"k")) != EOF) {
@@ -218,7 +217,7 @@ int du_main(int argc, char **argv)
218 case 'l': 217 case 'l':
219 count_hardlinks = 1; 218 count_hardlinks = 1;
220 break; 219 break;
221#ifdef BB_FEATURE_HUMAN_READABLE 220#ifdef CONFIG_FEATURE_HUMAN_READABLE
222 case 'h': disp_hr = 0; break; 221 case 'h': disp_hr = 0; break;
223 case 'm': disp_hr = MEGABYTE; break; 222 case 'm': disp_hr = MEGABYTE; break;
224#endif 223#endif
@@ -247,7 +246,7 @@ int du_main(int argc, char **argv)
247 return status; 246 return status;
248} 247}
249 248
250/* $Id: du.c,v 1.50 2001/06/30 17:54:20 andersen Exp $ */ 249/* $Id: du.c,v 1.51 2001/10/24 04:59:27 andersen Exp $ */
251/* 250/*
252Local Variables: 251Local Variables:
253c-file-style: "linux" 252c-file-style: "linux"
diff --git a/coreutils/head.c b/coreutils/head.c
index 688c250b1..4a1677146 100644
--- a/coreutils/head.c
+++ b/coreutils/head.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Mini head implementation for busybox 3 * Mini head implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999 by Lineo, inc. and John Beppu
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7 * Written by John Beppu <beppu@lineo.com>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/ln.c b/coreutils/ln.c
index 7412a86fd..213db9b72 100644
--- a/coreutils/ln.c
+++ b/coreutils/ln.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini ln implementation for busybox 3 * Mini ln implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 8d0282dfe..672a3bb3c 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -65,7 +65,7 @@ enum {
65#include <sys/ioctl.h> 65#include <sys/ioctl.h>
66#include "busybox.h" 66#include "busybox.h"
67 67
68#ifdef BB_FEATURE_LS_TIMESTAMPS 68#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
69#include <time.h> 69#include <time.h>
70#endif 70#endif
71 71
@@ -108,7 +108,7 @@ STYLE_COLUMNS = 3 /* fill columns */
108#define DISP_RECURSIVE (1<<4) /* show directory and everything below it */ 108#define DISP_RECURSIVE (1<<4) /* show directory and everything below it */
109#define DISP_ROWS (1<<5) /* print across rows */ 109#define DISP_ROWS (1<<5) /* print across rows */
110 110
111#ifdef BB_FEATURE_LS_SORTFILES 111#ifdef CONFIG_FEATURE_LS_SORTFILES
112/* how will the files be sorted */ 112/* how will the files be sorted */
113static const int SORT_FORWARD = 0; /* sort in reverse order */ 113static const int SORT_FORWARD = 0; /* sort in reverse order */
114static const int SORT_REVERSE = 1; /* sort in reverse order */ 114static const int SORT_REVERSE = 1; /* sort in reverse order */
@@ -122,7 +122,7 @@ static const int SORT_EXT = 8; /* sort by file name extension */
122static const int SORT_DIR = 9; /* sort by file or directory */ 122static const int SORT_DIR = 9; /* sort by file or directory */
123#endif 123#endif
124 124
125#ifdef BB_FEATURE_LS_TIMESTAMPS 125#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
126/* which of the three times will be used */ 126/* which of the three times will be used */
127static const int TIME_MOD = 0; 127static const int TIME_MOD = 0;
128static const int TIME_CHANGE = 1; 128static const int TIME_CHANGE = 1;
@@ -142,7 +142,7 @@ static const int SPLIT_SUBDIR = 2;
142 142
143#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) 143#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
144#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) 144#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
145#ifdef BB_FEATURE_LS_FILETYPES 145#ifdef CONFIG_FEATURE_LS_FILETYPES
146#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)]) 146#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
147#endif 147#endif
148 148
@@ -164,19 +164,19 @@ static int list_single(struct dnode *);
164static unsigned int disp_opts; 164static unsigned int disp_opts;
165static unsigned int style_fmt; 165static unsigned int style_fmt;
166static unsigned int list_fmt; 166static unsigned int list_fmt;
167#ifdef BB_FEATURE_LS_SORTFILES 167#ifdef CONFIG_FEATURE_LS_SORTFILES
168static unsigned int sort_opts; 168static unsigned int sort_opts;
169static unsigned int sort_order; 169static unsigned int sort_order;
170#endif 170#endif
171#ifdef BB_FEATURE_LS_TIMESTAMPS 171#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
172static unsigned int time_fmt; 172static unsigned int time_fmt;
173#endif 173#endif
174#ifdef BB_FEATURE_LS_FOLLOWLINKS 174#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
175static unsigned int follow_links=FALSE; 175static unsigned int follow_links=FALSE;
176#endif 176#endif
177 177
178static unsigned short column = 0; 178static unsigned short column = 0;
179#ifdef BB_FEATURE_AUTOWIDTH 179#ifdef CONFIG_FEATURE_AUTOWIDTH
180static unsigned short terminal_width = TERMINAL_WIDTH; 180static unsigned short terminal_width = TERMINAL_WIDTH;
181static unsigned short column_width = COLUMN_WIDTH; 181static unsigned short column_width = COLUMN_WIDTH;
182static unsigned short tabstops = COLUMN_GAP; 182static unsigned short tabstops = COLUMN_GAP;
@@ -186,13 +186,13 @@ static unsigned short column_width = COLUMN_WIDTH;
186 186
187static int status = EXIT_SUCCESS; 187static int status = EXIT_SUCCESS;
188 188
189#ifdef BB_FEATURE_HUMAN_READABLE 189#ifdef CONFIG_FEATURE_HUMAN_READABLE
190static unsigned long ls_disp_hr = 0; 190static unsigned long ls_disp_hr = 0;
191#endif 191#endif
192 192
193static int my_stat(struct dnode *cur) 193static int my_stat(struct dnode *cur)
194{ 194{
195#ifdef BB_FEATURE_LS_FOLLOWLINKS 195#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
196 if (follow_links == TRUE) { 196 if (follow_links == TRUE) {
197 if (stat(cur->fullname, &cur->dstat)) { 197 if (stat(cur->fullname, &cur->dstat)) {
198 perror_msg("%s", cur->fullname); 198 perror_msg("%s", cur->fullname);
@@ -222,7 +222,7 @@ static void newline(void)
222} 222}
223 223
224/*----------------------------------------------------------------------*/ 224/*----------------------------------------------------------------------*/
225#ifdef BB_FEATURE_LS_FILETYPES 225#ifdef CONFIG_FEATURE_LS_FILETYPES
226static char append_char(mode_t mode) 226static char append_char(mode_t mode)
227{ 227{
228 if ( !(list_fmt & LIST_FILETYPE)) 228 if ( !(list_fmt & LIST_FILETYPE))
@@ -304,7 +304,7 @@ static struct dnode **dnalloc(int num)
304 return(p); 304 return(p);
305} 305}
306 306
307#ifdef BB_FEATURE_LS_RECURSIVE 307#ifdef CONFIG_FEATURE_LS_RECURSIVE
308static void dfree(struct dnode **dnp) 308static void dfree(struct dnode **dnp)
309{ 309{
310 struct dnode *cur, *next; 310 struct dnode *cur, *next;
@@ -361,7 +361,7 @@ static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
361} 361}
362 362
363/*----------------------------------------------------------------------*/ 363/*----------------------------------------------------------------------*/
364#ifdef BB_FEATURE_LS_SORTFILES 364#ifdef CONFIG_FEATURE_LS_SORTFILES
365static int sortcmp(struct dnode *d1, struct dnode *d2) 365static int sortcmp(struct dnode *d1, struct dnode *d2)
366{ 366{
367 int cmp, dif; 367 int cmp, dif;
@@ -426,13 +426,13 @@ static void shellsort(struct dnode **dn, int size)
426static void showfiles(struct dnode **dn, int nfiles) 426static void showfiles(struct dnode **dn, int nfiles)
427{ 427{
428 int i, ncols, nrows, row, nc; 428 int i, ncols, nrows, row, nc;
429#ifdef BB_FEATURE_AUTOWIDTH 429#ifdef CONFIG_FEATURE_AUTOWIDTH
430 int len; 430 int len;
431#endif 431#endif
432 432
433 if(dn==NULL || nfiles < 1) return; 433 if(dn==NULL || nfiles < 1) return;
434 434
435#ifdef BB_FEATURE_AUTOWIDTH 435#ifdef CONFIG_FEATURE_AUTOWIDTH
436 /* find the longest file name- use that as the column width */ 436 /* find the longest file name- use that as the column width */
437 column_width= 0; 437 column_width= 0;
438 for (i=0; i<nfiles; i++) { 438 for (i=0; i<nfiles; i++) {
@@ -488,7 +488,7 @@ static void showdirs(struct dnode **dn, int ndirs)
488{ 488{
489 int i, nfiles; 489 int i, nfiles;
490 struct dnode **subdnp; 490 struct dnode **subdnp;
491#ifdef BB_FEATURE_LS_RECURSIVE 491#ifdef CONFIG_FEATURE_LS_RECURSIVE
492 int dndirs; 492 int dndirs;
493 struct dnode **dnd; 493 struct dnode **dnd;
494#endif 494#endif
@@ -503,17 +503,17 @@ static void showdirs(struct dnode **dn, int ndirs)
503 nfiles= countfiles(subdnp); 503 nfiles= countfiles(subdnp);
504 if (nfiles > 0) { 504 if (nfiles > 0) {
505 /* list all files at this level */ 505 /* list all files at this level */
506#ifdef BB_FEATURE_LS_SORTFILES 506#ifdef CONFIG_FEATURE_LS_SORTFILES
507 shellsort(subdnp, nfiles); 507 shellsort(subdnp, nfiles);
508#endif 508#endif
509 showfiles(subdnp, nfiles); 509 showfiles(subdnp, nfiles);
510#ifdef BB_FEATURE_LS_RECURSIVE 510#ifdef CONFIG_FEATURE_LS_RECURSIVE
511 if (disp_opts & DISP_RECURSIVE) { 511 if (disp_opts & DISP_RECURSIVE) {
512 /* recursive- list the sub-dirs */ 512 /* recursive- list the sub-dirs */
513 dnd= splitdnarray(subdnp, nfiles, SPLIT_SUBDIR); 513 dnd= splitdnarray(subdnp, nfiles, SPLIT_SUBDIR);
514 dndirs= countsubdirs(subdnp, nfiles); 514 dndirs= countsubdirs(subdnp, nfiles);
515 if (dndirs > 0) { 515 if (dndirs > 0) {
516#ifdef BB_FEATURE_LS_SORTFILES 516#ifdef CONFIG_FEATURE_LS_SORTFILES
517 shellsort(dnd, dndirs); 517 shellsort(dnd, dndirs);
518#endif 518#endif
519 showdirs(dnd, dndirs); 519 showdirs(dnd, dndirs);
@@ -582,26 +582,26 @@ static int list_single(struct dnode *dn)
582{ 582{
583 int i; 583 int i;
584 char scratch[BUFSIZ + 1]; 584 char scratch[BUFSIZ + 1];
585#ifdef BB_FEATURE_LS_TIMESTAMPS 585#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
586 char *filetime; 586 char *filetime;
587 time_t ttime, age; 587 time_t ttime, age;
588#endif 588#endif
589#if defined (BB_FEATURE_LS_FILETYPES) 589#if defined (CONFIG_FEATURE_LS_FILETYPES)
590 struct stat info; 590 struct stat info;
591#endif 591#endif
592#ifdef BB_FEATURE_LS_FILETYPES 592#ifdef CONFIG_FEATURE_LS_FILETYPES
593 char append; 593 char append;
594#endif 594#endif
595 595
596 if (dn==NULL || dn->fullname==NULL) return(0); 596 if (dn==NULL || dn->fullname==NULL) return(0);
597 597
598#ifdef BB_FEATURE_LS_TIMESTAMPS 598#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
599 ttime= dn->dstat.st_mtime; /* the default time */ 599 ttime= dn->dstat.st_mtime; /* the default time */
600 if (time_fmt & TIME_ACCESS) ttime= dn->dstat.st_atime; 600 if (time_fmt & TIME_ACCESS) ttime= dn->dstat.st_atime;
601 if (time_fmt & TIME_CHANGE) ttime= dn->dstat.st_ctime; 601 if (time_fmt & TIME_CHANGE) ttime= dn->dstat.st_ctime;
602 filetime= ctime(&ttime); 602 filetime= ctime(&ttime);
603#endif 603#endif
604#ifdef BB_FEATURE_LS_FILETYPES 604#ifdef CONFIG_FEATURE_LS_FILETYPES
605 append = append_char(dn->dstat.st_mode); 605 append = append_char(dn->dstat.st_mode);
606#endif 606#endif
607 607
@@ -612,7 +612,7 @@ static int list_single(struct dnode *dn)
612 column += 8; 612 column += 8;
613 break; 613 break;
614 case LIST_BLOCKS: 614 case LIST_BLOCKS:
615#ifdef BB_FEATURE_HUMAN_READABLE 615#ifdef CONFIG_FEATURE_HUMAN_READABLE
616 fprintf(stdout, "%6s ", make_human_readable_str(dn->dstat.st_blocks>>1, 616 fprintf(stdout, "%6s ", make_human_readable_str(dn->dstat.st_blocks>>1,
617 KILOBYTE, (ls_disp_hr==TRUE)? 0: KILOBYTE)); 617 KILOBYTE, (ls_disp_hr==TRUE)? 0: KILOBYTE));
618#else 618#else
@@ -633,7 +633,7 @@ static int list_single(struct dnode *dn)
633 column += 10; 633 column += 10;
634 break; 634 break;
635 case LIST_ID_NAME: 635 case LIST_ID_NAME:
636#ifdef BB_FEATURE_LS_USERNAME 636#ifdef CONFIG_FEATURE_LS_USERNAME
637 my_getpwuid(scratch, dn->dstat.st_uid); 637 my_getpwuid(scratch, dn->dstat.st_uid);
638 printf("%-8.8s ", scratch); 638 printf("%-8.8s ", scratch);
639 my_getgrgid(scratch, dn->dstat.st_gid); 639 my_getgrgid(scratch, dn->dstat.st_gid);
@@ -650,7 +650,7 @@ static int list_single(struct dnode *dn)
650 if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { 650 if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
651 printf("%4d, %3d ", (int)MAJOR(dn->dstat.st_rdev), (int)MINOR(dn->dstat.st_rdev)); 651 printf("%4d, %3d ", (int)MAJOR(dn->dstat.st_rdev), (int)MINOR(dn->dstat.st_rdev));
652 } else { 652 } else {
653#ifdef BB_FEATURE_HUMAN_READABLE 653#ifdef CONFIG_FEATURE_HUMAN_READABLE
654 if (ls_disp_hr==TRUE) { 654 if (ls_disp_hr==TRUE) {
655 fprintf(stdout, "%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0)); 655 fprintf(stdout, "%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0));
656 } else 656 } else
@@ -665,7 +665,7 @@ static int list_single(struct dnode *dn)
665 } 665 }
666 column += 10; 666 column += 10;
667 break; 667 break;
668#ifdef BB_FEATURE_LS_TIMESTAMPS 668#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
669 case LIST_FULLTIME: 669 case LIST_FULLTIME:
670 case LIST_DATE_TIME: 670 case LIST_DATE_TIME:
671 if (list_fmt & LIST_FULLTIME) { 671 if (list_fmt & LIST_FULLTIME) {
@@ -693,7 +693,7 @@ static int list_single(struct dnode *dn)
693 char *lpath = xreadlink(dn->fullname); 693 char *lpath = xreadlink(dn->fullname);
694 if (lpath) { 694 if (lpath) {
695 printf(" -> %s", lpath); 695 printf(" -> %s", lpath);
696#ifdef BB_FEATURE_LS_FILETYPES 696#ifdef CONFIG_FEATURE_LS_FILETYPES
697 if (!stat(dn->fullname, &info)) { 697 if (!stat(dn->fullname, &info)) {
698 append = append_char(info.st_mode); 698 append = append_char(info.st_mode);
699 } 699 }
@@ -703,7 +703,7 @@ static int list_single(struct dnode *dn)
703 } 703 }
704 } 704 }
705 break; 705 break;
706#ifdef BB_FEATURE_LS_FILETYPES 706#ifdef CONFIG_FEATURE_LS_FILETYPES
707 case LIST_FILETYPE: 707 case LIST_FILETYPE:
708 if (append != '\0') { 708 if (append != '\0') {
709 printf("%1c", append); 709 printf("%1c", append);
@@ -727,21 +727,21 @@ extern int ls_main(int argc, char **argv)
727 int opt; 727 int opt;
728 int oi, ac; 728 int oi, ac;
729 char **av; 729 char **av;
730#ifdef BB_FEATURE_AUTOWIDTH 730#ifdef CONFIG_FEATURE_AUTOWIDTH
731 struct winsize win = { 0, 0, 0, 0 }; 731 struct winsize win = { 0, 0, 0, 0 };
732#endif 732#endif
733 733
734 disp_opts= DISP_NORMAL; 734 disp_opts= DISP_NORMAL;
735 style_fmt= STYLE_AUTO; 735 style_fmt= STYLE_AUTO;
736 list_fmt= LIST_SHORT; 736 list_fmt= LIST_SHORT;
737#ifdef BB_FEATURE_LS_SORTFILES 737#ifdef CONFIG_FEATURE_LS_SORTFILES
738 sort_opts= SORT_NAME; 738 sort_opts= SORT_NAME;
739 sort_order= SORT_FORWARD; 739 sort_order= SORT_FORWARD;
740#endif 740#endif
741#ifdef BB_FEATURE_LS_TIMESTAMPS 741#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
742 time_fmt= TIME_MOD; 742 time_fmt= TIME_MOD;
743#endif 743#endif
744#ifdef BB_FEATURE_AUTOWIDTH 744#ifdef CONFIG_FEATURE_AUTOWIDTH
745 ioctl(fileno(stdout), TIOCGWINSZ, &win); 745 ioctl(fileno(stdout), TIOCGWINSZ, &win);
746 if (win.ws_row > 4) 746 if (win.ws_row > 4)
747 column_width = win.ws_row - 2; 747 column_width = win.ws_row - 2;
@@ -752,25 +752,25 @@ extern int ls_main(int argc, char **argv)
752 752
753 /* process options */ 753 /* process options */
754 while ((opt = getopt(argc, argv, "1AaCdgilnsx" 754 while ((opt = getopt(argc, argv, "1AaCdgilnsx"
755#ifdef BB_FEATURE_AUTOWIDTH 755#ifdef CONFIG_FEATURE_AUTOWIDTH
756"T:w:" 756"T:w:"
757#endif 757#endif
758#ifdef BB_FEATURE_LS_FILETYPES 758#ifdef CONFIG_FEATURE_LS_FILETYPES
759"Fp" 759"Fp"
760#endif 760#endif
761#ifdef BB_FEATURE_LS_RECURSIVE 761#ifdef CONFIG_FEATURE_LS_RECURSIVE
762"R" 762"R"
763#endif 763#endif
764#ifdef BB_FEATURE_LS_SORTFILES 764#ifdef CONFIG_FEATURE_LS_SORTFILES
765"rSvX" 765"rSvX"
766#endif 766#endif
767#ifdef BB_FEATURE_LS_TIMESTAMPS 767#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
768"cetu" 768"cetu"
769#endif 769#endif
770#ifdef BB_FEATURE_LS_FOLLOWLINKS 770#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
771"L" 771"L"
772#endif 772#endif
773#ifdef BB_FEATURE_HUMAN_READABLE 773#ifdef CONFIG_FEATURE_HUMAN_READABLE
774"h" 774"h"
775#endif 775#endif
776"k")) > 0) { 776"k")) > 0) {
@@ -785,54 +785,54 @@ extern int ls_main(int argc, char **argv)
785 case 'l': 785 case 'l':
786 style_fmt = STYLE_LONG; 786 style_fmt = STYLE_LONG;
787 list_fmt |= LIST_LONG; 787 list_fmt |= LIST_LONG;
788#ifdef BB_FEATURE_HUMAN_READABLE 788#ifdef CONFIG_FEATURE_HUMAN_READABLE
789 ls_disp_hr = FALSE; 789 ls_disp_hr = FALSE;
790#endif 790#endif
791 break; 791 break;
792 case 'n': list_fmt |= LIST_ID_NUMERIC; break; 792 case 'n': list_fmt |= LIST_ID_NUMERIC; break;
793 case 's': list_fmt |= LIST_BLOCKS; break; 793 case 's': list_fmt |= LIST_BLOCKS; break;
794 case 'x': disp_opts = DISP_ROWS; break; 794 case 'x': disp_opts = DISP_ROWS; break;
795#ifdef BB_FEATURE_LS_FILETYPES 795#ifdef CONFIG_FEATURE_LS_FILETYPES
796 case 'F': list_fmt |= LIST_FILETYPE | LIST_EXEC; break; 796 case 'F': list_fmt |= LIST_FILETYPE | LIST_EXEC; break;
797 case 'p': list_fmt |= LIST_FILETYPE; break; 797 case 'p': list_fmt |= LIST_FILETYPE; break;
798#endif 798#endif
799#ifdef BB_FEATURE_LS_RECURSIVE 799#ifdef CONFIG_FEATURE_LS_RECURSIVE
800 case 'R': disp_opts |= DISP_RECURSIVE; break; 800 case 'R': disp_opts |= DISP_RECURSIVE; break;
801#endif 801#endif
802#ifdef BB_FEATURE_LS_SORTFILES 802#ifdef CONFIG_FEATURE_LS_SORTFILES
803 case 'r': sort_order |= SORT_REVERSE; break; 803 case 'r': sort_order |= SORT_REVERSE; break;
804 case 'S': sort_opts= SORT_SIZE; break; 804 case 'S': sort_opts= SORT_SIZE; break;
805 case 'v': sort_opts= SORT_VERSION; break; 805 case 'v': sort_opts= SORT_VERSION; break;
806 case 'X': sort_opts= SORT_EXT; break; 806 case 'X': sort_opts= SORT_EXT; break;
807#endif 807#endif
808#ifdef BB_FEATURE_LS_TIMESTAMPS 808#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
809 case 'e': list_fmt |= LIST_FULLTIME; break; 809 case 'e': list_fmt |= LIST_FULLTIME; break;
810 case 'c': 810 case 'c':
811 time_fmt = TIME_CHANGE; 811 time_fmt = TIME_CHANGE;
812#ifdef BB_FEATURE_LS_SORTFILES 812#ifdef CONFIG_FEATURE_LS_SORTFILES
813 sort_opts= SORT_CTIME; 813 sort_opts= SORT_CTIME;
814#endif 814#endif
815 break; 815 break;
816 case 'u': 816 case 'u':
817 time_fmt = TIME_ACCESS; 817 time_fmt = TIME_ACCESS;
818#ifdef BB_FEATURE_LS_SORTFILES 818#ifdef CONFIG_FEATURE_LS_SORTFILES
819 sort_opts= SORT_ATIME; 819 sort_opts= SORT_ATIME;
820#endif 820#endif
821 break; 821 break;
822 case 't': 822 case 't':
823#ifdef BB_FEATURE_LS_SORTFILES 823#ifdef CONFIG_FEATURE_LS_SORTFILES
824 sort_opts= SORT_MTIME; 824 sort_opts= SORT_MTIME;
825#endif 825#endif
826 break; 826 break;
827#endif 827#endif
828#ifdef BB_FEATURE_LS_FOLLOWLINKS 828#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
829 case 'L': follow_links= TRUE; break; 829 case 'L': follow_links= TRUE; break;
830#endif 830#endif
831#ifdef BB_FEATURE_AUTOWIDTH 831#ifdef CONFIG_FEATURE_AUTOWIDTH
832 case 'T': tabstops= atoi(optarg); break; 832 case 'T': tabstops= atoi(optarg); break;
833 case 'w': terminal_width= atoi(optarg); break; 833 case 'w': terminal_width= atoi(optarg); break;
834#endif 834#endif
835#ifdef BB_FEATURE_HUMAN_READABLE 835#ifdef CONFIG_FEATURE_HUMAN_READABLE
836 case 'h': ls_disp_hr = TRUE; break; 836 case 'h': ls_disp_hr = TRUE; break;
837#endif 837#endif
838 case 'k': break; 838 case 'k': break;
@@ -842,17 +842,17 @@ extern int ls_main(int argc, char **argv)
842 } 842 }
843 843
844 /* sort out which command line options take precedence */ 844 /* sort out which command line options take precedence */
845#ifdef BB_FEATURE_LS_RECURSIVE 845#ifdef CONFIG_FEATURE_LS_RECURSIVE
846 if (disp_opts & DISP_NOLIST) 846 if (disp_opts & DISP_NOLIST)
847 disp_opts &= ~DISP_RECURSIVE; /* no recurse if listing only dir */ 847 disp_opts &= ~DISP_RECURSIVE; /* no recurse if listing only dir */
848#endif 848#endif
849#if defined (BB_FEATURE_LS_TIMESTAMPS) && defined (BB_FEATURE_LS_SORTFILES) 849#if defined (CONFIG_FEATURE_LS_TIMESTAMPS) && defined (CONFIG_FEATURE_LS_SORTFILES)
850 if (time_fmt & TIME_CHANGE) sort_opts= SORT_CTIME; 850 if (time_fmt & TIME_CHANGE) sort_opts= SORT_CTIME;
851 if (time_fmt & TIME_ACCESS) sort_opts= SORT_ATIME; 851 if (time_fmt & TIME_ACCESS) sort_opts= SORT_ATIME;
852#endif 852#endif
853 if (style_fmt != STYLE_LONG) 853 if (style_fmt != STYLE_LONG)
854 list_fmt &= ~LIST_ID_NUMERIC; /* numeric uid only for long list */ 854 list_fmt &= ~LIST_ID_NUMERIC; /* numeric uid only for long list */
855#ifdef BB_FEATURE_LS_USERNAME 855#ifdef CONFIG_FEATURE_LS_USERNAME
856 if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC)) 856 if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC))
857 list_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */ 857 list_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */
858#endif 858#endif
@@ -908,7 +908,7 @@ extern int ls_main(int argc, char **argv)
908 908
909 909
910 if (disp_opts & DISP_NOLIST) { 910 if (disp_opts & DISP_NOLIST) {
911#ifdef BB_FEATURE_LS_SORTFILES 911#ifdef CONFIG_FEATURE_LS_SORTFILES
912 shellsort(dnp, nfiles); 912 shellsort(dnp, nfiles);
913#endif 913#endif
914 if (nfiles > 0) showfiles(dnp, nfiles); 914 if (nfiles > 0) showfiles(dnp, nfiles);
@@ -918,13 +918,13 @@ extern int ls_main(int argc, char **argv)
918 dndirs= countdirs(dnp, nfiles); 918 dndirs= countdirs(dnp, nfiles);
919 dnfiles= nfiles - dndirs; 919 dnfiles= nfiles - dndirs;
920 if (dnfiles > 0) { 920 if (dnfiles > 0) {
921#ifdef BB_FEATURE_LS_SORTFILES 921#ifdef CONFIG_FEATURE_LS_SORTFILES
922 shellsort(dnf, dnfiles); 922 shellsort(dnf, dnfiles);
923#endif 923#endif
924 showfiles(dnf, dnfiles); 924 showfiles(dnf, dnfiles);
925 } 925 }
926 if (dndirs > 0) { 926 if (dndirs > 0) {
927#ifdef BB_FEATURE_LS_SORTFILES 927#ifdef CONFIG_FEATURE_LS_SORTFILES
928 shellsort(dnd, dndirs); 928 shellsort(dnd, dndirs);
929#endif 929#endif
930 showdirs(dnd, dndirs); 930 showdirs(dnd, dndirs);
diff --git a/coreutils/rmdir.c b/coreutils/rmdir.c
index cac27cac9..83b27c9bd 100644
--- a/coreutils/rmdir.c
+++ b/coreutils/rmdir.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Mini rmdir implementation for busybox 3 * Mini rmdir implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 4f4979cc5..fc12dfb01 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -43,10 +43,10 @@ int sort_main(int argc, char **argv)
43 char *line, **lines = NULL; 43 char *line, **lines = NULL;
44 int i, opt, nlines = 0; 44 int i, opt, nlines = 0;
45 int (*compare)(const void *, const void *) = compare_ascii; 45 int (*compare)(const void *, const void *) = compare_ascii;
46#ifdef BB_FEATURE_SORT_REVERSE 46#ifdef CONFIG_FEATURE_SORT_REVERSE
47 int reverse = FALSE; 47 int reverse = FALSE;
48#endif 48#endif
49#ifdef BB_FEATURE_SORT_UNIQUE 49#ifdef CONFIG_FEATURE_SORT_UNIQUE
50 int unique = FALSE; 50 int unique = FALSE;
51#endif 51#endif
52 52
@@ -55,12 +55,12 @@ int sort_main(int argc, char **argv)
55 case 'n': 55 case 'n':
56 compare = compare_numeric; 56 compare = compare_numeric;
57 break; 57 break;
58#ifdef BB_FEATURE_SORT_REVERSE 58#ifdef CONFIG_FEATURE_SORT_REVERSE
59 case 'r': 59 case 'r':
60 reverse = TRUE; 60 reverse = TRUE;
61 break; 61 break;
62#endif 62#endif
63#ifdef BB_FEATURE_SORT_UNIQUE 63#ifdef CONFIG_FEATURE_SORT_UNIQUE
64 case 'u': 64 case 'u':
65 unique = TRUE; 65 unique = TRUE;
66 break; 66 break;
@@ -88,17 +88,17 @@ int sort_main(int argc, char **argv)
88 qsort(lines, nlines, sizeof(char *), compare); 88 qsort(lines, nlines, sizeof(char *), compare);
89 89
90 /* print it */ 90 /* print it */
91#ifdef BB_FEATURE_SORT_REVERSE 91#ifdef CONFIG_FEATURE_SORT_REVERSE
92 if (reverse) { 92 if (reverse) {
93 for (i = --nlines; 0 <= i; i--) 93 for (i = --nlines; 0 <= i; i--)
94#ifdef BB_FEATURE_SORT_UNIQUE 94#ifdef CONFIG_FEATURE_SORT_UNIQUE
95 if((!unique) || (i == nlines) || (strcmp(lines[i + 1], lines[i]))) 95 if((!unique) || (i == nlines) || (strcmp(lines[i + 1], lines[i])))
96#endif 96#endif
97 puts(lines[i]); 97 puts(lines[i]);
98 } else 98 } else
99#endif 99#endif
100 for (i = 0; i < nlines; i++) 100 for (i = 0; i < nlines; i++)
101#ifdef BB_FEATURE_SORT_UNIQUE 101#ifdef CONFIG_FEATURE_SORT_UNIQUE
102 if((!unique) || (!i) || (strcmp(lines[i - 1], lines[i]))) 102 if((!unique) || (!i) || (strcmp(lines[i - 1], lines[i])))
103#endif 103#endif
104 puts(lines[i]); 104 puts(lines[i]);
diff --git a/coreutils/tail.c b/coreutils/tail.c
index 5e5fbc14f..0c8dec26a 100644
--- a/coreutils/tail.c
+++ b/coreutils/tail.c
@@ -73,7 +73,7 @@ int tail_main(int argc, char **argv)
73 case 'f': 73 case 'f':
74 follow = 1; 74 follow = 1;
75 break; 75 break;
76#ifdef BB_FEATURE_FANCY_TAIL 76#ifdef CONFIG_FEATURE_FANCY_TAIL
77 case 'c': 77 case 'c':
78 units = BYTES; 78 units = BYTES;
79 /* FALLS THROUGH */ 79 /* FALLS THROUGH */
@@ -85,7 +85,7 @@ int tail_main(int argc, char **argv)
85 if (optarg[0] == '+') 85 if (optarg[0] == '+')
86 from_top = 1; 86 from_top = 1;
87 break; 87 break;
88#ifdef BB_FEATURE_FANCY_TAIL 88#ifdef CONFIG_FEATURE_FANCY_TAIL
89 case 'q': 89 case 'q':
90 hide_headers = 1; 90 hide_headers = 1;
91 break; 91 break;
@@ -118,7 +118,7 @@ int tail_main(int argc, char **argv)
118 } 118 }
119 } 119 }
120 120
121#ifdef BB_FEATURE_FANCY_TAIL 121#ifdef CONFIG_FEATURE_FANCY_TAIL
122 /* tail the files */ 122 /* tail the files */
123 if (!from_top && units == BYTES) 123 if (!from_top && units == BYTES)
124 tailbuf = xmalloc(count); 124 tailbuf = xmalloc(count);
@@ -136,7 +136,7 @@ int tail_main(int argc, char **argv)
136 printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]); 136 printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]);
137 while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) { 137 while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) {
138 if (from_top) { 138 if (from_top) {
139#ifdef BB_FEATURE_FANCY_TAIL 139#ifdef CONFIG_FEATURE_FANCY_TAIL
140 if (units == BYTES) { 140 if (units == BYTES) {
141 if (count - 1 <= seen) 141 if (count - 1 <= seen)
142 nwrite = nread; 142 nwrite = nread;
@@ -169,7 +169,7 @@ int tail_main(int argc, char **argv)
169 break; 169 break;
170 } 170 }
171 } else { 171 } else {
172#ifdef BB_FEATURE_FANCY_TAIL 172#ifdef CONFIG_FEATURE_FANCY_TAIL
173 if (units == BYTES) { 173 if (units == BYTES) {
174 if (nread < count) { 174 if (nread < count) {
175 memmove(tailbuf, tailbuf + nread, count - nread); 175 memmove(tailbuf, tailbuf + nread, count - nread);
@@ -203,7 +203,7 @@ int tail_main(int argc, char **argv)
203 status = EXIT_FAILURE; 203 status = EXIT_FAILURE;
204 } 204 }
205 205
206#ifdef BB_FEATURE_FANCY_TAIL 206#ifdef CONFIG_FEATURE_FANCY_TAIL
207 if (!from_top && units == BYTES) { 207 if (!from_top && units == BYTES) {
208 if (count < seen) 208 if (count < seen)
209 seen = count; 209 seen = count;
diff --git a/coreutils/tee.c b/coreutils/tee.c
index 64a0922b7..1c145426a 100644
--- a/coreutils/tee.c
+++ b/coreutils/tee.c
@@ -2,8 +2,7 @@
2/* 2/*
3 * Mini tee implementation for busybox 3 * Mini tee implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 2000,2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 * 6 *
8 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/touch.c b/coreutils/touch.c
index 1718da71e..267349596 100644
--- a/coreutils/touch.c
+++ b/coreutils/touch.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Mini touch implementation for busybox 3 * Mini touch implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/coreutils/tr.c b/coreutils/tr.c
index 5b7b8d091..2665d926f 100644
--- a/coreutils/tr.c
+++ b/coreutils/tr.c
@@ -155,11 +155,11 @@ extern int tr_main(int argc, char **argv)
155 int output_length=0, input_length; 155 int output_length=0, input_length;
156 int idx = 1; 156 int idx = 1;
157 int i; 157 int i;
158 RESERVE_BB_BUFFER(output, BUFSIZ); 158 RESERVE_CONFIG_BUFFER(output, BUFSIZ);
159 RESERVE_BB_BUFFER(input, BUFSIZ); 159 RESERVE_CONFIG_BUFFER(input, BUFSIZ);
160 RESERVE_BB_UBUFFER(vector, ASCII+1); 160 RESERVE_CONFIG_UBUFFER(vector, ASCII+1);
161 RESERVE_BB_BUFFER(invec, ASCII+1); 161 RESERVE_CONFIG_BUFFER(invec, ASCII+1);
162 RESERVE_BB_BUFFER(outvec, ASCII+1); 162 RESERVE_CONFIG_BUFFER(outvec, ASCII+1);
163 163
164 /* ... but make them available globally */ 164 /* ... but make them available globally */
165 poutput = output; 165 poutput = output;
diff --git a/coreutils/uniq.c b/coreutils/uniq.c
index 53e3c64f2..cb63c4277 100644
--- a/coreutils/uniq.c
+++ b/coreutils/uniq.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Mini uniq implementation for busybox 3 * Mini uniq implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999 by Lineo, inc. and John Beppu
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7 * Written by John Beppu <beppu@lineo.com>
8 * Rewritten by Matt Kraai <kraai@alumni.carnegiemellon.edu> 7 * Rewritten by Matt Kraai <kraai@alumni.carnegiemellon.edu>
9 * 8 *
10 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
diff --git a/coreutils/uuencode.c b/coreutils/uuencode.c
index fc037403a..0a362a262 100644
--- a/coreutils/uuencode.c
+++ b/coreutils/uuencode.c
@@ -84,8 +84,8 @@ int uuencode_main(int argc, char **argv)
84{ 84{
85 const int src_buf_size = 60; // This *MUST* be a multiple of 3 85 const int src_buf_size = 60; // This *MUST* be a multiple of 3
86 const int dst_buf_size = 4 * ((src_buf_size + 2) / 3); 86 const int dst_buf_size = 4 * ((src_buf_size + 2) / 3);
87 RESERVE_BB_BUFFER(src_buf, src_buf_size + 1); 87 RESERVE_CONFIG_BUFFER(src_buf, src_buf_size + 1);
88 RESERVE_BB_BUFFER(dst_buf, dst_buf_size + 1); 88 RESERVE_CONFIG_BUFFER(dst_buf, dst_buf_size + 1);
89 struct stat stat_buf; 89 struct stat stat_buf;
90 FILE *src_stream = stdin; 90 FILE *src_stream = stdin;
91 char *tbl = tbl_std; 91 char *tbl = tbl_std;
diff --git a/cp.c b/cp.c
deleted file mode 100644
index 8f8fe5ed3..000000000
--- a/cp.c
+++ /dev/null
@@ -1,114 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini cp implementation for busybox
4 *
5 *
6 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <utime.h>
29#include <errno.h>
30#include <dirent.h>
31#include <stdlib.h>
32
33#include "busybox.h"
34
35extern int cp_main(int argc, char **argv)
36{
37 int status = 0;
38 int opt;
39 int flags = FILEUTILS_DEREFERENCE;
40 int i;
41
42 while ((opt = getopt(argc, argv, "adfipR")) != -1)
43 switch (opt) {
44 case 'a':
45 flags |= FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR;
46 /* fallthrough */
47 case 'd':
48 flags &= ~FILEUTILS_DEREFERENCE;
49 break;
50 case 'f':
51 flags |= FILEUTILS_FORCE;
52 break;
53 case 'i':
54 flags |= FILEUTILS_INTERACTIVE;
55 break;
56 case 'p':
57 flags |= FILEUTILS_PRESERVE_STATUS;
58 break;
59 case 'R':
60 flags |= FILEUTILS_RECUR;
61 break;
62 default:
63 show_usage();
64 }
65
66 if (optind + 2 > argc)
67 show_usage();
68
69 /* If there are only two arguments and... */
70 if (optind + 2 == argc) {
71 struct stat source_stat;
72 struct stat dest_stat;
73 int source_exists = 1;
74 int dest_exists = 1;
75
76 if ((!(flags & FILEUTILS_DEREFERENCE) &&
77 lstat(argv[optind], &source_stat) < 0) ||
78 ((flags & FILEUTILS_DEREFERENCE) &&
79 stat(argv[optind], &source_stat))) {
80 if (errno != ENOENT)
81 perror_msg_and_die("unable to stat `%s'", argv[optind]);
82 source_exists = 0;
83 }
84
85 if (stat(argv[optind + 1], &dest_stat) < 0) {
86 if (errno != ENOENT)
87 perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
88 dest_exists = 0;
89 }
90
91 /* ...if neither is a directory or... */
92 if (((!source_exists || !S_ISDIR(source_stat.st_mode)) &&
93 (!dest_exists || !S_ISDIR(dest_stat.st_mode))) ||
94 /* ...recursing, the first is a directory, and the
95 * second doesn't exist, then... */
96 ((flags & FILEUTILS_RECUR) && S_ISDIR(source_stat.st_mode) &&
97 !dest_exists)) {
98 /* ...do a simple copy. */
99 if (copy_file(argv[optind], argv[optind + 1], flags) < 0)
100 status = 1;
101 return status;
102 }
103 }
104
105 for (i = optind; i < argc - 1; i++) {
106 char *dest = concat_path_file(argv[argc - 1],
107 get_last_path_component(argv[i]));
108 if (copy_file(argv[i], dest, flags) < 0)
109 status = 1;
110 free(dest);
111 }
112
113 return status;
114}
diff --git a/cpio.c b/cpio.c
deleted file mode 100644
index 372f9f5b1..000000000
--- a/cpio.c
+++ /dev/null
@@ -1,95 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini cpio implementation for busybox
4 *
5 * Copyright (C) 2001 by Glenn McGrath
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * Limitations:
22 * Doesn't check CRC's
23 * Only supports new ASCII and CRC formats
24 *
25 */
26#include <fcntl.h>
27#include <getopt.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31#include "busybox.h"
32
33extern int cpio_main(int argc, char **argv)
34{
35 FILE *src_stream = stdin;
36 char **extract_names = NULL;
37 int extract_function = 0;
38 int num_of_entries = 0;
39 int opt = 0;
40 mode_t oldmask = 0;
41
42 while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) {
43 switch (opt) {
44 case 'i': // extract
45 extract_function |= extract_all_to_fs;
46 break;
47 case 'd': // create _leading_ directories
48 extract_function |= extract_create_leading_dirs;
49 oldmask = umask(077); /* Make make_directory act like GNU cpio */
50 break;
51 case 'm': // preserve modification time
52 extract_function |= extract_preserve_date;
53 break;
54 case 'v': // verbosly list files
55 extract_function |= extract_verbose_list;
56 break;
57 case 'u': // unconditional
58 extract_function |= extract_unconditional;
59 break;
60 case 't': // list files
61 extract_function |= extract_list;
62 break;
63 case 'F':
64 src_stream = xfopen(optarg, "r");
65 break;
66 default:
67 show_usage();
68 }
69 }
70
71 if ((extract_function & extract_all_to_fs) && (extract_function & extract_list)) {
72 extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/
73 }
74
75 if ((extract_function & extract_all_to_fs) && (extract_function & extract_verbose_list)) {
76 /* The meaning of v changes on extract */
77 extract_function ^= extract_verbose_list;
78 extract_function |= extract_list;
79 }
80
81 while (optind < argc) {
82 extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
83 extract_names[num_of_entries] = xstrdup(argv[optind]);
84 num_of_entries++;
85 extract_names[num_of_entries] = NULL;
86 optind++;
87 }
88
89 unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names, NULL);
90 if (oldmask) {
91 umask(oldmask); /* Restore umask if we changed it */
92 }
93 return EXIT_SUCCESS;
94}
95
diff --git a/cut.c b/cut.c
deleted file mode 100644
index 3ed264870..000000000
--- a/cut.c
+++ /dev/null
@@ -1,356 +0,0 @@
1/*
2 * cut.c - minimalist version of cut
3 *
4 * Copyright (C) 1999,2000,2001 by Lineo, inc.
5 * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h> /* getopt */
26#include <string.h>
27#include <limits.h>
28#include "busybox.h"
29
30
31/* globals from other files */
32extern int optind;
33extern char *optarg;
34
35
36/* option vars */
37static char part = 0; /* (b)yte, (c)har, (f)ields */
38static unsigned int supress_non_delimited_lines = 0;
39static char delim = '\t'; /* delimiter, default is tab */
40
41struct cut_list {
42 int startpos;
43 int endpos;
44};
45
46static const int BOL = 0;
47static const int EOL = INT_MAX;
48static const int NON_RANGE = -1;
49
50static struct cut_list *cut_lists = NULL; /* growable array holding a series of lists */
51static unsigned int nlists = 0; /* number of elements in above list */
52
53
54static int cmpfunc(const void *a, const void *b)
55{
56 struct cut_list *la = (struct cut_list *)a;
57 struct cut_list *lb = (struct cut_list *)b;
58
59 if (la->startpos > lb->startpos)
60 return 1;
61 if (la->startpos < lb->startpos)
62 return -1;
63 return 0;
64}
65
66
67/*
68 * parse_lists() - parses a list and puts values into startpos and endpos.
69 * valid list formats: N, N-, N-M, -M
70 * more than one list can be seperated by commas
71 */
72static void parse_lists(char *lists)
73{
74 char *ltok = NULL;
75 char *ntok = NULL;
76 char *junk;
77 int s = 0, e = 0;
78
79 /* take apart the lists, one by one (they are seperated with commas */
80 while ((ltok = strsep(&lists, ",")) != NULL) {
81
82 /* it's actually legal to pass an empty list */
83 if (strlen(ltok) == 0)
84 continue;
85
86 /* get the start pos */
87 ntok = strsep(&ltok, "-");
88 if (ntok == NULL) {
89 fprintf(stderr, "Help ntok is null for starting position! What do I do?\n");
90 } else if (strlen(ntok) == 0) {
91 s = BOL;
92 } else {
93 s = strtoul(ntok, &junk, 10);
94 if(*junk != '\0' || s < 0)
95 error_msg_and_die("invalid byte or field list");
96
97 /* account for the fact that arrays are zero based, while the user
98 * expects the first char on the line to be char # 1 */
99 if (s != 0)
100 s--;
101 }
102
103 /* get the end pos */
104 ntok = strsep(&ltok, "-");
105 if (ntok == NULL) {
106 e = NON_RANGE;
107 } else if (strlen(ntok) == 0) {
108 e = EOL;
109 } else {
110 e = strtoul(ntok, &junk, 10);
111 if(*junk != '\0' || e < 0)
112 error_msg_and_die("invalid byte or field list");
113 /* if the user specified and end position of 0, that means "til the
114 * end of the line */
115 if (e == 0)
116 e = INT_MAX;
117 e--; /* again, arrays are zero based, lines are 1 based */
118 if (e == s)
119 e = NON_RANGE;
120 }
121
122 /* if there's something left to tokenize, the user past an invalid list */
123 if (ltok)
124 error_msg_and_die("invalid byte or field list");
125
126 /* add the new list */
127 cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
128 cut_lists[nlists-1].startpos = s;
129 cut_lists[nlists-1].endpos = e;
130 }
131
132 /* make sure we got some cut positions out of all that */
133 if (nlists == 0)
134 error_msg_and_die("missing list of positions");
135
136 /* now that the lists are parsed, we need to sort them to make life easier
137 * on us when it comes time to print the chars / fields / lines */
138 qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
139
140}
141
142
143static void cut_line_by_chars(const char *line)
144{
145 int c, l;
146 /* set up a list so we can keep track of what's been printed */
147 char *printed = xcalloc(strlen(line), sizeof(char));
148
149 /* print the chars specified in each cut list */
150 for (c = 0; c < nlists; c++) {
151 l = cut_lists[c].startpos;
152 while (l < strlen(line)) {
153 if (!printed[l]) {
154 putchar(line[l]);
155 printed[l] = 'X';
156 }
157 l++;
158 if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos)
159 break;
160 }
161 }
162 putchar('\n'); /* cuz we were handed a chomped line */
163 free(printed);
164}
165
166
167static void cut_line_by_fields(char *line)
168{
169 int c, f;
170 int ndelim = -1; /* zero-based / one-based problem */
171 int nfields_printed = 0;
172 char *field = NULL;
173 char d[2] = { delim, 0 };
174 char *printed;
175
176 /* test the easy case first: does this line contain any delimiters? */
177 if (strchr(line, delim) == NULL) {
178 if (!supress_non_delimited_lines)
179 puts(line);
180 return;
181 }
182
183 /* set up a list so we can keep track of what's been printed */
184 printed = xcalloc(strlen(line), sizeof(char));
185
186 /* process each list on this line, for as long as we've got a line to process */
187 for (c = 0; c < nlists && line; c++) {
188 f = cut_lists[c].startpos;
189 do {
190
191 /* find the field we're looking for */
192 while (line && ndelim < f) {
193 field = strsep(&line, d);
194 ndelim++;
195 }
196
197 /* we found it, and it hasn't been printed yet */
198 if (field && ndelim == f && !printed[ndelim]) {
199 /* if this isn't our first time through, we need to print the
200 * delimiter after the last field that was printed */
201 if (nfields_printed > 0)
202 putchar(delim);
203 fputs(field, stdout);
204 printed[ndelim] = 'X';
205 nfields_printed++;
206 }
207
208 f++;
209
210 /* keep going as long as we have a line to work with, this is a
211 * list, and we're not at the end of that list */
212 } while (line && cut_lists[c].endpos != NON_RANGE && f <= cut_lists[c].endpos);
213 }
214
215 /* if we printed anything at all, we need to finish it with a newline cuz
216 * we were handed a chomped line */
217 putchar('\n');
218
219 free(printed);
220}
221
222
223static void cut_file_by_lines(const char *line, unsigned int linenum)
224{
225 static int c = 0;
226 static int l = -1;
227
228 /* I can't initialize this above cuz the "initializer isn't
229 * constant" *sigh* */
230 if (l == -1)
231 l = cut_lists[c].startpos;
232
233 /* get out if we have no more lists to process or if the lines are lower
234 * than what we're interested in */
235 if (c >= nlists || linenum < l)
236 return;
237
238 /* if the line we're looking for is lower than the one we were passed, it
239 * means we displayed it already, so move on */
240 while (l < linenum) {
241 l++;
242 /* move on to the next list if we're at the end of this one */
243 if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos) {
244 c++;
245 /* get out if there's no more lists to process */
246 if (c >= nlists)
247 return;
248 l = cut_lists[c].startpos;
249 /* get out if the current line is lower than the one we just became
250 * interested in */
251 if (linenum < l)
252 return;
253 }
254 }
255
256 /* If we made it here, it means we've found the line we're looking for, so print it */
257 puts(line);
258}
259
260
261/*
262 * snippy-snip
263 */
264static void cut_file(FILE *file)
265{
266 char *line = NULL;
267 unsigned int linenum = 0; /* keep these zero-based to be consistent */
268
269 /* go through every line in the file */
270 while ((line = get_line_from_file(file)) != NULL) {
271 chomp(line);
272
273 /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
274 if (part == 'c' || part == 'b')
275 cut_line_by_chars(line);
276
277 /* cut based on fields */
278 else if (part == 'f') {
279 if (delim == '\n')
280 cut_file_by_lines(line, linenum);
281 else
282 cut_line_by_fields(line);
283 }
284
285 linenum++;
286 free(line);
287 }
288}
289
290
291extern int cut_main(int argc, char **argv)
292{
293 int opt;
294
295 while ((opt = getopt(argc, argv, "b:c:d:f:ns")) > 0) {
296 switch (opt) {
297 case 'b':
298 case 'c':
299 case 'f':
300 /* make sure they didn't ask for two types of lists */
301 if (part != 0) {
302 error_msg_and_die("only one type of list may be specified");
303 }
304 part = (char)opt;
305 parse_lists(optarg);
306 break;
307 case 'd':
308 if (strlen(optarg) > 1) {
309 error_msg_and_die("the delimiter must be a single character");
310 }
311 delim = optarg[0];
312 break;
313 case 'n':
314 /* no-op */
315 break;
316 case 's':
317 supress_non_delimited_lines++;
318 break;
319 }
320 }
321
322 if (part == 0) {
323 error_msg_and_die("you must specify a list of bytes, characters, or fields");
324 }
325
326 /* non-field (char or byte) cutting has some special handling */
327 if (part != 'f') {
328 if (supress_non_delimited_lines) {
329 error_msg_and_die("suppressing non-delimited lines makes sense"
330 " only when operating on fields");
331 }
332 if (delim != '\t' && part != 'f') {
333 error_msg_and_die("a delimiter may be specified only when operating on fields");
334 }
335 }
336
337 /* argv[(optind)..(argc-1)] should be names of file to process. If no
338 * files were specified or '-' was specified, take input from stdin.
339 * Otherwise, we process all the files specified. */
340 if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
341 cut_file(stdin);
342 }
343 else {
344 int i;
345 FILE *file;
346 for (i = optind; i < argc; i++) {
347 file = wfopen(argv[i], "r");
348 if(file) {
349 cut_file(file);
350 fclose(file);
351 }
352 }
353 }
354
355 return EXIT_SUCCESS;
356}
diff --git a/date.c b/date.c
deleted file mode 100644
index 6db3e2838..000000000
--- a/date.c
+++ /dev/null
@@ -1,247 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini date implementation for busybox
4 *
5 * by Matthew Grant <grantma@anathoth.gen.nz>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21*/
22
23#include <stdlib.h>
24#include <errno.h>
25#include <sys/time.h>
26#include <unistd.h>
27#include <time.h>
28#include <stdio.h>
29#include <string.h>
30#include <getopt.h>
31#include "busybox.h"
32
33
34/* This 'date' command supports only 2 time setting formats,
35 all the GNU strftime stuff (its in libc, lets use it),
36 setting time using UTC and displaying int, as well as
37 an RFC 822 complient date output for shell scripting
38 mail commands */
39
40/* Input parsing code is always bulky - used heavy duty libc stuff as
41 much as possible, missed out a lot of bounds checking */
42
43/* Default input handling to save suprising some people */
44
45static struct tm *date_conv_time(struct tm *tm_time, const char *t_string)
46{
47 int nr;
48
49 nr = sscanf(t_string, "%2d%2d%2d%2d%d",
50 &(tm_time->tm_mon),
51 &(tm_time->tm_mday),
52 &(tm_time->tm_hour),
53 &(tm_time->tm_min), &(tm_time->tm_year));
54
55 if (nr < 4 || nr > 5) {
56 error_msg_and_die(invalid_date, t_string);
57 }
58
59 /* correct for century - minor Y2K problem here? */
60 if (tm_time->tm_year >= 1900)
61 tm_time->tm_year -= 1900;
62 /* adjust date */
63 tm_time->tm_mon -= 1;
64
65 return (tm_time);
66
67}
68
69
70/* The new stuff for LRP */
71
72static struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string)
73{
74 struct tm t;
75
76 /* Parse input and assign appropriately to tm_time */
77
78 if (t=*tm_time,sscanf(t_string, "%d:%d:%d",
79 &t.tm_hour, &t.tm_min, &t.tm_sec) == 3) {
80 /* no adjustments needed */
81
82 } else if (t=*tm_time,sscanf(t_string, "%d:%d",
83 &t.tm_hour, &t.tm_min) == 2) {
84 /* no adjustments needed */
85
86
87 } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d:%d",
88 &t.tm_mon,
89 &t.tm_mday,
90 &t.tm_hour,
91 &t.tm_min, &t.tm_sec) == 5) {
92
93 t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
94
95 } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d",
96 &t.tm_mon,
97 &t.tm_mday,
98 &t.tm_hour, &t.tm_min) == 4) {
99
100 t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
101
102 } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d:%d",
103 &t.tm_year,
104 &t.tm_mon,
105 &t.tm_mday,
106 &t.tm_hour,
107 &t.tm_min, &t.tm_sec) == 6) {
108
109 t.tm_year -= 1900; /* Adjust years */
110 t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
111
112 } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d",
113 &t.tm_year,
114 &t.tm_mon,
115 &t.tm_mday,
116 &t.tm_hour, &t.tm_min) == 5) {
117 t.tm_year -= 1900; /* Adjust years */
118 t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
119
120 } else {
121 error_msg_and_die(invalid_date, t_string);
122 }
123 *tm_time = t;
124 return (tm_time);
125}
126
127
128int date_main(int argc, char **argv)
129{
130 char *date_str = NULL;
131 char *date_fmt = NULL;
132 char *t_buff;
133 int c;
134 int set_time = 0;
135 int rfc822 = 0;
136 int utc = 0;
137 int use_arg = 0;
138 time_t tm;
139 struct tm tm_time;
140
141 /* Interpret command line args */
142 while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) {
143 switch (c) {
144 case 'R':
145 rfc822 = 1;
146 break;
147 case 's':
148 set_time = 1;
149 if ((date_str != NULL) || ((date_str = optarg) == NULL)) {
150 show_usage();
151 }
152 break;
153 case 'u':
154 utc = 1;
155 if (putenv("TZ=UTC0") != 0)
156 error_msg_and_die(memory_exhausted);
157 break;
158 case 'd':
159 use_arg = 1;
160 if ((date_str != NULL) || ((date_str = optarg) == NULL))
161 show_usage();
162 break;
163 default:
164 show_usage();
165 }
166 }
167
168 if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+'))
169 date_fmt = &argv[optind][1]; /* Skip over the '+' */
170 else if (date_str == NULL) {
171 set_time = 1;
172 date_str = argv[optind];
173 }
174#if 0
175 else {
176 error_msg("date_str='%s' date_fmt='%s'\n", date_str, date_fmt);
177 show_usage();
178 }
179#endif
180
181 /* Now we have parsed all the information except the date format
182 which depends on whether the clock is being set or read */
183
184 time(&tm);
185 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
186 /* Zero out fields - take her back to midnight! */
187 if (date_str != NULL) {
188 tm_time.tm_sec = 0;
189 tm_time.tm_min = 0;
190 tm_time.tm_hour = 0;
191 }
192
193 /* Process any date input to UNIX time since 1 Jan 1970 */
194 if (date_str != NULL) {
195
196 if (strchr(date_str, ':') != NULL) {
197 date_conv_ftime(&tm_time, date_str);
198 } else {
199 date_conv_time(&tm_time, date_str);
200 }
201
202 /* Correct any day of week and day of year etc. fields */
203 tm = mktime(&tm_time);
204 if (tm < 0)
205 error_msg_and_die(invalid_date, date_str);
206 if ( utc ) {
207 if (putenv("TZ=UTC0") != 0)
208 error_msg_and_die(memory_exhausted);
209 }
210
211 /* if setting time, set it */
212 if (set_time) {
213 if (stime(&tm) < 0) {
214 perror_msg("cannot set date");
215 }
216 }
217 }
218
219 /* Display output */
220
221 /* Deal with format string */
222 if (date_fmt == NULL) {
223 date_fmt = (rfc822
224 ? (utc
225 ? "%a, %_d %b %Y %H:%M:%S GMT"
226 : "%a, %_d %b %Y %H:%M:%S %z")
227 : "%a %b %e %H:%M:%S %Z %Y");
228
229 } else if (*date_fmt == '\0') {
230 /* Imitate what GNU 'date' does with NO format string! */
231 printf("\n");
232 return EXIT_SUCCESS;
233 }
234
235 /* Handle special conversions */
236
237 if (strncmp(date_fmt, "%f", 2) == 0) {
238 date_fmt = "%Y.%m.%d-%H:%M:%S";
239 }
240
241 /* Print OUTPUT (after ALL that!) */
242 t_buff = xmalloc(201);
243 strftime(t_buff, 200, date_fmt, &tm_time);
244 puts(t_buff);
245
246 return EXIT_SUCCESS;
247}
diff --git a/dc.c b/dc.c
deleted file mode 100644
index 8d7a92a28..000000000
--- a/dc.c
+++ /dev/null
@@ -1,182 +0,0 @@
1/* vi: set sw=4 ts=4: */
2#include <ctype.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7#include <math.h>
8#include "busybox.h"
9
10/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
11
12static double stack[100];
13static unsigned int pointer;
14
15static void push(double a)
16{
17 if (pointer >= (sizeof(stack) / sizeof(*stack)))
18 error_msg_and_die("stack overflow");
19 stack[pointer++] = a;
20}
21
22static double pop()
23{
24 if (pointer == 0)
25 error_msg_and_die("stack underflow");
26 return stack[--pointer];
27}
28
29static void add()
30{
31 push(pop() + pop());
32}
33
34static void sub()
35{
36 double subtrahend = pop();
37
38 push(pop() - subtrahend);
39}
40
41static void mul()
42{
43 push(pop() * pop());
44}
45
46static void divide()
47{
48 double divisor = pop();
49
50 push(pop() / divisor);
51}
52
53static void and()
54{
55 push((unsigned int) pop() & (unsigned int) pop());
56}
57
58static void or()
59{
60 push((unsigned int) pop() | (unsigned int) pop());
61}
62
63static void eor()
64{
65 push((unsigned int) pop() ^ (unsigned int) pop());
66}
67
68static void not()
69{
70 push(~(unsigned int) pop());
71}
72
73static void print()
74{
75 printf("%g\n", pop());
76}
77
78struct op {
79 const char *name;
80 void (*function) ();
81};
82
83static const struct op operators[] = {
84 {"+", add},
85 {"add", add},
86 {"-", sub},
87 {"sub", sub},
88 {"*", mul},
89 {"mul", mul},
90 {"/", divide},
91 {"div", divide},
92 {"and", and},
93 {"or", or},
94 {"not", not},
95 {"eor", eor},
96 {0, 0}
97};
98
99static void stack_machine(const char *argument)
100{
101 char *endPointer = 0;
102 double d;
103 const struct op *o = operators;
104
105 if (argument == 0) {
106 print();
107 return;
108 }
109
110 d = strtod(argument, &endPointer);
111
112 if (endPointer != argument) {
113 push(d);
114 return;
115 }
116
117 while (o->name != 0) {
118 if (strcmp(o->name, argument) == 0) {
119 (*(o->function)) ();
120 return;
121 }
122 o++;
123 }
124 error_msg_and_die("%s: syntax error.", argument);
125}
126
127/* return pointer to next token in buffer and set *buffer to one char
128 * past the end of the above mentioned token
129 */
130static char *get_token(char **buffer)
131{
132 char *start = NULL;
133 char *current = *buffer;
134
135 while (isspace(*current)) { current++; }
136 if (*current != 0) {
137 start = current;
138 while (!isspace(*current) && current != 0) { current++; }
139 *buffer = current;
140 }
141 return start;
142}
143
144/* In Perl one might say, scalar m|\s*(\S+)\s*|g */
145static int number_of_tokens(char *buffer)
146{
147 int i = 0;
148 char *b = buffer;
149 while (get_token(&b)) { i++; }
150 return i;
151}
152
153int dc_main(int argc, char **argv)
154{
155 /* take stuff from stdin if no args are given */
156 if (argc <= 1) {
157 int i, len;
158 char *line = NULL;
159 char *cursor = NULL;
160 char *token = NULL;
161 while ((line = get_line_from_file(stdin))) {
162 cursor = line;
163 len = number_of_tokens(line);
164 for (i = 0; i < len; i++) {
165 token = get_token(&cursor);
166 *cursor++ = 0;
167 stack_machine(token);
168 }
169 free(line);
170 }
171 } else {
172 if (*argv[1]=='-')
173 show_usage();
174 while (argc >= 2) {
175 stack_machine(argv[1]);
176 argv++;
177 argc--;
178 }
179 }
180 stack_machine(0);
181 return EXIT_SUCCESS;
182}
diff --git a/dd.c b/dd.c
deleted file mode 100644
index d46db82a0..000000000
--- a/dd.c
+++ /dev/null
@@ -1,154 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini dd implementation for busybox
4 *
5 *
6 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <sys/types.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <string.h>
29#include <fcntl.h>
30#include "busybox.h"
31
32
33static const struct suffix_mult dd_suffixes[] = {
34 { "c", 1 },
35 { "w", 2 },
36 { "b", 512 },
37 { "kD", 1000 },
38 { "k", 1024 },
39 { "MD", 1000000 },
40 { "M", 1048576 },
41 { "GD", 1000000000 },
42 { "G", 1073741824 },
43 { NULL, 0 }
44};
45
46int dd_main(int argc, char **argv)
47{
48 int i, ifd, ofd, oflag, sync_flag = FALSE, trunc = TRUE;
49 size_t in_full = 0, in_part = 0, out_full = 0, out_part = 0;
50 size_t bs = 512, count = -1;
51 ssize_t n;
52 off_t seek = 0, skip = 0;
53 char *infile = NULL, *outfile = NULL, *buf;
54
55 for (i = 1; i < argc; i++) {
56 if (strncmp("bs=", argv[i], 3) == 0)
57 bs = parse_number(argv[i]+3, dd_suffixes);
58 else if (strncmp("count=", argv[i], 6) == 0)
59 count = parse_number(argv[i]+6, dd_suffixes);
60 else if (strncmp("seek=", argv[i], 5) == 0)
61 seek = parse_number(argv[i]+5, dd_suffixes);
62 else if (strncmp("skip=", argv[i], 5) == 0)
63 skip = parse_number(argv[i]+5, dd_suffixes);
64 else if (strncmp("if=", argv[i], 3) == 0)
65 infile = argv[i]+3;
66 else if (strncmp("of=", argv[i], 3) == 0)
67 outfile = argv[i]+3;
68 else if (strncmp("conv=", argv[i], 5) == 0) {
69 buf = argv[i]+5;
70 while (1) {
71 if (strncmp("notrunc", buf, 7) == 0) {
72 trunc = FALSE;
73 buf += 7;
74 } else if (strncmp("sync", buf, 4) == 0) {
75 sync_flag = TRUE;
76 buf += 4;
77 } else {
78 error_msg_and_die("invalid conversion `%s'", argv[i]+5);
79 }
80 if (buf[0] == '\0')
81 break;
82 if (buf[0] == ',')
83 buf++;
84 }
85 } else
86 show_usage();
87 }
88
89 buf = xmalloc(bs);
90
91 if (infile != NULL) {
92 if ((ifd = open(infile, O_RDONLY)) < 0)
93 perror_msg_and_die("%s", infile);
94 } else {
95 ifd = STDIN_FILENO;
96 infile = "standard input";
97 }
98
99 if (outfile != NULL) {
100 oflag = O_WRONLY | O_CREAT;
101
102 if (!seek && trunc)
103 oflag |= O_TRUNC;
104
105 if ((ofd = open(outfile, oflag, 0666)) < 0)
106 perror_msg_and_die("%s", outfile);
107
108 if (seek && trunc) {
109 if (ftruncate(ofd, seek * bs) < 0)
110 perror_msg_and_die("%s", outfile);
111 }
112 } else {
113 ofd = STDOUT_FILENO;
114 outfile = "standard output";
115 }
116
117 if (skip) {
118 if (lseek(ifd, skip * bs, SEEK_CUR) < 0)
119 perror_msg_and_die("%s", infile);
120 }
121
122 if (seek) {
123 if (lseek(ofd, seek * bs, SEEK_CUR) < 0)
124 perror_msg_and_die("%s", outfile);
125 }
126
127 while (in_full + in_part != count) {
128 n = safe_read(ifd, buf, bs);
129 if (n < 0)
130 perror_msg_and_die("%s", infile);
131 if (n == 0)
132 break;
133 if (n == bs)
134 in_full++;
135 else
136 in_part++;
137 if (sync_flag) {
138 memset(buf + n, '\0', bs - n);
139 n = bs;
140 }
141 n = full_write(ofd, buf, n);
142 if (n < 0)
143 perror_msg_and_die("%s", outfile);
144 if (n == bs)
145 out_full++;
146 else
147 out_part++;
148 }
149
150 fprintf(stderr, "%ld+%ld records in\n", (long)in_full, (long)in_part);
151 fprintf(stderr, "%ld+%ld records out\n", (long)out_full, (long)out_part);
152
153 return EXIT_SUCCESS;
154}
diff --git a/deallocvt.c b/deallocvt.c
deleted file mode 100644
index 15cd0c9b9..000000000
--- a/deallocvt.c
+++ /dev/null
@@ -1,43 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s)
4 * Renamed deallocvt.
5 */
6#include <stdlib.h>
7#include <stdio.h>
8#include <fcntl.h>
9#include <sys/types.h>
10#include <sys/ioctl.h>
11#include "busybox.h"
12
13/* From <linux/vt.h> */
14static const int VT_DISALLOCATE = 0x5608; /* free memory associated to vt */
15
16int deallocvt_main(int argc, char *argv[])
17{
18 int fd, num, i;
19
20 //if ((argc > 2) || ((argv == 2) && (**(argv + 1) == '-')))
21 if (argc > 2)
22 show_usage();
23
24 fd = get_console_fd("/dev/console");
25
26 if (argc == 1) {
27 /* deallocate all unused consoles */
28 if (ioctl(fd, VT_DISALLOCATE, 0))
29 perror_msg_and_die("VT_DISALLOCATE");
30 } else {
31 for (i = 1; i < argc; i++) {
32 num = atoi(argv[i]);
33 if (num == 0)
34 error_msg("0: illegal VT number");
35 else if (num == 1)
36 error_msg("VT 1 cannot be deallocated");
37 else if (ioctl(fd, VT_DISALLOCATE, num))
38 perror_msg_and_die("VT_DISALLOCATE");
39 }
40 }
41
42 return EXIT_SUCCESS;
43}
diff --git a/debian/Config.h-deb b/debian/Config.h-deb
index fd848e192..818d66d53 100644
--- a/debian/Config.h-deb
+++ b/debian/Config.h-deb
@@ -3,142 +3,142 @@
3// When you turn things off here, they won't be compiled in at all. 3// When you turn things off here, they won't be compiled in at all.
4// 4//
5//// This file is parsed by sed. You MUST use single line comments. 5//// This file is parsed by sed. You MUST use single line comments.
6// i.e., //#define BB_BLAH 6// i.e., //#define CONFIG_BLAH
7// 7//
8// 8//
9// BusyBox Applications 9// BusyBox Applications
10//#define BB_ADJTIMEX 10//#define CONFIG_ADJTIMEX
11#define BB_AR 11#define CONFIG_AR
12//#define BB_ASH 12//#define CONFIG_ASH
13#define BB_BASENAME 13#define CONFIG_BASENAME
14#define BB_CAT 14#define CONFIG_CAT
15#define BB_CHGRP 15#define CONFIG_CHGRP
16#define BB_CHMOD 16#define CONFIG_CHMOD
17#define BB_CHOWN 17#define CONFIG_CHOWN
18#define BB_CHROOT 18#define CONFIG_CHROOT
19#define BB_CHVT 19#define CONFIG_CHVT
20#define BB_CLEAR 20#define CONFIG_CLEAR
21//#define BB_CMP 21//#define CONFIG_CMP
22#define BB_CP 22#define CONFIG_CP
23//#define BB_CPIO 23//#define CONFIG_CPIO
24#define BB_CUT 24#define CONFIG_CUT
25#define BB_DATE 25#define CONFIG_DATE
26//#define BB_DC 26//#define CONFIG_DC
27#define BB_DD 27#define CONFIG_DD
28//#define BB_DEALLOCVT 28//#define CONFIG_DEALLOCVT
29#define BB_DF 29#define CONFIG_DF
30#define BB_DIRNAME 30#define CONFIG_DIRNAME
31#define BB_DMESG 31#define CONFIG_DMESG
32//#define BB_DOS2UNIX 32//#define CONFIG_DOS2UNIX
33//#define BB_DPKG 33//#define CONFIG_DPKG
34//#define BB_DPKG_DEB 34//#define CONFIG_DPKG_DEB
35//#define BB_DUTMP 35//#define CONFIG_DUTMP
36#define BB_DU 36#define CONFIG_DU
37//#define BB_DUMPKMAP 37//#define CONFIG_DUMPKMAP
38#define BB_ECHO 38#define CONFIG_ECHO
39#define BB_ENV 39#define CONFIG_ENV
40#define BB_EXPR 40#define CONFIG_EXPR
41//#define BB_FBSET 41//#define CONFIG_FBSET
42//#define BB_FDFLUSH 42//#define CONFIG_FDFLUSH
43#define BB_FIND 43#define CONFIG_FIND
44#define BB_FREE 44#define CONFIG_FREE
45//#define BB_FREERAMDISK 45//#define CONFIG_FREERAMDISK
46//#define BB_FSCK_MINIX 46//#define CONFIG_FSCK_MINIX
47//#define BB_GETOPT 47//#define CONFIG_GETOPT
48#define BB_GREP 48#define CONFIG_GREP
49#define BB_GUNZIP 49#define CONFIG_GUNZIP
50#define BB_GZIP 50#define CONFIG_GZIP
51#define BB_HALT 51#define CONFIG_HALT
52#define BB_HEAD 52#define CONFIG_HEAD
53//#define BB_HOSTID 53//#define CONFIG_HOSTID
54//#define BB_HOSTNAME 54//#define CONFIG_HOSTNAME
55//#define BB_HUSH 55//#define CONFIG_HUSH
56#define BB_ID 56#define CONFIG_ID
57//#define BB_IFCONFIG 57//#define CONFIG_IFCONFIG
58#define BB_INIT 58#define CONFIG_INIT
59//#define BB_INSMOD 59//#define CONFIG_INSMOD
60#define BB_KILL 60#define CONFIG_KILL
61#define BB_KILLALL 61#define CONFIG_KILLALL
62#define BB_KLOGD 62#define CONFIG_KLOGD
63//#define BB_LASH 63//#define CONFIG_LASH
64//#define BB_LENGTH 64//#define CONFIG_LENGTH
65#define BB_LN 65#define CONFIG_LN
66//#define BB_LOADACM 66//#define CONFIG_LOADACM
67//#define BB_LOADFONT 67//#define CONFIG_LOADFONT
68#define BB_LOADKMAP 68#define CONFIG_LOADKMAP
69#define BB_LOGGER 69#define CONFIG_LOGGER
70//#define BB_LOGNAME 70//#define CONFIG_LOGNAME
71#define BB_LS 71#define CONFIG_LS
72#define BB_LSMOD 72#define CONFIG_LSMOD
73//#define BB_MAKEDEVS 73//#define CONFIG_MAKEDEVS
74#define BB_MD5SUM 74#define CONFIG_MD5SUM
75#define BB_MKDIR 75#define CONFIG_MKDIR
76//#define BB_MKFIFO 76//#define CONFIG_MKFIFO
77//#define BB_MKFS_MINIX 77//#define CONFIG_MKFS_MINIX
78#define BB_MKNOD 78#define CONFIG_MKNOD
79#define BB_MKSWAP 79#define CONFIG_MKSWAP
80//#define BB_MKTEMP 80//#define CONFIG_MKTEMP
81//#define BB_MODPROBE 81//#define CONFIG_MODPROBE
82#define BB_MORE 82#define CONFIG_MORE
83#define BB_MOUNT 83#define CONFIG_MOUNT
84//#define BB_MSH 84//#define CONFIG_MSH
85//#define BB_MT 85//#define CONFIG_MT
86#define BB_MV 86#define CONFIG_MV
87//#define BB_NC 87//#define CONFIG_NC
88//#define BB_NSLOOKUP 88//#define CONFIG_NSLOOKUP
89//#define BB_PIDOF 89//#define CONFIG_PIDOF
90#define BB_PING 90#define CONFIG_PING
91//#define BB_PIVOT_ROOT 91//#define CONFIG_PIVOT_ROOT
92#define BB_POWEROFF 92#define CONFIG_POWEROFF
93//#define BB_PRINTF 93//#define CONFIG_PRINTF
94#define BB_PS 94#define CONFIG_PS
95#define BB_PWD 95#define CONFIG_PWD
96//#define BB_RDATE 96//#define CONFIG_RDATE
97//#define BB_READLINK 97//#define CONFIG_READLINK
98#define BB_REBOOT 98#define CONFIG_REBOOT
99//#define BB_RENICE 99//#define CONFIG_RENICE
100#define BB_RESET 100#define CONFIG_RESET
101#define BB_RM 101#define CONFIG_RM
102#define BB_RMDIR 102#define CONFIG_RMDIR
103//#define BB_RMMOD 103//#define CONFIG_RMMOD
104//#define BB_ROUTE 104//#define CONFIG_ROUTE
105//#define BB_RPM2CPIO 105//#define CONFIG_RPM2CPIO
106#define BB_SED 106#define CONFIG_SED
107//#define BB_SETKEYCODES 107//#define CONFIG_SETKEYCODES
108#define BB_SLEEP 108#define CONFIG_SLEEP
109#define BB_SORT 109#define CONFIG_SORT
110//#define BB_STTY 110//#define CONFIG_STTY
111#define BB_SWAPONOFF 111#define CONFIG_SWAPONOFF
112#define BB_SYNC 112#define CONFIG_SYNC
113#define BB_SYSLOGD 113#define CONFIG_SYSLOGD
114#define BB_TAIL 114#define CONFIG_TAIL
115#define BB_TAR 115#define CONFIG_TAR
116//#define BB_TEE 116//#define CONFIG_TEE
117//#define BB_TEST 117//#define CONFIG_TEST
118#define BB_TELNET 118#define CONFIG_TELNET
119//#define BB_TFTP 119//#define CONFIG_TFTP
120#define BB_TOUCH 120#define CONFIG_TOUCH
121#define BB_TR 121#define CONFIG_TR
122//#define BB_TRACEROUTE 122//#define CONFIG_TRACEROUTE
123#define BB_TRUE_FALSE 123#define CONFIG_TRUE_FALSE
124#define BB_TTY 124#define CONFIG_TTY
125//#define BB_UNIX2DOS 125//#define CONFIG_UNIX2DOS
126//#define BB_UUENCODE 126//#define CONFIG_UUENCODE
127//#define BB_UUDECODE 127//#define CONFIG_UUDECODE
128#define BB_UMOUNT 128#define CONFIG_UMOUNT
129#define BB_UNIQ 129#define CONFIG_UNIQ
130#define BB_UNAME 130#define CONFIG_UNAME
131//#define BB_UPDATE 131//#define CONFIG_UPDATE
132#define BB_UPTIME 132#define CONFIG_UPTIME
133//#define BB_USLEEP 133//#define CONFIG_USLEEP
134#define BB_VI 134#define CONFIG_VI
135//#define BB_WATCHDOG 135//#define CONFIG_WATCHDOG
136#define BB_WC 136#define CONFIG_WC
137#define BB_WGET 137#define CONFIG_WGET
138#define BB_WHICH 138#define CONFIG_WHICH
139#define BB_WHOAMI 139#define CONFIG_WHOAMI
140#define BB_XARGS 140#define CONFIG_XARGS
141#define BB_YES 141#define CONFIG_YES
142// End of Applications List 142// End of Applications List
143// 143//
144// 144//
@@ -151,21 +151,21 @@
151// 151//
152// If you enabled one or more of the shells, you may select which one 152// If you enabled one or more of the shells, you may select which one
153// should be run when sh is invoked: 153// should be run when sh is invoked:
154//#define BB_FEATURE_SH_IS_ASH 154//#define CONFIG_FEATURE_SH_IS_ASH
155//#define BB_FEATURE_SH_IS_HUSH 155//#define CONFIG_FEATURE_SH_IS_HUSH
156//#define BB_FEATURE_SH_IS_LASH 156//#define CONFIG_FEATURE_SH_IS_LASH
157#define BB_FEATURE_SH_IS_MSH 157#define CONFIG_FEATURE_SH_IS_MSH
158// 158//
159// BusyBox will, by default, malloc space for its buffers. This costs code 159// BusyBox will, by default, malloc space for its buffers. This costs code
160// size for the call to xmalloc. You can use the following feature to have 160// size for the call to xmalloc. You can use the following feature to have
161// them put on the stack. For some very small machines with limited stack 161// them put on the stack. For some very small machines with limited stack
162// space, this can be deadly. For most folks, this works just fine... 162// space, this can be deadly. For most folks, this works just fine...
163//#define BB_FEATURE_BUFFERS_GO_ON_STACK 163//#define CONFIG_FEATURE_BUFFERS_GO_ON_STACK
164// The third alternative for buffer allocation is to use BSS. This works 164// The third alternative for buffer allocation is to use BSS. This works
165// beautifully for computers with a real MMU (and OS support), but wastes 165// beautifully for computers with a real MMU (and OS support), but wastes
166// runtime RAM for uCLinux. This behavior was the only one available for 166// runtime RAM for uCLinux. This behavior was the only one available for
167// BusyBox versions 0.48 and earlier. 167// BusyBox versions 0.48 and earlier.
168//#define BB_FEATURE_BUFFERS_GO_IN_BSS 168//#define CONFIG_FEATURE_BUFFERS_GO_IN_BSS
169// 169//
170// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, 170// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
171// thereby eliminating the need for the /proc filesystem and thereby saving 171// thereby eliminating the need for the /proc filesystem and thereby saving
@@ -176,212 +176,212 @@
176// mknod /dev/mtab c 10 22 176// mknod /dev/mtab c 10 22
177// mknod /dev/ps c 10 21 177// mknod /dev/ps c 10 21
178// I emailed Linus and this patch will not be going into the stock kernel. 178// I emailed Linus and this patch will not be going into the stock kernel.
179//#define BB_FEATURE_USE_DEVPS_PATCH 179//#define CONFIG_FEATURE_USE_DEVPS_PATCH
180// 180//
181// show verbose usage messages 181// show verbose usage messages
182//#define BB_FEATURE_VERBOSE_USAGE 182//#define CONFIG_FEATURE_VERBOSE_USAGE
183// 183//
184// Use termios to manipulate the screen ('more' is prettier with this on) 184// Use termios to manipulate the screen ('more' is prettier with this on)
185#define BB_FEATURE_USE_TERMIOS 185#define CONFIG_FEATURE_USE_TERMIOS
186// 186//
187// calculate terminal & column widths (for more and ls) 187// calculate terminal & column widths (for more and ls)
188#define BB_FEATURE_AUTOWIDTH 188#define CONFIG_FEATURE_AUTOWIDTH
189// 189//
190// show username/groupnames for ls 190// show username/groupnames for ls
191#define BB_FEATURE_LS_USERNAME 191#define CONFIG_FEATURE_LS_USERNAME
192// 192//
193// show file timestamps in ls 193// show file timestamps in ls
194#define BB_FEATURE_LS_TIMESTAMPS 194#define CONFIG_FEATURE_LS_TIMESTAMPS
195// 195//
196// enable ls -p and -F 196// enable ls -p and -F
197#define BB_FEATURE_LS_FILETYPES 197#define CONFIG_FEATURE_LS_FILETYPES
198// 198//
199// sort the file names 199// sort the file names
200#define BB_FEATURE_LS_SORTFILES 200#define CONFIG_FEATURE_LS_SORTFILES
201// 201//
202// enable ls -R 202// enable ls -R
203#define BB_FEATURE_LS_RECURSIVE 203#define CONFIG_FEATURE_LS_RECURSIVE
204// 204//
205// enable ls -L 205// enable ls -L
206#define BB_FEATURE_LS_FOLLOWLINKS 206#define CONFIG_FEATURE_LS_FOLLOWLINKS
207// 207//
208// Disable for a smaller (but less functional) ping 208// Disable for a smaller (but less functional) ping
209#define BB_FEATURE_FANCY_PING 209#define CONFIG_FEATURE_FANCY_PING
210// 210//
211// Make init use a simplified /etc/inittab file (recommended). 211// Make init use a simplified /etc/inittab file (recommended).
212#define BB_FEATURE_USE_INITTAB 212#define CONFIG_FEATURE_USE_INITTAB
213// 213//
214//Enable init being called as /linuxrc 214//Enable init being called as /linuxrc
215#define BB_FEATURE_LINUXRC 215#define CONFIG_FEATURE_INITRD
216// 216//
217//Have init enable core dumping for child processes (for debugging only) 217//Have init enable core dumping for child processes (for debugging only)
218//#define BB_FEATURE_INIT_COREDUMPS 218//#define CONFIG_FEATURE_INIT_COREDUMPS
219// 219//
220//Make sure nothing is printed to the console on boot 220//Make sure nothing is printed to the console on boot
221//#define BB_FEATURE_EXTRA_QUIET 221//#define CONFIG_FEATURE_EXTRA_QUIET
222// 222//
223// enable syslogd -R remotehost 223// enable syslogd -R remotehost
224#define BB_FEATURE_REMOTE_LOG 224#define CONFIG_FEATURE_REMOTE_LOG
225// 225//
226// enable syslogd -C 226// enable syslogd -C
227//#define BB_FEATURE_IPC_SYSLOG 227//#define CONFIG_FEATURE_IPC_SYSLOG
228// 228//
229//Disable for a simple tail implementation (2.34k vs 3k for the full one). 229//Disable for a simple tail implementation (2.34k vs 3k for the full one).
230//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 230//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v.
231#define BB_FEATURE_FANCY_TAIL 231#define CONFIG_FEATURE_FANCY_TAIL
232// 232//
233// Enable support for loop devices in mount 233// Enable support for loop devices in mount
234#define BB_FEATURE_MOUNT_LOOP 234#define CONFIG_FEATURE_MOUNT_LOOP
235// 235//
236// Enable support for a real /etc/mtab file instead of /proc/mounts 236// Enable support for a real /etc/mtab file instead of /proc/mounts
237//#define BB_FEATURE_MTAB_SUPPORT 237//#define CONFIG_FEATURE_MTAB_SUPPORT
238// 238//
239// Enable support for mounting remote NFS volumes. 239// Enable support for mounting remote NFS volumes.
240// You may need to mount with "-o nolock" if you are 240// You may need to mount with "-o nolock" if you are
241// not running a local portmapper daemon... 241// not running a local portmapper daemon...
242#define BB_FEATURE_NFSMOUNT 242#define CONFIG_FEATURE_NFSMOUNT
243// 243//
244// Enable support forced filesystem unmounting 244// Enable support forced filesystem unmounting
245// (i.e., in case of an unreachable NFS system). 245// (i.e., in case of an unreachable NFS system).
246#define BB_FEATURE_MOUNT_FORCE 246#define CONFIG_FEATURE_MOUNT_FORCE
247// 247//
248// Enable support for creation of tar files. 248// Enable support for creation of tar files.
249#define BB_FEATURE_TAR_CREATE 249#define CONFIG_FEATURE_TAR_CREATE
250// 250//
251// Enable support for "--exclude" and "-X" for excluding files 251// Enable support for "--exclude" and "-X" for excluding files
252#define BB_FEATURE_TAR_EXCLUDE 252#define CONFIG_FEATURE_TAR_EXCLUDE
253// 253//
254// Enable support for tar -z option (currently only works for inflating) 254// Enable support for tar -z option (currently only works for inflating)
255#define BB_FEATURE_TAR_GZIP 255#define CONFIG_FEATURE_TAR_GZIP
256// 256//
257// Enable reverse sort 257// Enable reverse sort
258#define BB_FEATURE_SORT_REVERSE 258#define CONFIG_FEATURE_SORT_REVERSE
259// 259//
260// Enable uniqe sort 260// Enable uniqe sort
261#define BB_FEATURE_SORT_UNIQUE 261#define CONFIG_FEATURE_SORT_UNIQUE
262// 262//
263// Enable command line editing in the shell. 263// Enable command line editing in the shell.
264// Only relevant if a shell is enabled. On by default. 264// Only relevant if a shell is enabled. On by default.
265#define BB_FEATURE_COMMAND_EDITING 265#define CONFIG_FEATURE_COMMAND_EDITING
266// 266//
267// Enable tab completion in the shell. This is now working quite nicely. 267// Enable tab completion in the shell. This is now working quite nicely.
268// This feature adds a bit over 4k. Only relevant if a shell is enabled. 268// This feature adds a bit over 4k. Only relevant if a shell is enabled.
269#define BB_FEATURE_COMMAND_TAB_COMPLETION 269#define CONFIG_FEATURE_COMMAND_TAB_COMPLETION
270// 270//
271// Attempts to match usernames in a ~-prefixed path 271// Attempts to match usernames in a ~-prefixed path
272//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION 272//#define CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
273// 273//
274//Allow the shell to invoke all the compiled in BusyBox applets as if they 274//Allow the shell to invoke all the compiled in BusyBox applets as if they
275//were shell builtins. Nice for staticly linking an emergency rescue shell, 275//were shell builtins. Nice for staticly linking an emergency rescue shell,
276//among other things. Off by default. 276//among other things. Off by default.
277// Only relevant if a shell is enabled. 277// Only relevant if a shell is enabled.
278//#define BB_FEATURE_SH_STANDALONE_SHELL 278//#define CONFIG_FEATURE_SH_STANDALONE_SHELL
279// 279//
280//When this is enabled, busybox shell applets can be called using full path 280//When this is enabled, busybox shell applets can be called using full path
281//names. This causes applets (i.e., most busybox commands) to override 281//names. This causes applets (i.e., most busybox commands) to override
282//real commands on the filesystem. For example, if you run run /bin/cat, it 282//real commands on the filesystem. For example, if you run run /bin/cat, it
283//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ 283//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
284//busybox. Some systems want this, others do not. Choose wisely. :-) This 284//busybox. Some systems want this, others do not. Choose wisely. :-) This
285//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. 285//only has meaning when CONFIG_FEATURE_SH_STANDALONE_SHELL is enabled.
286// Only relevant if a shell is enabled. Off by default. 286// Only relevant if a shell is enabled. Off by default.
287//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN 287//#define CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
288// 288//
289// Uncomment this option for a fancy shell prompt that includes the 289// Uncomment this option for a fancy shell prompt that includes the
290// current username and hostname. On systems that don't have usernames 290// current username and hostname. On systems that don't have usernames
291// or hostnames, this can look hideous. 291// or hostnames, this can look hideous.
292// Only relevant if a shell is enabled. 292// Only relevant if a shell is enabled.
293//#define BB_FEATURE_SH_FANCY_PROMPT 293//#define CONFIG_FEATURE_SH_FANCY_PROMPT
294// 294//
295//Turn on extra fbset options 295//Turn on extra fbset options
296//#define BB_FEATURE_FBSET_FANCY 296//#define CONFIG_FEATURE_FBSET_FANCY
297// 297//
298//Turn on fbset readmode support 298//Turn on fbset readmode support
299//#define BB_FEATURE_FBSET_READMODE 299//#define CONFIG_FEATURE_FBSET_READMODE
300// 300//
301// Support insmod/lsmod/rmmod for post 2.1 kernels 301// Support insmod/lsmod/rmmod for post 2.1 kernels
302//#define BB_FEATURE_NEW_MODULE_INTERFACE 302//#define CONFIG_FEATURE_NEW_MODULE_INTERFACE
303// 303//
304// Support insmod/lsmod/rmmod for pre 2.1 kernels 304// Support insmod/lsmod/rmmod for pre 2.1 kernels
305//#define BB_FEATURE_OLD_MODULE_INTERFACE 305//#define CONFIG_FEATURE_OLD_MODULE_INTERFACE
306// 306//
307// Support module version checking 307// Support module version checking
308//#define BB_FEATURE_INSMOD_VERSION_CHECKING 308//#define CONFIG_FEATURE_INSMOD_VERSION_CHECKING
309// 309//
310// Support for uClinux memory usage optimization, which will load the image 310// Support for uClinux memory usage optimization, which will load the image
311// directly into the kernel memory. This divides memory requrements by three. 311// directly into the kernel memory. This divides memory requrements by three.
312// If you are not running uClinux (i.e., your CPU has an MMU) leave this 312// If you are not running uClinux (i.e., your CPU has an MMU) leave this
313// disabled... 313// disabled...
314//#define BB_FEATURE_INSMOD_LOADINKMEM 314//#define CONFIG_FEATURE_INSMOD_LOADINKMEM
315// 315//
316// Support for Minix filesystem, version 2 316// Support for Minix filesystem, version 2
317//#define BB_FEATURE_MINIX2 317//#define CONFIG_FEATURE_MINIX2
318// 318//
319// Enable ifconfig status reporting output -- this feature adds 12k. 319// Enable ifconfig status reporting output -- this feature adds 12k.
320#define BB_FEATURE_IFCONFIG_STATUS 320#define CONFIG_FEATURE_IFCONFIG_STATUS
321// 321//
322// Enable ifconfig slip-specific options "keepalive" and "outfill" 322// Enable ifconfig slip-specific options "keepalive" and "outfill"
323//#define BB_FEATURE_IFCONFIG_SLIP 323//#define CONFIG_FEATURE_IFCONFIG_SLIP
324// 324//
325// Enable ifconfig options "mem_start", "io_addr", and "irq". 325// Enable ifconfig options "mem_start", "io_addr", and "irq".
326//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 326//#define CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
327// 327//
328// Enable ifconfig option "hw". Currently works for only with "ether". 328// Enable ifconfig option "hw". Currently works for only with "ether".
329#define BB_FEATURE_IFCONFIG_HW 329#define CONFIG_FEATURE_IFCONFIG_HW
330// 330//
331// Enable busybox --install [-s] 331// Enable busybox --install [-s]
332// to create links (or symlinks) for all the commands that are 332// to create links (or symlinks) for all the commands that are
333// compiled into the binary. (needs /proc filesystem) 333// compiled into the binary. (needs /proc filesystem)
334#define BB_FEATURE_INSTALLER 334#define CONFIG_FEATURE_INSTALLER
335// 335//
336// Enable a nifty progress meter in wget (adds just under 2k) 336// Enable a nifty progress meter in wget (adds just under 2k)
337#define BB_FEATURE_WGET_STATUSBAR 337#define CONFIG_FEATURE_WGET_STATUSBAR
338// 338//
339// Enable HTTP authentication in wget 339// Enable HTTP authentication in wget
340#define BB_FEATURE_WGET_AUTHENTICATION 340#define CONFIG_FEATURE_WGET_AUTHENTICATION
341// 341//
342// Clean up all memory before exiting -- usually not needed 342// Clean up all memory before exiting -- usually not needed
343// as the OS can clean up... Don't enable this unless you 343// as the OS can clean up... Don't enable this unless you
344// have a really good reason for cleaning things up manually. 344// have a really good reason for cleaning things up manually.
345//#define BB_FEATURE_CLEAN_UP 345//#define CONFIG_FEATURE_CLEAN_UP
346// 346//
347// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) 347// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
348#define BB_FEATURE_HUMAN_READABLE 348#define CONFIG_FEATURE_HUMAN_READABLE
349// 349//
350// Support for the find -type option. 350// Support for the find -type option.
351#define BB_FEATURE_FIND_TYPE 351#define CONFIG_FEATURE_FIND_TYPE
352// 352//
353// Support for the find -perm option. 353// Support for the find -perm option.
354#define BB_FEATURE_FIND_PERM 354#define CONFIG_FEATURE_FIND_PERM
355// 355//
356// Support for the find -mtine option. 356// Support for the find -mtine option.
357#define BB_FEATURE_FIND_MTIME 357#define CONFIG_FEATURE_FIND_MTIME
358// 358//
359// Support for the -A -B and -C context flags in grep 359// Support for the -A -B and -C context flags in grep
360//#define BB_FEATURE_GREP_CONTEXT 360//#define CONFIG_FEATURE_GREP_CONTEXT
361// 361//
362// Support for the EGREP applet (alias to the grep applet) 362// Support for the EGREP applet (alias to the grep applet)
363//#define BB_FEATURE_GREP_EGREP_ALIAS 363//#define CONFIG_FEATURE_GREP_EGREP_ALIAS
364// 364//
365// Tell tftp what commands that should be supported. 365// Tell tftp what commands that should be supported.
366#define BB_FEATURE_TFTP_PUT 366#define CONFIG_FEATURE_TFTP_PUT
367#define BB_FEATURE_TFTP_GET 367#define CONFIG_FEATURE_TFTP_GET
368// 368//
369// features for vi 369// features for vi
370#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode 370#define CONFIG_FEATURE_VI_COLON // ":" colon commands, no "ex" mode
371#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds 371#define CONFIG_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds
372#define BB_FEATURE_VI_SEARCH // search and replace cmds 372#define CONFIG_FEATURE_VI_SEARCH // search and replace cmds
373#define BB_FEATURE_VI_USE_SIGNALS // catch signals 373#define CONFIG_FEATURE_VI_USE_SIGNALS // catch signals
374#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd 374#define CONFIG_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd
375#define BB_FEATURE_VI_READONLY // vi -R and "view" mode 375#define CONFIG_FEATURE_VI_READONLY // vi -R and "view" mode
376#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch 376#define CONFIG_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch
377#define BB_FEATURE_VI_SET // :set 377#define CONFIG_FEATURE_VI_SET // :set
378#define BB_FEATURE_VI_WIN_RESIZE // handle window resize 378#define CONFIG_FEATURE_VI_WIN_RESIZE // handle window resize
379// 379//
380// Enable a if you system have setuped locale 380// Enable a if you system have setuped locale
381//#define BB_LOCALE_SUPPORT 381//#define CONFIG_LOCALE_SUPPORT
382// 382//
383// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. 383// Support for TELNET to pass TERM type to remote host. Adds 384 bytes.
384#define BB_FEATURE_TELNET_TTYPE 384#define CONFIG_FEATURE_TELNET_TTYPE
385// 385//
386// End of Features List 386// End of Features List
387// 387//
@@ -396,74 +396,74 @@
396// 396//
397#include <features.h> 397#include <features.h>
398#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ 398#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__
399 #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ 399 #undef CONFIG_RPM2CPIO /* Uses gz_open(), which uses fork() */
400 #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ 400 #undef CONFIG_DPKG_DEB /* Uses gz_open(), which uses fork() */
401 #undef BB_ASH /* Uses fork() */ 401 #undef CONFIG_ASH /* Uses fork() */
402 #undef BB_HUSH /* Uses fork() */ 402 #undef CONFIG_HUSH /* Uses fork() */
403 #undef BB_LASH /* Uses fork() */ 403 #undef CONFIG_LASH /* Uses fork() */
404 #undef BB_INIT /* Uses fork() */ 404 #undef CONFIG_INIT /* Uses fork() */
405 #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ 405 #undef CONFIG_FEATURE_TAR_GZIP /* Uses fork() */
406 #undef BB_SYSLOGD /* Uses daemon() */ 406 #undef CONFIG_SYSLOGD /* Uses daemon() */
407 #undef BB_KLOGD /* Uses daemon() */ 407 #undef CONFIG_KLOGD /* Uses daemon() */
408 #undef BB_UPDATE /* Uses daemon() */ 408 #undef CONFIG_UPDATE /* Uses daemon() */
409#endif 409#endif
410#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH 410#if defined CONFIG_ASH || defined CONFIG_HUSH || defined CONFIG_LASH || defined CONFIG_MSH
411 #if defined BB_FEATURE_COMMAND_EDITING 411 #if defined CONFIG_FEATURE_COMMAND_EDITING
412 #define BB_CMDEDIT 412 #define CONFIG_CMDEDIT
413 #else 413 #else
414 #undef BB_FEATURE_COMMAND_EDITING 414 #undef CONFIG_FEATURE_COMMAND_EDITING
415 #undef BB_FEATURE_COMMAND_TAB_COMPLETION 415 #undef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
416 #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION 416 #undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
417 #undef BB_FEATURE_SH_FANCY_PROMPT 417 #undef CONFIG_FEATURE_SH_FANCY_PROMPT
418 #endif 418 #endif
419#else 419#else
420 #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 420 #undef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
421 #undef BB_FEATURE_SH_STANDALONE_SHELL 421 #undef CONFIG_FEATURE_SH_STANDALONE_SHELL
422 #undef BB_FEATURE_SH_FANCY_PROMPT 422 #undef CONFIG_FEATURE_SH_FANCY_PROMPT
423#endif 423#endif
424// 424//
425#ifdef BB_KILLALL 425#ifdef CONFIG_KILLALL
426 #ifndef BB_KILL 426 #ifndef CONFIG_KILL
427 #define BB_KILL 427 #define CONFIG_KILL
428 #endif 428 #endif
429#endif 429#endif
430// 430//
431#ifndef BB_INIT 431#ifndef CONFIG_INIT
432 #undef BB_FEATURE_LINUXRC 432 #undef CONFIG_FEATURE_INITRD
433#endif 433#endif
434// 434//
435#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT 435#if defined CONFIG_MOUNT && defined CONFIG_FEATURE_NFSMOUNT
436 #define BB_NFSMOUNT 436 #define CONFIG_NFSMOUNT
437#endif 437#endif
438// 438//
439#if defined BB_FEATURE_AUTOWIDTH 439#if defined CONFIG_FEATURE_AUTOWIDTH
440 #ifndef BB_FEATURE_USE_TERMIOS 440 #ifndef CONFIG_FEATURE_USE_TERMIOS
441 #define BB_FEATURE_USE_TERMIOS 441 #define CONFIG_FEATURE_USE_TERMIOS
442 #endif 442 #endif
443#endif 443#endif
444// 444//
445#if defined BB_INSMOD || defined BB_LSMOD 445#if defined CONFIG_INSMOD || defined CONFIG_LSMOD
446 #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE 446 #if ! defined CONFIG_FEATURE_NEW_MODULE_INTERFACE && ! defined CONFIG_FEATURE_OLD_MODULE_INTERFACE
447 #define BB_FEATURE_NEW_MODULE_INTERFACE 447 #define CONFIG_FEATURE_NEW_MODULE_INTERFACE
448 #endif 448 #endif
449#endif 449#endif
450// 450//
451#ifdef BB_UNIX2DOS 451#ifdef CONFIG_UNIX2DOS
452 #define BB_DOS2UNIX 452 #define CONFIG_DOS2UNIX
453#endif 453#endif
454// 454//
455#ifdef BB_SYSLOGD 455#ifdef CONFIG_SYSLOGD
456 #if defined BB_FEATURE_IPC_SYSLOG 456 #if defined CONFIG_FEATURE_IPC_SYSLOG
457 #define BB_LOGREAD 457 #define CONFIG_LOGREAD
458 #endif 458 #endif
459#endif 459#endif
460// 460//
461#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH 461#if defined CONFIG_ASH && defined CONFIG_FEATURE_SH_IS_ASH
462# define shell_main ash_main 462# define shell_main ash_main
463#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH 463#elif defined CONFIG_HUSH && defined CONFIG_FEATURE_SH_IS_HUSH
464# define shell_main hush_main 464# define shell_main hush_main
465#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH 465#elif defined CONFIG_LASH && defined CONFIG_FEATURE_SH_IS_LASH
466# define shell_main lash_main 466# define shell_main lash_main
467#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH 467#elif defined CONFIG_MSH && defined CONFIG_FEATURE_SH_IS_MSH
468# define shell_main msh_main 468# define shell_main msh_main
469#endif 469#endif
diff --git a/debian/Config.h-static b/debian/Config.h-static
index 094b1f9b4..215bfda65 100644
--- a/debian/Config.h-static
+++ b/debian/Config.h-static
@@ -3,142 +3,142 @@
3// When you turn things off here, they won't be compiled in at all. 3// When you turn things off here, they won't be compiled in at all.
4// 4//
5//// This file is parsed by sed. You MUST use single line comments. 5//// This file is parsed by sed. You MUST use single line comments.
6// i.e., //#define BB_BLAH 6// i.e., //#define CONFIG_BLAH
7// 7//
8// 8//
9// BusyBox Applications 9// BusyBox Applications
10//#define BB_ADJTIMEX 10//#define CONFIG_ADJTIMEX
11#define BB_AR 11#define CONFIG_AR
12#define BB_ASH 12#define CONFIG_ASH
13#define BB_BASENAME 13#define CONFIG_BASENAME
14#define BB_CAT 14#define CONFIG_CAT
15#define BB_CHGRP 15#define CONFIG_CHGRP
16#define BB_CHMOD 16#define CONFIG_CHMOD
17#define BB_CHOWN 17#define CONFIG_CHOWN
18#define BB_CHROOT 18#define CONFIG_CHROOT
19#define BB_CHVT 19#define CONFIG_CHVT
20#define BB_CLEAR 20#define CONFIG_CLEAR
21#define BB_CMP 21#define CONFIG_CMP
22#define BB_CP 22#define CONFIG_CP
23#define BB_CPIO 23#define CONFIG_CPIO
24#define BB_CUT 24#define CONFIG_CUT
25#define BB_DATE 25#define CONFIG_DATE
26#define BB_DC 26#define CONFIG_DC
27#define BB_DD 27#define CONFIG_DD
28#define BB_DEALLOCVT 28#define CONFIG_DEALLOCVT
29#define BB_DF 29#define CONFIG_DF
30#define BB_DIRNAME 30#define CONFIG_DIRNAME
31#define BB_DMESG 31#define CONFIG_DMESG
32#define BB_DOS2UNIX 32#define CONFIG_DOS2UNIX
33#define BB_DPKG 33#define CONFIG_DPKG
34#define BB_DPKG_DEB 34#define CONFIG_DPKG_DEB
35#define BB_DUTMP 35#define CONFIG_DUTMP
36#define BB_DU 36#define CONFIG_DU
37#define BB_DUMPKMAP 37#define CONFIG_DUMPKMAP
38#define BB_ECHO 38#define CONFIG_ECHO
39#define BB_ENV 39#define CONFIG_ENV
40#define BB_EXPR 40#define CONFIG_EXPR
41#define BB_FBSET 41#define CONFIG_FBSET
42#define BB_FDFLUSH 42#define CONFIG_FDFLUSH
43#define BB_FIND 43#define CONFIG_FIND
44#define BB_FREE 44#define CONFIG_FREE
45#define BB_FREERAMDISK 45#define CONFIG_FREERAMDISK
46#define BB_FSCK_MINIX 46#define CONFIG_FSCK_MINIX
47#define BB_GETOPT 47#define CONFIG_GETOPT
48#define BB_GREP 48#define CONFIG_GREP
49#define BB_GUNZIP 49#define CONFIG_GUNZIP
50#define BB_GZIP 50#define CONFIG_GZIP
51#define BB_HALT 51#define CONFIG_HALT
52#define BB_HEAD 52#define CONFIG_HEAD
53#define BB_HOSTID 53#define CONFIG_HOSTID
54#define BB_HOSTNAME 54#define CONFIG_HOSTNAME
55//#define BB_HUSH 55//#define CONFIG_HUSH
56#define BB_ID 56#define CONFIG_ID
57#define BB_IFCONFIG 57#define CONFIG_IFCONFIG
58#define BB_INIT 58#define CONFIG_INIT
59//#define BB_INSMOD 59//#define CONFIG_INSMOD
60#define BB_KILL 60#define CONFIG_KILL
61#define BB_KILLALL 61#define CONFIG_KILLALL
62#define BB_KLOGD 62#define CONFIG_KLOGD
63//#define BB_LASH 63//#define CONFIG_LASH
64#define BB_LENGTH 64#define CONFIG_LENGTH
65#define BB_LN 65#define CONFIG_LN
66#define BB_LOADACM 66#define CONFIG_LOADACM
67#define BB_LOADFONT 67#define CONFIG_LOADFONT
68#define BB_LOADKMAP 68#define CONFIG_LOADKMAP
69#define BB_LOGGER 69#define CONFIG_LOGGER
70#define BB_LOGNAME 70#define CONFIG_LOGNAME
71#define BB_LS 71#define CONFIG_LS
72#define BB_LSMOD 72#define CONFIG_LSMOD
73#define BB_MAKEDEVS 73#define CONFIG_MAKEDEVS
74#define BB_MD5SUM 74#define CONFIG_MD5SUM
75#define BB_MKDIR 75#define CONFIG_MKDIR
76#define BB_MKFIFO 76#define CONFIG_MKFIFO
77#define BB_MKFS_MINIX 77#define CONFIG_MKFS_MINIX
78#define BB_MKNOD 78#define CONFIG_MKNOD
79#define BB_MKSWAP 79#define CONFIG_MKSWAP
80#define BB_MKTEMP 80#define CONFIG_MKTEMP
81//#define BB_MODPROBE 81//#define CONFIG_MODPROBE
82#define BB_MORE 82#define CONFIG_MORE
83#define BB_MOUNT 83#define CONFIG_MOUNT
84//#define BB_MSH 84//#define CONFIG_MSH
85#define BB_MT 85#define CONFIG_MT
86#define BB_MV 86#define CONFIG_MV
87#define BB_NC 87#define CONFIG_NC
88#define BB_NSLOOKUP 88#define CONFIG_NSLOOKUP
89#define BB_PIDOF 89#define CONFIG_PIDOF
90#define BB_PING 90#define CONFIG_PING
91#define BB_PIVOT_ROOT 91#define CONFIG_PIVOT_ROOT
92#define BB_POWEROFF 92#define CONFIG_POWEROFF
93#define BB_PRINTF 93#define CONFIG_PRINTF
94#define BB_PS 94#define CONFIG_PS
95#define BB_PWD 95#define CONFIG_PWD
96#define BB_RDATE 96#define CONFIG_RDATE
97#define BB_READLINK 97#define CONFIG_READLINK
98#define BB_REBOOT 98#define CONFIG_REBOOT
99#define BB_RENICE 99#define CONFIG_RENICE
100#define BB_RESET 100#define CONFIG_RESET
101#define BB_RM 101#define CONFIG_RM
102#define BB_RMDIR 102#define CONFIG_RMDIR
103#define BB_RMMOD 103#define CONFIG_RMMOD
104#define BB_ROUTE 104#define CONFIG_ROUTE
105#define BB_RPM2CPIO 105#define CONFIG_RPM2CPIO
106#define BB_SED 106#define CONFIG_SED
107#define BB_SETKEYCODES 107#define CONFIG_SETKEYCODES
108#define BB_SLEEP 108#define CONFIG_SLEEP
109#define BB_SORT 109#define CONFIG_SORT
110#define BB_STTY 110#define CONFIG_STTY
111#define BB_SWAPONOFF 111#define CONFIG_SWAPONOFF
112#define BB_SYNC 112#define CONFIG_SYNC
113#define BB_SYSLOGD 113#define CONFIG_SYSLOGD
114#define BB_TAIL 114#define CONFIG_TAIL
115#define BB_TAR 115#define CONFIG_TAR
116#define BB_TEE 116#define CONFIG_TEE
117#define BB_TEST 117#define CONFIG_TEST
118#define BB_TELNET 118#define CONFIG_TELNET
119#define BB_TFTP 119#define CONFIG_TFTP
120#define BB_TOUCH 120#define CONFIG_TOUCH
121#define BB_TR 121#define CONFIG_TR
122#define BB_TRACEROUTE 122#define CONFIG_TRACEROUTE
123#define BB_TRUE_FALSE 123#define CONFIG_TRUE_FALSE
124#define BB_TTY 124#define CONFIG_TTY
125#define BB_UNIX2DOS 125#define CONFIG_UNIX2DOS
126#define BB_UUENCODE 126#define CONFIG_UUENCODE
127#define BB_UUDECODE 127#define CONFIG_UUDECODE
128#define BB_UMOUNT 128#define CONFIG_UMOUNT
129#define BB_UNIQ 129#define CONFIG_UNIQ
130#define BB_UNAME 130#define CONFIG_UNAME
131#define BB_UPDATE 131#define CONFIG_UPDATE
132#define BB_UPTIME 132#define CONFIG_UPTIME
133#define BB_USLEEP 133#define CONFIG_USLEEP
134#define BB_VI 134#define CONFIG_VI
135#define BB_WATCHDOG 135#define CONFIG_WATCHDOG
136#define BB_WC 136#define CONFIG_WC
137#define BB_WGET 137#define CONFIG_WGET
138#define BB_WHICH 138#define CONFIG_WHICH
139#define BB_WHOAMI 139#define CONFIG_WHOAMI
140#define BB_XARGS 140#define CONFIG_XARGS
141#define BB_YES 141#define CONFIG_YES
142// End of Applications List 142// End of Applications List
143// 143//
144// 144//
@@ -151,21 +151,21 @@
151// 151//
152// If you enabled one or more of the shells, you may select which one 152// If you enabled one or more of the shells, you may select which one
153// should be run when sh is invoked: 153// should be run when sh is invoked:
154#define BB_FEATURE_SH_IS_ASH 154#define CONFIG_FEATURE_SH_IS_ASH
155//#define BB_FEATURE_SH_IS_HUSH 155//#define CONFIG_FEATURE_SH_IS_HUSH
156//#define BB_FEATURE_SH_IS_LASH 156//#define CONFIG_FEATURE_SH_IS_LASH
157//#define BB_FEATURE_SH_IS_MSH 157//#define CONFIG_FEATURE_SH_IS_MSH
158// 158//
159// BusyBox will, by default, malloc space for its buffers. This costs code 159// BusyBox will, by default, malloc space for its buffers. This costs code
160// size for the call to xmalloc. You can use the following feature to have 160// size for the call to xmalloc. You can use the following feature to have
161// them put on the stack. For some very small machines with limited stack 161// them put on the stack. For some very small machines with limited stack
162// space, this can be deadly. For most folks, this works just fine... 162// space, this can be deadly. For most folks, this works just fine...
163//#define BB_FEATURE_BUFFERS_GO_ON_STACK 163//#define CONFIG_FEATURE_BUFFERS_GO_ON_STACK
164// The third alternative for buffer allocation is to use BSS. This works 164// The third alternative for buffer allocation is to use BSS. This works
165// beautifully for computers with a real MMU (and OS support), but wastes 165// beautifully for computers with a real MMU (and OS support), but wastes
166// runtime RAM for uCLinux. This behavior was the only one available for 166// runtime RAM for uCLinux. This behavior was the only one available for
167// BusyBox versions 0.48 and earlier. 167// BusyBox versions 0.48 and earlier.
168//#define BB_FEATURE_BUFFERS_GO_IN_BSS 168//#define CONFIG_FEATURE_BUFFERS_GO_IN_BSS
169// 169//
170// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, 170// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
171// thereby eliminating the need for the /proc filesystem and thereby saving 171// thereby eliminating the need for the /proc filesystem and thereby saving
@@ -176,212 +176,212 @@
176// mknod /dev/mtab c 10 22 176// mknod /dev/mtab c 10 22
177// mknod /dev/ps c 10 21 177// mknod /dev/ps c 10 21
178// I emailed Linus and this patch will not be going into the stock kernel. 178// I emailed Linus and this patch will not be going into the stock kernel.
179//#define BB_FEATURE_USE_DEVPS_PATCH 179//#define CONFIG_FEATURE_USE_DEVPS_PATCH
180// 180//
181// show verbose usage messages 181// show verbose usage messages
182#define BB_FEATURE_VERBOSE_USAGE 182#define CONFIG_FEATURE_VERBOSE_USAGE
183// 183//
184// Use termios to manipulate the screen ('more' is prettier with this on) 184// Use termios to manipulate the screen ('more' is prettier with this on)
185#define BB_FEATURE_USE_TERMIOS 185#define CONFIG_FEATURE_USE_TERMIOS
186// 186//
187// calculate terminal & column widths (for more and ls) 187// calculate terminal & column widths (for more and ls)
188#define BB_FEATURE_AUTOWIDTH 188#define CONFIG_FEATURE_AUTOWIDTH
189// 189//
190// show username/groupnames for ls 190// show username/groupnames for ls
191#define BB_FEATURE_LS_USERNAME 191#define CONFIG_FEATURE_LS_USERNAME
192// 192//
193// show file timestamps in ls 193// show file timestamps in ls
194#define BB_FEATURE_LS_TIMESTAMPS 194#define CONFIG_FEATURE_LS_TIMESTAMPS
195// 195//
196// enable ls -p and -F 196// enable ls -p and -F
197#define BB_FEATURE_LS_FILETYPES 197#define CONFIG_FEATURE_LS_FILETYPES
198// 198//
199// sort the file names 199// sort the file names
200#define BB_FEATURE_LS_SORTFILES 200#define CONFIG_FEATURE_LS_SORTFILES
201// 201//
202// enable ls -R 202// enable ls -R
203#define BB_FEATURE_LS_RECURSIVE 203#define CONFIG_FEATURE_LS_RECURSIVE
204// 204//
205// enable ls -L 205// enable ls -L
206#define BB_FEATURE_LS_FOLLOWLINKS 206#define CONFIG_FEATURE_LS_FOLLOWLINKS
207// 207//
208// Disable for a smaller (but less functional) ping 208// Disable for a smaller (but less functional) ping
209#define BB_FEATURE_FANCY_PING 209#define CONFIG_FEATURE_FANCY_PING
210// 210//
211// Make init use a simplified /etc/inittab file (recommended). 211// Make init use a simplified /etc/inittab file (recommended).
212#define BB_FEATURE_USE_INITTAB 212#define CONFIG_FEATURE_USE_INITTAB
213// 213//
214//Enable init being called as /linuxrc 214//Enable init being called as /linuxrc
215#define BB_FEATURE_LINUXRC 215#define CONFIG_FEATURE_INITRD
216// 216//
217//Have init enable core dumping for child processes (for debugging only) 217//Have init enable core dumping for child processes (for debugging only)
218//#define BB_FEATURE_INIT_COREDUMPS 218//#define CONFIG_FEATURE_INIT_COREDUMPS
219// 219//
220//Make sure nothing is printed to the console on boot 220//Make sure nothing is printed to the console on boot
221//#define BB_FEATURE_EXTRA_QUIET 221//#define CONFIG_FEATURE_EXTRA_QUIET
222// 222//
223// enable syslogd -R remotehost 223// enable syslogd -R remotehost
224#define BB_FEATURE_REMOTE_LOG 224#define CONFIG_FEATURE_REMOTE_LOG
225// 225//
226// enable syslogd -C 226// enable syslogd -C
227//#define BB_FEATURE_IPC_SYSLOG 227//#define CONFIG_FEATURE_IPC_SYSLOG
228// 228//
229//Disable for a simple tail implementation (2.34k vs 3k for the full one). 229//Disable for a simple tail implementation (2.34k vs 3k for the full one).
230//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 230//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v.
231#define BB_FEATURE_FANCY_TAIL 231#define CONFIG_FEATURE_FANCY_TAIL
232// 232//
233// Enable support for loop devices in mount 233// Enable support for loop devices in mount
234#define BB_FEATURE_MOUNT_LOOP 234#define CONFIG_FEATURE_MOUNT_LOOP
235// 235//
236// Enable support for a real /etc/mtab file instead of /proc/mounts 236// Enable support for a real /etc/mtab file instead of /proc/mounts
237//#define BB_FEATURE_MTAB_SUPPORT 237//#define CONFIG_FEATURE_MTAB_SUPPORT
238// 238//
239// Enable support for mounting remote NFS volumes. 239// Enable support for mounting remote NFS volumes.
240// You may need to mount with "-o nolock" if you are 240// You may need to mount with "-o nolock" if you are
241// not running a local portmapper daemon... 241// not running a local portmapper daemon...
242#define BB_FEATURE_NFSMOUNT 242#define CONFIG_FEATURE_NFSMOUNT
243// 243//
244// Enable support forced filesystem unmounting 244// Enable support forced filesystem unmounting
245// (i.e., in case of an unreachable NFS system). 245// (i.e., in case of an unreachable NFS system).
246#define BB_FEATURE_MOUNT_FORCE 246#define CONFIG_FEATURE_MOUNT_FORCE
247// 247//
248// Enable support for creation of tar files. 248// Enable support for creation of tar files.
249#define BB_FEATURE_TAR_CREATE 249#define CONFIG_FEATURE_TAR_CREATE
250// 250//
251// Enable support for "--exclude" and "-X" for excluding files 251// Enable support for "--exclude" and "-X" for excluding files
252#define BB_FEATURE_TAR_EXCLUDE 252#define CONFIG_FEATURE_TAR_EXCLUDE
253// 253//
254// Enable support for tar -z option (currently only works for inflating) 254// Enable support for tar -z option (currently only works for inflating)
255#define BB_FEATURE_TAR_GZIP 255#define CONFIG_FEATURE_TAR_GZIP
256// 256//
257// Enable reverse sort 257// Enable reverse sort
258#define BB_FEATURE_SORT_REVERSE 258#define CONFIG_FEATURE_SORT_REVERSE
259// 259//
260// Enable uniqe sort 260// Enable uniqe sort
261#define BB_FEATURE_SORT_UNIQUE 261#define CONFIG_FEATURE_SORT_UNIQUE
262// 262//
263// Enable command line editing in the shell. 263// Enable command line editing in the shell.
264// Only relevant if a shell is enabled. On by default. 264// Only relevant if a shell is enabled. On by default.
265#define BB_FEATURE_COMMAND_EDITING 265#define CONFIG_FEATURE_COMMAND_EDITING
266// 266//
267// Enable tab completion in the shell. This is now working quite nicely. 267// Enable tab completion in the shell. This is now working quite nicely.
268// This feature adds a bit over 4k. Only relevant if a shell is enabled. 268// This feature adds a bit over 4k. Only relevant if a shell is enabled.
269#define BB_FEATURE_COMMAND_TAB_COMPLETION 269#define CONFIG_FEATURE_COMMAND_TAB_COMPLETION
270// 270//
271// Attempts to match usernames in a ~-prefixed path 271// Attempts to match usernames in a ~-prefixed path
272//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION 272//#define CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
273// 273//
274//Allow the shell to invoke all the compiled in BusyBox applets as if they 274//Allow the shell to invoke all the compiled in BusyBox applets as if they
275//were shell builtins. Nice for staticly linking an emergency rescue shell, 275//were shell builtins. Nice for staticly linking an emergency rescue shell,
276//among other things. Off by default. 276//among other things. Off by default.
277// Only relevant if a shell is enabled. 277// Only relevant if a shell is enabled.
278#define BB_FEATURE_SH_STANDALONE_SHELL 278#define CONFIG_FEATURE_SH_STANDALONE_SHELL
279// 279//
280//When this is enabled, busybox shell applets can be called using full path 280//When this is enabled, busybox shell applets can be called using full path
281//names. This causes applets (i.e., most busybox commands) to override 281//names. This causes applets (i.e., most busybox commands) to override
282//real commands on the filesystem. For example, if you run run /bin/cat, it 282//real commands on the filesystem. For example, if you run run /bin/cat, it
283//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ 283//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
284//busybox. Some systems want this, others do not. Choose wisely. :-) This 284//busybox. Some systems want this, others do not. Choose wisely. :-) This
285//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. 285//only has meaning when CONFIG_FEATURE_SH_STANDALONE_SHELL is enabled.
286// Only relevant if a shell is enabled. Off by default. 286// Only relevant if a shell is enabled. Off by default.
287#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN 287#define CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
288// 288//
289// Uncomment this option for a fancy shell prompt that includes the 289// Uncomment this option for a fancy shell prompt that includes the
290// current username and hostname. On systems that don't have usernames 290// current username and hostname. On systems that don't have usernames
291// or hostnames, this can look hideous. 291// or hostnames, this can look hideous.
292// Only relevant if a shell is enabled. 292// Only relevant if a shell is enabled.
293#define BB_FEATURE_SH_FANCY_PROMPT 293#define CONFIG_FEATURE_SH_FANCY_PROMPT
294// 294//
295//Turn on extra fbset options 295//Turn on extra fbset options
296//#define BB_FEATURE_FBSET_FANCY 296//#define CONFIG_FEATURE_FBSET_FANCY
297// 297//
298//Turn on fbset readmode support 298//Turn on fbset readmode support
299//#define BB_FEATURE_FBSET_READMODE 299//#define CONFIG_FEATURE_FBSET_READMODE
300// 300//
301// Support insmod/lsmod/rmmod for post 2.1 kernels 301// Support insmod/lsmod/rmmod for post 2.1 kernels
302#define BB_FEATURE_NEW_MODULE_INTERFACE 302#define CONFIG_FEATURE_NEW_MODULE_INTERFACE
303// 303//
304// Support insmod/lsmod/rmmod for pre 2.1 kernels 304// Support insmod/lsmod/rmmod for pre 2.1 kernels
305//#define BB_FEATURE_OLD_MODULE_INTERFACE 305//#define CONFIG_FEATURE_OLD_MODULE_INTERFACE
306// 306//
307// Support module version checking 307// Support module version checking
308//#define BB_FEATURE_INSMOD_VERSION_CHECKING 308//#define CONFIG_FEATURE_INSMOD_VERSION_CHECKING
309// 309//
310// Support for uClinux memory usage optimization, which will load the image 310// Support for uClinux memory usage optimization, which will load the image
311// directly into the kernel memory. This divides memory requrements by three. 311// directly into the kernel memory. This divides memory requrements by three.
312// If you are not running uClinux (i.e., your CPU has an MMU) leave this 312// If you are not running uClinux (i.e., your CPU has an MMU) leave this
313// disabled... 313// disabled...
314//#define BB_FEATURE_INSMOD_LOADINKMEM 314//#define CONFIG_FEATURE_INSMOD_LOADINKMEM
315// 315//
316// Support for Minix filesystem, version 2 316// Support for Minix filesystem, version 2
317//#define BB_FEATURE_MINIX2 317//#define CONFIG_FEATURE_MINIX2
318// 318//
319// Enable ifconfig status reporting output -- this feature adds 12k. 319// Enable ifconfig status reporting output -- this feature adds 12k.
320#define BB_FEATURE_IFCONFIG_STATUS 320#define CONFIG_FEATURE_IFCONFIG_STATUS
321// 321//
322// Enable ifconfig slip-specific options "keepalive" and "outfill" 322// Enable ifconfig slip-specific options "keepalive" and "outfill"
323//#define BB_FEATURE_IFCONFIG_SLIP 323//#define CONFIG_FEATURE_IFCONFIG_SLIP
324// 324//
325// Enable ifconfig options "mem_start", "io_addr", and "irq". 325// Enable ifconfig options "mem_start", "io_addr", and "irq".
326//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 326//#define CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
327// 327//
328// Enable ifconfig option "hw". Currently works for only with "ether". 328// Enable ifconfig option "hw". Currently works for only with "ether".
329#define BB_FEATURE_IFCONFIG_HW 329#define CONFIG_FEATURE_IFCONFIG_HW
330// 330//
331// Enable busybox --install [-s] 331// Enable busybox --install [-s]
332// to create links (or symlinks) for all the commands that are 332// to create links (or symlinks) for all the commands that are
333// compiled into the binary. (needs /proc filesystem) 333// compiled into the binary. (needs /proc filesystem)
334#define BB_FEATURE_INSTALLER 334#define CONFIG_FEATURE_INSTALLER
335// 335//
336// Enable a nifty progress meter in wget (adds just under 2k) 336// Enable a nifty progress meter in wget (adds just under 2k)
337#define BB_FEATURE_WGET_STATUSBAR 337#define CONFIG_FEATURE_WGET_STATUSBAR
338// 338//
339// Enable HTTP authentication in wget 339// Enable HTTP authentication in wget
340#define BB_FEATURE_WGET_AUTHENTICATION 340#define CONFIG_FEATURE_WGET_AUTHENTICATION
341// 341//
342// Clean up all memory before exiting -- usually not needed 342// Clean up all memory before exiting -- usually not needed
343// as the OS can clean up... Don't enable this unless you 343// as the OS can clean up... Don't enable this unless you
344// have a really good reason for cleaning things up manually. 344// have a really good reason for cleaning things up manually.
345//#define BB_FEATURE_CLEAN_UP 345//#define CONFIG_FEATURE_CLEAN_UP
346// 346//
347// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) 347// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
348#define BB_FEATURE_HUMAN_READABLE 348#define CONFIG_FEATURE_HUMAN_READABLE
349// 349//
350// Support for the find -type option. 350// Support for the find -type option.
351#define BB_FEATURE_FIND_TYPE 351#define CONFIG_FEATURE_FIND_TYPE
352// 352//
353// Support for the find -perm option. 353// Support for the find -perm option.
354#define BB_FEATURE_FIND_PERM 354#define CONFIG_FEATURE_FIND_PERM
355// 355//
356// Support for the find -mtine option. 356// Support for the find -mtine option.
357#define BB_FEATURE_FIND_MTIME 357#define CONFIG_FEATURE_FIND_MTIME
358// 358//
359// Support for the -A -B and -C context flags in grep 359// Support for the -A -B and -C context flags in grep
360//#define BB_FEATURE_GREP_CONTEXT 360//#define CONFIG_FEATURE_GREP_CONTEXT
361// 361//
362// Support for the EGREP applet (alias to the grep applet) 362// Support for the EGREP applet (alias to the grep applet)
363//#define BB_FEATURE_GREP_EGREP_ALIAS 363//#define CONFIG_FEATURE_GREP_EGREP_ALIAS
364// 364//
365// Tell tftp what commands that should be supported. 365// Tell tftp what commands that should be supported.
366#define BB_FEATURE_TFTP_PUT 366#define CONFIG_FEATURE_TFTP_PUT
367#define BB_FEATURE_TFTP_GET 367#define CONFIG_FEATURE_TFTP_GET
368// 368//
369// features for vi 369// features for vi
370#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode 370#define CONFIG_FEATURE_VI_COLON // ":" colon commands, no "ex" mode
371#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds 371#define CONFIG_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds
372#define BB_FEATURE_VI_SEARCH // search and replace cmds 372#define CONFIG_FEATURE_VI_SEARCH // search and replace cmds
373#define BB_FEATURE_VI_USE_SIGNALS // catch signals 373#define CONFIG_FEATURE_VI_USE_SIGNALS // catch signals
374#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd 374#define CONFIG_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd
375#define BB_FEATURE_VI_READONLY // vi -R and "view" mode 375#define CONFIG_FEATURE_VI_READONLY // vi -R and "view" mode
376#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch 376#define CONFIG_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch
377#define BB_FEATURE_VI_SET // :set 377#define CONFIG_FEATURE_VI_SET // :set
378#define BB_FEATURE_VI_WIN_RESIZE // handle window resize 378#define CONFIG_FEATURE_VI_WIN_RESIZE // handle window resize
379// 379//
380// Enable a if you system have setuped locale 380// Enable a if you system have setuped locale
381//#define BB_LOCALE_SUPPORT 381//#define CONFIG_LOCALE_SUPPORT
382// 382//
383// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. 383// Support for TELNET to pass TERM type to remote host. Adds 384 bytes.
384#define BB_FEATURE_TELNET_TTYPE 384#define CONFIG_FEATURE_TELNET_TTYPE
385// 385//
386// End of Features List 386// End of Features List
387// 387//
@@ -396,74 +396,74 @@
396// 396//
397#include <features.h> 397#include <features.h>
398#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ 398#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__
399 #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ 399 #undef CONFIG_RPM2CPIO /* Uses gz_open(), which uses fork() */
400 #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ 400 #undef CONFIG_DPKG_DEB /* Uses gz_open(), which uses fork() */
401 #undef BB_ASH /* Uses fork() */ 401 #undef CONFIG_ASH /* Uses fork() */
402 #undef BB_HUSH /* Uses fork() */ 402 #undef CONFIG_HUSH /* Uses fork() */
403 #undef BB_LASH /* Uses fork() */ 403 #undef CONFIG_LASH /* Uses fork() */
404 #undef BB_INIT /* Uses fork() */ 404 #undef CONFIG_INIT /* Uses fork() */
405 #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ 405 #undef CONFIG_FEATURE_TAR_GZIP /* Uses fork() */
406 #undef BB_SYSLOGD /* Uses daemon() */ 406 #undef CONFIG_SYSLOGD /* Uses daemon() */
407 #undef BB_KLOGD /* Uses daemon() */ 407 #undef CONFIG_KLOGD /* Uses daemon() */
408 #undef BB_UPDATE /* Uses daemon() */ 408 #undef CONFIG_UPDATE /* Uses daemon() */
409#endif 409#endif
410#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH 410#if defined CONFIG_ASH || defined CONFIG_HUSH || defined CONFIG_LASH || defined CONFIG_MSH
411 #if defined BB_FEATURE_COMMAND_EDITING 411 #if defined CONFIG_FEATURE_COMMAND_EDITING
412 #define BB_CMDEDIT 412 #define CONFIG_CMDEDIT
413 #else 413 #else
414 #undef BB_FEATURE_COMMAND_EDITING 414 #undef CONFIG_FEATURE_COMMAND_EDITING
415 #undef BB_FEATURE_COMMAND_TAB_COMPLETION 415 #undef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
416 #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION 416 #undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
417 #undef BB_FEATURE_SH_FANCY_PROMPT 417 #undef CONFIG_FEATURE_SH_FANCY_PROMPT
418 #endif 418 #endif
419#else 419#else
420 #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 420 #undef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
421 #undef BB_FEATURE_SH_STANDALONE_SHELL 421 #undef CONFIG_FEATURE_SH_STANDALONE_SHELL
422 #undef BB_FEATURE_SH_FANCY_PROMPT 422 #undef CONFIG_FEATURE_SH_FANCY_PROMPT
423#endif 423#endif
424// 424//
425#ifdef BB_KILLALL 425#ifdef CONFIG_KILLALL
426 #ifndef BB_KILL 426 #ifndef CONFIG_KILL
427 #define BB_KILL 427 #define CONFIG_KILL
428 #endif 428 #endif
429#endif 429#endif
430// 430//
431#ifndef BB_INIT 431#ifndef CONFIG_INIT
432 #undef BB_FEATURE_LINUXRC 432 #undef CONFIG_FEATURE_INITRD
433#endif 433#endif
434// 434//
435#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT 435#if defined CONFIG_MOUNT && defined CONFIG_FEATURE_NFSMOUNT
436 #define BB_NFSMOUNT 436 #define CONFIG_NFSMOUNT
437#endif 437#endif
438// 438//
439#if defined BB_FEATURE_AUTOWIDTH 439#if defined CONFIG_FEATURE_AUTOWIDTH
440 #ifndef BB_FEATURE_USE_TERMIOS 440 #ifndef CONFIG_FEATURE_USE_TERMIOS
441 #define BB_FEATURE_USE_TERMIOS 441 #define CONFIG_FEATURE_USE_TERMIOS
442 #endif 442 #endif
443#endif 443#endif
444// 444//
445#if defined BB_INSMOD || defined BB_LSMOD 445#if defined CONFIG_INSMOD || defined CONFIG_LSMOD
446 #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE 446 #if ! defined CONFIG_FEATURE_NEW_MODULE_INTERFACE && ! defined CONFIG_FEATURE_OLD_MODULE_INTERFACE
447 #define BB_FEATURE_NEW_MODULE_INTERFACE 447 #define CONFIG_FEATURE_NEW_MODULE_INTERFACE
448 #endif 448 #endif
449#endif 449#endif
450// 450//
451#ifdef BB_UNIX2DOS 451#ifdef CONFIG_UNIX2DOS
452 #define BB_DOS2UNIX 452 #define CONFIG_DOS2UNIX
453#endif 453#endif
454// 454//
455#ifdef BB_SYSLOGD 455#ifdef CONFIG_SYSLOGD
456 #if defined BB_FEATURE_IPC_SYSLOG 456 #if defined CONFIG_FEATURE_IPC_SYSLOG
457 #define BB_LOGREAD 457 #define CONFIG_LOGREAD
458 #endif 458 #endif
459#endif 459#endif
460// 460//
461#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH 461#if defined CONFIG_ASH && defined CONFIG_FEATURE_SH_IS_ASH
462# define shell_main ash_main 462# define shell_main ash_main
463#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH 463#elif defined CONFIG_HUSH && defined CONFIG_FEATURE_SH_IS_HUSH
464# define shell_main hush_main 464# define shell_main hush_main
465#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH 465#elif defined CONFIG_LASH && defined CONFIG_FEATURE_SH_IS_LASH
466# define shell_main lash_main 466# define shell_main lash_main
467#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH 467#elif defined CONFIG_MSH && defined CONFIG_FEATURE_SH_IS_MSH
468# define shell_main msh_main 468# define shell_main msh_main
469#endif 469#endif
diff --git a/debian/Config.h-udeb b/debian/Config.h-udeb
index 8e7594dc4..28c4031c5 100644
--- a/debian/Config.h-udeb
+++ b/debian/Config.h-udeb
@@ -3,142 +3,142 @@
3// When you turn things off here, they won't be compiled in at all. 3// When you turn things off here, they won't be compiled in at all.
4// 4//
5//// This file is parsed by sed. You MUST use single line comments. 5//// This file is parsed by sed. You MUST use single line comments.
6// i.e., //#define BB_BLAH 6// i.e., //#define CONFIG_BLAH
7// 7//
8// 8//
9// BusyBox Applications 9// BusyBox Applications
10//#define BB_ADJTIMEX 10//#define CONFIG_ADJTIMEX
11//#define BB_AR 11//#define CONFIG_AR
12//#define BB_ASH 12//#define CONFIG_ASH
13#define BB_BASENAME 13#define CONFIG_BASENAME
14#define BB_CAT 14#define CONFIG_CAT
15#define BB_CHGRP 15#define CONFIG_CHGRP
16#define BB_CHMOD 16#define CONFIG_CHMOD
17#define BB_CHOWN 17#define CONFIG_CHOWN
18#define BB_CHROOT 18#define CONFIG_CHROOT
19#define BB_CHVT 19#define CONFIG_CHVT
20#define BB_CLEAR 20#define CONFIG_CLEAR
21//#define BB_CMP 21//#define CONFIG_CMP
22#define BB_CP 22#define CONFIG_CP
23//#define BB_CPIO 23//#define CONFIG_CPIO
24#define BB_CUT 24#define CONFIG_CUT
25#define BB_DATE 25#define CONFIG_DATE
26//#define BB_DC 26//#define CONFIG_DC
27#define BB_DD 27#define CONFIG_DD
28//#define BB_DEALLOCVT 28//#define CONFIG_DEALLOCVT
29#define BB_DF 29#define CONFIG_DF
30#define BB_DIRNAME 30#define CONFIG_DIRNAME
31#define BB_DMESG 31#define CONFIG_DMESG
32//#define BB_DOS2UNIX 32//#define CONFIG_DOS2UNIX
33//#define BB_DPKG 33//#define CONFIG_DPKG
34//#define BB_DPKG_DEB 34//#define CONFIG_DPKG_DEB
35//#define BB_DUTMP 35//#define CONFIG_DUTMP
36#define BB_DU 36#define CONFIG_DU
37//#define BB_DUMPKMAP 37//#define CONFIG_DUMPKMAP
38#define BB_ECHO 38#define CONFIG_ECHO
39#define BB_ENV 39#define CONFIG_ENV
40#define BB_EXPR 40#define CONFIG_EXPR
41//#define BB_FBSET 41//#define CONFIG_FBSET
42//#define BB_FDFLUSH 42//#define CONFIG_FDFLUSH
43#define BB_FIND 43#define CONFIG_FIND
44#define BB_FREE 44#define CONFIG_FREE
45#define BB_FREERAMDISK 45#define CONFIG_FREERAMDISK
46//#define BB_FSCK_MINIX 46//#define CONFIG_FSCK_MINIX
47//#define BB_GETOPT 47//#define CONFIG_GETOPT
48#define BB_GREP 48#define CONFIG_GREP
49#define BB_GUNZIP 49#define CONFIG_GUNZIP
50#define BB_GZIP 50#define CONFIG_GZIP
51#define BB_HALT 51#define CONFIG_HALT
52#define BB_HEAD 52#define CONFIG_HEAD
53//#define BB_HOSTID 53//#define CONFIG_HOSTID
54//#define BB_HOSTNAME 54//#define CONFIG_HOSTNAME
55//#define BB_HUSH 55//#define CONFIG_HUSH
56#define BB_ID 56#define CONFIG_ID
57//#define BB_IFCONFIG 57//#define CONFIG_IFCONFIG
58#define BB_INIT 58#define CONFIG_INIT
59//#define BB_INSMOD 59//#define CONFIG_INSMOD
60#define BB_KILL 60#define CONFIG_KILL
61#define BB_KILLALL 61#define CONFIG_KILLALL
62#define BB_KLOGD 62#define CONFIG_KLOGD
63//#define BB_LASH 63//#define CONFIG_LASH
64//#define BB_LENGTH 64//#define CONFIG_LENGTH
65#define BB_LN 65#define CONFIG_LN
66//#define BB_LOADACM 66//#define CONFIG_LOADACM
67//#define BB_LOADFONT 67//#define CONFIG_LOADFONT
68#define BB_LOADKMAP 68#define CONFIG_LOADKMAP
69#define BB_LOGGER 69#define CONFIG_LOGGER
70//#define BB_LOGNAME 70//#define CONFIG_LOGNAME
71#define BB_LS 71#define CONFIG_LS
72#define BB_LSMOD 72#define CONFIG_LSMOD
73//#define BB_MAKEDEVS 73//#define CONFIG_MAKEDEVS
74#define BB_MD5SUM 74#define CONFIG_MD5SUM
75#define BB_MKDIR 75#define CONFIG_MKDIR
76//#define BB_MKFIFO 76//#define CONFIG_MKFIFO
77//#define BB_MKFS_MINIX 77//#define CONFIG_MKFS_MINIX
78#define BB_MKNOD 78#define CONFIG_MKNOD
79#define BB_MKSWAP 79#define CONFIG_MKSWAP
80//#define BB_MKTEMP 80//#define CONFIG_MKTEMP
81//#define BB_MODPROBE 81//#define CONFIG_MODPROBE
82#define BB_MORE 82#define CONFIG_MORE
83#define BB_MOUNT 83#define CONFIG_MOUNT
84//#define BB_MSH 84//#define CONFIG_MSH
85//#define BB_MT 85//#define CONFIG_MT
86#define BB_MV 86#define CONFIG_MV
87//#define BB_NC 87//#define CONFIG_NC
88//#define BB_NSLOOKUP 88//#define CONFIG_NSLOOKUP
89//#define BB_PIDOF 89//#define CONFIG_PIDOF
90#define BB_PING 90#define CONFIG_PING
91#define BB_PIVOT_ROOT 91#define CONFIG_PIVOT_ROOT
92#define BB_POWEROFF 92#define CONFIG_POWEROFF
93//#define BB_PRINTF 93//#define CONFIG_PRINTF
94#define BB_PS 94#define CONFIG_PS
95#define BB_PWD 95#define CONFIG_PWD
96//#define BB_RDATE 96//#define CONFIG_RDATE
97//#define BB_READLINK 97//#define CONFIG_READLINK
98#define BB_REBOOT 98#define CONFIG_REBOOT
99//#define BB_RENICE 99//#define CONFIG_RENICE
100#define BB_RESET 100#define CONFIG_RESET
101#define BB_RM 101#define CONFIG_RM
102#define BB_RMDIR 102#define CONFIG_RMDIR
103//#define BB_RMMOD 103//#define CONFIG_RMMOD
104//#define BB_ROUTE 104//#define CONFIG_ROUTE
105//#define BB_RPM2CPIO 105//#define CONFIG_RPM2CPIO
106#define BB_SED 106#define CONFIG_SED
107//#define BB_SETKEYCODES 107//#define CONFIG_SETKEYCODES
108#define BB_SLEEP 108#define CONFIG_SLEEP
109#define BB_SORT 109#define CONFIG_SORT
110//#define BB_STTY 110//#define CONFIG_STTY
111#define BB_SWAPONOFF 111#define CONFIG_SWAPONOFF
112#define BB_SYNC 112#define CONFIG_SYNC
113#define BB_SYSLOGD 113#define CONFIG_SYSLOGD
114#define BB_TAIL 114#define CONFIG_TAIL
115#define BB_TAR 115#define CONFIG_TAR
116//#define BB_TEE 116//#define CONFIG_TEE
117//#define BB_TEST 117//#define CONFIG_TEST
118#define BB_TELNET 118#define CONFIG_TELNET
119//#define BB_TFTP 119//#define CONFIG_TFTP
120#define BB_TOUCH 120#define CONFIG_TOUCH
121#define BB_TR 121#define CONFIG_TR
122//#define BB_TRACEROUTE 122//#define CONFIG_TRACEROUTE
123#define BB_TRUE_FALSE 123#define CONFIG_TRUE_FALSE
124#define BB_TTY 124#define CONFIG_TTY
125//#define BB_UNIX2DOS 125//#define CONFIG_UNIX2DOS
126//#define BB_UUENCODE 126//#define CONFIG_UUENCODE
127//#define BB_UUDECODE 127//#define CONFIG_UUDECODE
128#define BB_UMOUNT 128#define CONFIG_UMOUNT
129#define BB_UNIQ 129#define CONFIG_UNIQ
130#define BB_UNAME 130#define CONFIG_UNAME
131//#define BB_UPDATE 131//#define CONFIG_UPDATE
132#define BB_UPTIME 132#define CONFIG_UPTIME
133//#define BB_USLEEP 133//#define CONFIG_USLEEP
134#define BB_VI 134#define CONFIG_VI
135//#define BB_WATCHDOG 135//#define CONFIG_WATCHDOG
136#define BB_WC 136#define CONFIG_WC
137#define BB_WGET 137#define CONFIG_WGET
138#define BB_WHICH 138#define CONFIG_WHICH
139#define BB_WHOAMI 139#define CONFIG_WHOAMI
140#define BB_XARGS 140#define CONFIG_XARGS
141#define BB_YES 141#define CONFIG_YES
142// End of Applications List 142// End of Applications List
143// 143//
144// 144//
@@ -151,21 +151,21 @@
151// 151//
152// If you enabled one or more of the shells, you may select which one 152// If you enabled one or more of the shells, you may select which one
153// should be run when sh is invoked: 153// should be run when sh is invoked:
154//#define BB_FEATURE_SH_IS_ASH 154//#define CONFIG_FEATURE_SH_IS_ASH
155//#define BB_FEATURE_SH_IS_HUSH 155//#define CONFIG_FEATURE_SH_IS_HUSH
156//#define BB_FEATURE_SH_IS_LASH 156//#define CONFIG_FEATURE_SH_IS_LASH
157#define BB_FEATURE_SH_IS_MSH 157#define CONFIG_FEATURE_SH_IS_MSH
158// 158//
159// BusyBox will, by default, malloc space for its buffers. This costs code 159// BusyBox will, by default, malloc space for its buffers. This costs code
160// size for the call to xmalloc. You can use the following feature to have 160// size for the call to xmalloc. You can use the following feature to have
161// them put on the stack. For some very small machines with limited stack 161// them put on the stack. For some very small machines with limited stack
162// space, this can be deadly. For most folks, this works just fine... 162// space, this can be deadly. For most folks, this works just fine...
163//#define BB_FEATURE_BUFFERS_GO_ON_STACK 163//#define CONFIG_FEATURE_BUFFERS_GO_ON_STACK
164// The third alternative for buffer allocation is to use BSS. This works 164// The third alternative for buffer allocation is to use BSS. This works
165// beautifully for computers with a real MMU (and OS support), but wastes 165// beautifully for computers with a real MMU (and OS support), but wastes
166// runtime RAM for uCLinux. This behavior was the only one available for 166// runtime RAM for uCLinux. This behavior was the only one available for
167// BusyBox versions 0.48 and earlier. 167// BusyBox versions 0.48 and earlier.
168//#define BB_FEATURE_BUFFERS_GO_IN_BSS 168//#define CONFIG_FEATURE_BUFFERS_GO_IN_BSS
169// 169//
170// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, 170// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
171// thereby eliminating the need for the /proc filesystem and thereby saving 171// thereby eliminating the need for the /proc filesystem and thereby saving
@@ -176,212 +176,212 @@
176// mknod /dev/mtab c 10 22 176// mknod /dev/mtab c 10 22
177// mknod /dev/ps c 10 21 177// mknod /dev/ps c 10 21
178// I emailed Linus and this patch will not be going into the stock kernel. 178// I emailed Linus and this patch will not be going into the stock kernel.
179//#define BB_FEATURE_USE_DEVPS_PATCH 179//#define CONFIG_FEATURE_USE_DEVPS_PATCH
180// 180//
181// show verbose usage messages 181// show verbose usage messages
182//#define BB_FEATURE_VERBOSE_USAGE 182//#define CONFIG_FEATURE_VERBOSE_USAGE
183// 183//
184// Use termios to manipulate the screen ('more' is prettier with this on) 184// Use termios to manipulate the screen ('more' is prettier with this on)
185#define BB_FEATURE_USE_TERMIOS 185#define CONFIG_FEATURE_USE_TERMIOS
186// 186//
187// calculate terminal & column widths (for more and ls) 187// calculate terminal & column widths (for more and ls)
188#define BB_FEATURE_AUTOWIDTH 188#define CONFIG_FEATURE_AUTOWIDTH
189// 189//
190// show username/groupnames for ls 190// show username/groupnames for ls
191#define BB_FEATURE_LS_USERNAME 191#define CONFIG_FEATURE_LS_USERNAME
192// 192//
193// show file timestamps in ls 193// show file timestamps in ls
194#define BB_FEATURE_LS_TIMESTAMPS 194#define CONFIG_FEATURE_LS_TIMESTAMPS
195// 195//
196// enable ls -p and -F 196// enable ls -p and -F
197#define BB_FEATURE_LS_FILETYPES 197#define CONFIG_FEATURE_LS_FILETYPES
198// 198//
199// sort the file names 199// sort the file names
200#define BB_FEATURE_LS_SORTFILES 200#define CONFIG_FEATURE_LS_SORTFILES
201// 201//
202// enable ls -R 202// enable ls -R
203#define BB_FEATURE_LS_RECURSIVE 203#define CONFIG_FEATURE_LS_RECURSIVE
204// 204//
205// enable ls -L 205// enable ls -L
206#define BB_FEATURE_LS_FOLLOWLINKS 206#define CONFIG_FEATURE_LS_FOLLOWLINKS
207// 207//
208// Disable for a smaller (but less functional) ping 208// Disable for a smaller (but less functional) ping
209#define BB_FEATURE_FANCY_PING 209#define CONFIG_FEATURE_FANCY_PING
210// 210//
211// Make init use a simplified /etc/inittab file (recommended). 211// Make init use a simplified /etc/inittab file (recommended).
212#define BB_FEATURE_USE_INITTAB 212#define CONFIG_FEATURE_USE_INITTAB
213// 213//
214//Enable init being called as /linuxrc 214//Enable init being called as /linuxrc
215#define BB_FEATURE_LINUXRC 215#define CONFIG_FEATURE_INITRD
216// 216//
217//Have init enable core dumping for child processes (for debugging only) 217//Have init enable core dumping for child processes (for debugging only)
218//#define BB_FEATURE_INIT_COREDUMPS 218//#define CONFIG_FEATURE_INIT_COREDUMPS
219// 219//
220//Make sure nothing is printed to the console on boot 220//Make sure nothing is printed to the console on boot
221//#define BB_FEATURE_EXTRA_QUIET 221//#define CONFIG_FEATURE_EXTRA_QUIET
222// 222//
223// enable syslogd -R remotehost 223// enable syslogd -R remotehost
224#define BB_FEATURE_REMOTE_LOG 224#define CONFIG_FEATURE_REMOTE_LOG
225// 225//
226// enable syslogd -C 226// enable syslogd -C
227//#define BB_FEATURE_IPC_SYSLOG 227//#define CONFIG_FEATURE_IPC_SYSLOG
228// 228//
229//Disable for a simple tail implementation (2.34k vs 3k for the full one). 229//Disable for a simple tail implementation (2.34k vs 3k for the full one).
230//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 230//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v.
231#define BB_FEATURE_FANCY_TAIL 231#define CONFIG_FEATURE_FANCY_TAIL
232// 232//
233// Enable support for loop devices in mount 233// Enable support for loop devices in mount
234#define BB_FEATURE_MOUNT_LOOP 234#define CONFIG_FEATURE_MOUNT_LOOP
235// 235//
236// Enable support for a real /etc/mtab file instead of /proc/mounts 236// Enable support for a real /etc/mtab file instead of /proc/mounts
237//#define BB_FEATURE_MTAB_SUPPORT 237//#define CONFIG_FEATURE_MTAB_SUPPORT
238// 238//
239// Enable support for mounting remote NFS volumes. 239// Enable support for mounting remote NFS volumes.
240// You may need to mount with "-o nolock" if you are 240// You may need to mount with "-o nolock" if you are
241// not running a local portmapper daemon... 241// not running a local portmapper daemon...
242#define BB_FEATURE_NFSMOUNT 242#define CONFIG_FEATURE_NFSMOUNT
243// 243//
244// Enable support forced filesystem unmounting 244// Enable support forced filesystem unmounting
245// (i.e., in case of an unreachable NFS system). 245// (i.e., in case of an unreachable NFS system).
246#define BB_FEATURE_MOUNT_FORCE 246#define CONFIG_FEATURE_MOUNT_FORCE
247// 247//
248// Enable support for creation of tar files. 248// Enable support for creation of tar files.
249#define BB_FEATURE_TAR_CREATE 249#define CONFIG_FEATURE_TAR_CREATE
250// 250//
251// Enable support for "--exclude" and "-X" for excluding files 251// Enable support for "--exclude" and "-X" for excluding files
252#define BB_FEATURE_TAR_EXCLUDE 252#define CONFIG_FEATURE_TAR_EXCLUDE
253// 253//
254// Enable support for tar -z option (currently only works for inflating) 254// Enable support for tar -z option (currently only works for inflating)
255#define BB_FEATURE_TAR_GZIP 255#define CONFIG_FEATURE_TAR_GZIP
256// 256//
257// Enable reverse sort 257// Enable reverse sort
258#define BB_FEATURE_SORT_REVERSE 258#define CONFIG_FEATURE_SORT_REVERSE
259// 259//
260// Enable uniqe sort 260// Enable uniqe sort
261#define BB_FEATURE_SORT_UNIQUE 261#define CONFIG_FEATURE_SORT_UNIQUE
262// 262//
263// Enable command line editing in the shell. 263// Enable command line editing in the shell.
264// Only relevant if a shell is enabled. On by default. 264// Only relevant if a shell is enabled. On by default.
265#define BB_FEATURE_COMMAND_EDITING 265#define CONFIG_FEATURE_COMMAND_EDITING
266// 266//
267// Enable tab completion in the shell. This is now working quite nicely. 267// Enable tab completion in the shell. This is now working quite nicely.
268// This feature adds a bit over 4k. Only relevant if a shell is enabled. 268// This feature adds a bit over 4k. Only relevant if a shell is enabled.
269#define BB_FEATURE_COMMAND_TAB_COMPLETION 269#define CONFIG_FEATURE_COMMAND_TAB_COMPLETION
270// 270//
271// Attempts to match usernames in a ~-prefixed path 271// Attempts to match usernames in a ~-prefixed path
272//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION 272//#define CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
273// 273//
274//Allow the shell to invoke all the compiled in BusyBox applets as if they 274//Allow the shell to invoke all the compiled in BusyBox applets as if they
275//were shell builtins. Nice for staticly linking an emergency rescue shell, 275//were shell builtins. Nice for staticly linking an emergency rescue shell,
276//among other things. Off by default. 276//among other things. Off by default.
277// Only relevant if a shell is enabled. 277// Only relevant if a shell is enabled.
278//#define BB_FEATURE_SH_STANDALONE_SHELL 278//#define CONFIG_FEATURE_SH_STANDALONE_SHELL
279// 279//
280//When this is enabled, busybox shell applets can be called using full path 280//When this is enabled, busybox shell applets can be called using full path
281//names. This causes applets (i.e., most busybox commands) to override 281//names. This causes applets (i.e., most busybox commands) to override
282//real commands on the filesystem. For example, if you run run /bin/cat, it 282//real commands on the filesystem. For example, if you run run /bin/cat, it
283//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ 283//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
284//busybox. Some systems want this, others do not. Choose wisely. :-) This 284//busybox. Some systems want this, others do not. Choose wisely. :-) This
285//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. 285//only has meaning when CONFIG_FEATURE_SH_STANDALONE_SHELL is enabled.
286// Only relevant if a shell is enabled. Off by default. 286// Only relevant if a shell is enabled. Off by default.
287//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN 287//#define CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
288// 288//
289// Uncomment this option for a fancy shell prompt that includes the 289// Uncomment this option for a fancy shell prompt that includes the
290// current username and hostname. On systems that don't have usernames 290// current username and hostname. On systems that don't have usernames
291// or hostnames, this can look hideous. 291// or hostnames, this can look hideous.
292// Only relevant if a shell is enabled. 292// Only relevant if a shell is enabled.
293//#define BB_FEATURE_SH_FANCY_PROMPT 293//#define CONFIG_FEATURE_SH_FANCY_PROMPT
294// 294//
295//Turn on extra fbset options 295//Turn on extra fbset options
296//#define BB_FEATURE_FBSET_FANCY 296//#define CONFIG_FEATURE_FBSET_FANCY
297// 297//
298//Turn on fbset readmode support 298//Turn on fbset readmode support
299//#define BB_FEATURE_FBSET_READMODE 299//#define CONFIG_FEATURE_FBSET_READMODE
300// 300//
301// Support insmod/lsmod/rmmod for post 2.1 kernels 301// Support insmod/lsmod/rmmod for post 2.1 kernels
302//#define BB_FEATURE_NEW_MODULE_INTERFACE 302//#define CONFIG_FEATURE_NEW_MODULE_INTERFACE
303// 303//
304// Support insmod/lsmod/rmmod for pre 2.1 kernels 304// Support insmod/lsmod/rmmod for pre 2.1 kernels
305//#define BB_FEATURE_OLD_MODULE_INTERFACE 305//#define CONFIG_FEATURE_OLD_MODULE_INTERFACE
306// 306//
307// Support module version checking 307// Support module version checking
308//#define BB_FEATURE_INSMOD_VERSION_CHECKING 308//#define CONFIG_FEATURE_INSMOD_VERSION_CHECKING
309// 309//
310// Support for uClinux memory usage optimization, which will load the image 310// Support for uClinux memory usage optimization, which will load the image
311// directly into the kernel memory. This divides memory requrements by three. 311// directly into the kernel memory. This divides memory requrements by three.
312// If you are not running uClinux (i.e., your CPU has an MMU) leave this 312// If you are not running uClinux (i.e., your CPU has an MMU) leave this
313// disabled... 313// disabled...
314//#define BB_FEATURE_INSMOD_LOADINKMEM 314//#define CONFIG_FEATURE_INSMOD_LOADINKMEM
315// 315//
316// Support for Minix filesystem, version 2 316// Support for Minix filesystem, version 2
317//#define BB_FEATURE_MINIX2 317//#define CONFIG_FEATURE_MINIX2
318// 318//
319// Enable ifconfig status reporting output -- this feature adds 12k. 319// Enable ifconfig status reporting output -- this feature adds 12k.
320#define BB_FEATURE_IFCONFIG_STATUS 320#define CONFIG_FEATURE_IFCONFIG_STATUS
321// 321//
322// Enable ifconfig slip-specific options "keepalive" and "outfill" 322// Enable ifconfig slip-specific options "keepalive" and "outfill"
323//#define BB_FEATURE_IFCONFIG_SLIP 323//#define CONFIG_FEATURE_IFCONFIG_SLIP
324// 324//
325// Enable ifconfig options "mem_start", "io_addr", and "irq". 325// Enable ifconfig options "mem_start", "io_addr", and "irq".
326//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 326//#define CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
327// 327//
328// Enable ifconfig option "hw". Currently works for only with "ether". 328// Enable ifconfig option "hw". Currently works for only with "ether".
329#define BB_FEATURE_IFCONFIG_HW 329#define CONFIG_FEATURE_IFCONFIG_HW
330// 330//
331// Enable busybox --install [-s] 331// Enable busybox --install [-s]
332// to create links (or symlinks) for all the commands that are 332// to create links (or symlinks) for all the commands that are
333// compiled into the binary. (needs /proc filesystem) 333// compiled into the binary. (needs /proc filesystem)
334#define BB_FEATURE_INSTALLER 334#define CONFIG_FEATURE_INSTALLER
335// 335//
336// Enable a nifty progress meter in wget (adds just under 2k) 336// Enable a nifty progress meter in wget (adds just under 2k)
337#define BB_FEATURE_WGET_STATUSBAR 337#define CONFIG_FEATURE_WGET_STATUSBAR
338// 338//
339// Enable HTTP authentication in wget 339// Enable HTTP authentication in wget
340#define BB_FEATURE_WGET_AUTHENTICATION 340#define CONFIG_FEATURE_WGET_AUTHENTICATION
341// 341//
342// Clean up all memory before exiting -- usually not needed 342// Clean up all memory before exiting -- usually not needed
343// as the OS can clean up... Don't enable this unless you 343// as the OS can clean up... Don't enable this unless you
344// have a really good reason for cleaning things up manually. 344// have a really good reason for cleaning things up manually.
345//#define BB_FEATURE_CLEAN_UP 345//#define CONFIG_FEATURE_CLEAN_UP
346// 346//
347// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) 347// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
348#define BB_FEATURE_HUMAN_READABLE 348#define CONFIG_FEATURE_HUMAN_READABLE
349// 349//
350// Support for the find -type option. 350// Support for the find -type option.
351#define BB_FEATURE_FIND_TYPE 351#define CONFIG_FEATURE_FIND_TYPE
352// 352//
353// Support for the find -perm option. 353// Support for the find -perm option.
354#define BB_FEATURE_FIND_PERM 354#define CONFIG_FEATURE_FIND_PERM
355// 355//
356// Support for the find -mtine option. 356// Support for the find -mtine option.
357#define BB_FEATURE_FIND_MTIME 357#define CONFIG_FEATURE_FIND_MTIME
358// 358//
359// Support for the -A -B and -C context flags in grep 359// Support for the -A -B and -C context flags in grep
360//#define BB_FEATURE_GREP_CONTEXT 360//#define CONFIG_FEATURE_GREP_CONTEXT
361// 361//
362// Support for the EGREP applet (alias to the grep applet) 362// Support for the EGREP applet (alias to the grep applet)
363//#define BB_FEATURE_GREP_EGREP_ALIAS 363//#define CONFIG_FEATURE_GREP_EGREP_ALIAS
364// 364//
365// Tell tftp what commands that should be supported. 365// Tell tftp what commands that should be supported.
366#define BB_FEATURE_TFTP_PUT 366#define CONFIG_FEATURE_TFTP_PUT
367#define BB_FEATURE_TFTP_GET 367#define CONFIG_FEATURE_TFTP_GET
368// 368//
369// features for vi 369// features for vi
370#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode 370#define CONFIG_FEATURE_VI_COLON // ":" colon commands, no "ex" mode
371#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds 371#define CONFIG_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds
372#define BB_FEATURE_VI_SEARCH // search and replace cmds 372#define CONFIG_FEATURE_VI_SEARCH // search and replace cmds
373#define BB_FEATURE_VI_USE_SIGNALS // catch signals 373#define CONFIG_FEATURE_VI_USE_SIGNALS // catch signals
374#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd 374#define CONFIG_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd
375#define BB_FEATURE_VI_READONLY // vi -R and "view" mode 375#define CONFIG_FEATURE_VI_READONLY // vi -R and "view" mode
376#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch 376#define CONFIG_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch
377#define BB_FEATURE_VI_SET // :set 377#define CONFIG_FEATURE_VI_SET // :set
378#define BB_FEATURE_VI_WIN_RESIZE // handle window resize 378#define CONFIG_FEATURE_VI_WIN_RESIZE // handle window resize
379// 379//
380// Enable a if you system have setuped locale 380// Enable a if you system have setuped locale
381//#define BB_LOCALE_SUPPORT 381//#define CONFIG_LOCALE_SUPPORT
382// 382//
383// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. 383// Support for TELNET to pass TERM type to remote host. Adds 384 bytes.
384#define BB_FEATURE_TELNET_TTYPE 384#define CONFIG_FEATURE_TELNET_TTYPE
385// 385//
386// End of Features List 386// End of Features List
387// 387//
@@ -396,74 +396,74 @@
396// 396//
397#include <features.h> 397#include <features.h>
398#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ 398#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__
399 #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ 399 #undef CONFIG_RPM2CPIO /* Uses gz_open(), which uses fork() */
400 #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ 400 #undef CONFIG_DPKG_DEB /* Uses gz_open(), which uses fork() */
401 #undef BB_ASH /* Uses fork() */ 401 #undef CONFIG_ASH /* Uses fork() */
402 #undef BB_HUSH /* Uses fork() */ 402 #undef CONFIG_HUSH /* Uses fork() */
403 #undef BB_LASH /* Uses fork() */ 403 #undef CONFIG_LASH /* Uses fork() */
404 #undef BB_INIT /* Uses fork() */ 404 #undef CONFIG_INIT /* Uses fork() */
405 #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ 405 #undef CONFIG_FEATURE_TAR_GZIP /* Uses fork() */
406 #undef BB_SYSLOGD /* Uses daemon() */ 406 #undef CONFIG_SYSLOGD /* Uses daemon() */
407 #undef BB_KLOGD /* Uses daemon() */ 407 #undef CONFIG_KLOGD /* Uses daemon() */
408 #undef BB_UPDATE /* Uses daemon() */ 408 #undef CONFIG_UPDATE /* Uses daemon() */
409#endif 409#endif
410#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH 410#if defined CONFIG_ASH || defined CONFIG_HUSH || defined CONFIG_LASH || defined CONFIG_MSH
411 #if defined BB_FEATURE_COMMAND_EDITING 411 #if defined CONFIG_FEATURE_COMMAND_EDITING
412 #define BB_CMDEDIT 412 #define CONFIG_CMDEDIT
413 #else 413 #else
414 #undef BB_FEATURE_COMMAND_EDITING 414 #undef CONFIG_FEATURE_COMMAND_EDITING
415 #undef BB_FEATURE_COMMAND_TAB_COMPLETION 415 #undef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
416 #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION 416 #undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
417 #undef BB_FEATURE_SH_FANCY_PROMPT 417 #undef CONFIG_FEATURE_SH_FANCY_PROMPT
418 #endif 418 #endif
419#else 419#else
420 #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 420 #undef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
421 #undef BB_FEATURE_SH_STANDALONE_SHELL 421 #undef CONFIG_FEATURE_SH_STANDALONE_SHELL
422 #undef BB_FEATURE_SH_FANCY_PROMPT 422 #undef CONFIG_FEATURE_SH_FANCY_PROMPT
423#endif 423#endif
424// 424//
425#ifdef BB_KILLALL 425#ifdef CONFIG_KILLALL
426 #ifndef BB_KILL 426 #ifndef CONFIG_KILL
427 #define BB_KILL 427 #define CONFIG_KILL
428 #endif 428 #endif
429#endif 429#endif
430// 430//
431#ifndef BB_INIT 431#ifndef CONFIG_INIT
432 #undef BB_FEATURE_LINUXRC 432 #undef CONFIG_FEATURE_INITRD
433#endif 433#endif
434// 434//
435#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT 435#if defined CONFIG_MOUNT && defined CONFIG_FEATURE_NFSMOUNT
436 #define BB_NFSMOUNT 436 #define CONFIG_NFSMOUNT
437#endif 437#endif
438// 438//
439#if defined BB_FEATURE_AUTOWIDTH 439#if defined CONFIG_FEATURE_AUTOWIDTH
440 #ifndef BB_FEATURE_USE_TERMIOS 440 #ifndef CONFIG_FEATURE_USE_TERMIOS
441 #define BB_FEATURE_USE_TERMIOS 441 #define CONFIG_FEATURE_USE_TERMIOS
442 #endif 442 #endif
443#endif 443#endif
444// 444//
445#if defined BB_INSMOD || defined BB_LSMOD 445#if defined CONFIG_INSMOD || defined CONFIG_LSMOD
446 #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE 446 #if ! defined CONFIG_FEATURE_NEW_MODULE_INTERFACE && ! defined CONFIG_FEATURE_OLD_MODULE_INTERFACE
447 #define BB_FEATURE_NEW_MODULE_INTERFACE 447 #define CONFIG_FEATURE_NEW_MODULE_INTERFACE
448 #endif 448 #endif
449#endif 449#endif
450// 450//
451#ifdef BB_UNIX2DOS 451#ifdef CONFIG_UNIX2DOS
452 #define BB_DOS2UNIX 452 #define CONFIG_DOS2UNIX
453#endif 453#endif
454// 454//
455#ifdef BB_SYSLOGD 455#ifdef CONFIG_SYSLOGD
456 #if defined BB_FEATURE_IPC_SYSLOG 456 #if defined CONFIG_FEATURE_IPC_SYSLOG
457 #define BB_LOGREAD 457 #define CONFIG_LOGREAD
458 #endif 458 #endif
459#endif 459#endif
460// 460//
461#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH 461#if defined CONFIG_ASH && defined CONFIG_FEATURE_SH_IS_ASH
462# define shell_main ash_main 462# define shell_main ash_main
463#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH 463#elif defined CONFIG_HUSH && defined CONFIG_FEATURE_SH_IS_HUSH
464# define shell_main hush_main 464# define shell_main hush_main
465#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH 465#elif defined CONFIG_LASH && defined CONFIG_FEATURE_SH_IS_LASH
466# define shell_main lash_main 466# define shell_main lash_main
467#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH 467#elif defined CONFIG_MSH && defined CONFIG_FEATURE_SH_IS_MSH
468# define shell_main msh_main 468# define shell_main msh_main
469#endif 469#endif
diff --git a/debian/rules b/debian/rules
index 1d7413c35..45a6c604c 100755
--- a/debian/rules
+++ b/debian/rules
@@ -28,8 +28,8 @@ debian/build-stamp-busybox:
28 mkdir -p $(bbbd) 28 mkdir -p $(bbbd)
29 cp Makefile $(bbbd) 29 cp Makefile $(bbbd)
30 cp debian/Config.h-deb $(bbbd)/Config.h 30 cp debian/Config.h-deb $(bbbd)/Config.h
31 -(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" applet_source_list) 31 -(cd $(bbbd); $(MAKE) "CONFIG_SRC_DIR=../../" applet_source_list)
32 (cd $(bbbd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../") 32 (cd $(bbbd); $(MAKE) USE_SYSTEM_PWD_GRP=false "CONFIG_SRC_DIR=../../")
33 touch debian/build-stamp-busybox 33 touch debian/build-stamp-busybox
34 34
35install: build 35install: build
@@ -39,7 +39,7 @@ install: build
39 dh_installdirs 39 dh_installdirs
40 # Do not run 'make install', since we do not want all the symlinks. 40 # Do not run 'make install', since we do not want all the symlinks.
41 # This just installes the busybox binary... 41 # This just installes the busybox binary...
42 #(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bb)" install) 42 #(cd $(bbbd); $(MAKE) "CONFIG_SRC_DIR=../../" "PREFIX=../../$(bb)" install)
43 mkdir -p $(bb)/bin/ 43 mkdir -p $(bb)/bin/
44 cp $(bbbd)/busybox $(bb)/bin/busybox 44 cp $(bbbd)/busybox $(bb)/bin/busybox
45 mkdir -p $(bb)/usr/share/doc/busybox/busybox.lineo.com 45 mkdir -p $(bb)/usr/share/doc/busybox/busybox.lineo.com
@@ -54,7 +54,7 @@ debian/build-stamp-busybox-static:
54 mkdir -p $(bbsbd) 54 mkdir -p $(bbsbd)
55 cp Makefile $(bbsbd) 55 cp Makefile $(bbsbd)
56 cp debian/Config.h-static $(bbsbd)/Config.h 56 cp debian/Config.h-static $(bbsbd)/Config.h
57 (cd $(bbsbd); $(MAKE) DOSTATIC=true USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../") 57 (cd $(bbsbd); $(MAKE) DOSTATIC=true USE_SYSTEM_PWD_GRP=false "CONFIG_SRC_DIR=../../")
58 touch debian/build-stamp-busybox-static 58 touch debian/build-stamp-busybox-static
59 59
60install-static: build 60install-static: build
@@ -64,7 +64,7 @@ install-static: build
64 dh_installdirs 64 dh_installdirs
65 # Do not run 'make install', since we do not want all the symlinks. 65 # Do not run 'make install', since we do not want all the symlinks.
66 # This just installes the busybox binary... 66 # This just installes the busybox binary...
67 #(cd $(bbsbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbs)" install) 67 #(cd $(bbsbd); $(MAKE) "CONFIG_SRC_DIR=../../" "PREFIX=../../$(bbs)" install)
68 mkdir -p $(bbs)/bin/ 68 mkdir -p $(bbs)/bin/
69 cp $(bbsbd)/busybox $(bbs)/bin/busybox 69 cp $(bbsbd)/busybox $(bbs)/bin/busybox
70 mkdir -p $(bbs)/usr/share/doc/busybox-static/busybox.lineo.com 70 mkdir -p $(bbs)/usr/share/doc/busybox-static/busybox.lineo.com
@@ -94,7 +94,7 @@ debian/build-stamp-busybox-udeb:
94 mkdir -p $(bbubd) 94 mkdir -p $(bbubd)
95 cp Makefile $(bbubd) 95 cp Makefile $(bbubd)
96 cp debian/Config.h-udeb $(bbubd)/Config.h 96 cp debian/Config.h-udeb $(bbubd)/Config.h
97 (cd $(bbubd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../") 97 (cd $(bbubd); $(MAKE) USE_SYSTEM_PWD_GRP=false "CONFIG_SRC_DIR=../../")
98 touch debian/build-stamp-busybox-udeb 98 touch debian/build-stamp-busybox-udeb
99 99
100install-udeb: build 100install-udeb: build
@@ -102,7 +102,7 @@ install-udeb: build
102 dh_testroot 102 dh_testroot
103 dh_clean -k 103 dh_clean -k
104 dh_installdirs 104 dh_installdirs
105 (cd $(bbubd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbu)" install) 105 (cd $(bbubd); $(MAKE) "CONFIG_SRC_DIR=../../" "PREFIX=../../$(bbu)" install)
106 mkdir -p $(bbu)/usr/share/man/man1/ 106 mkdir -p $(bbu)/usr/share/man/man1/
107 cp $(bbubd)/docs/BusyBox.1 $(bbu)/usr/share/man/man1/busybox.1 107 cp $(bbubd)/docs/BusyBox.1 $(bbu)/usr/share/man/man1/busybox.1
108 108
diff --git a/deluser.c b/deluser.c
deleted file mode 100644
index bb6e10996..000000000
--- a/deluser.c
+++ /dev/null
@@ -1,175 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * deluser (remove lusers from the system ;) for TinyLogin
4 *
5 *
6 * Copyright (C) 1999 by Lineo, inc.
7 * Written by John Beppu <beppu@lineo.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <sys/stat.h>
26#include <unistd.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include "busybox.h"
31
32#define PASSWD_FILE "/etc/passwd"
33#define GROUP_FILE "/etc/group"
34
35/* where to start and stop deletion */
36typedef struct {
37 size_t start;
38 size_t stop;
39} Bounds;
40
41/* An interesting side-effect of boundary()'s
42 * implementation is that the first user (typically root)
43 * cannot be removed. Let's call it a feature. */
44static Bounds boundary(const char *buffer, const char *login)
45{
46 char needle[256];
47 char *start;
48 char *stop;
49 Bounds b;
50
51 snprintf(needle, 256, "\n%s", login);
52 needle[255] = 0;
53 start = strstr(buffer, needle);
54 if (!start) {
55 b.start = 0;
56 b.stop = 0;
57 return b;
58 }
59 start++;
60
61 stop = index(start, '\n'); /* index is a BSD-ism */
62 b.start = start - buffer;
63 b.stop = stop - buffer;
64 return b;
65}
66
67/* grep -v ^login (except it only deletes the first match) */
68/* ...in fact, I think I'm going to simplify this later */
69static int del_line_matching(char *login, char *filename)
70{
71 char *buffer;
72 FILE *passwd;
73 size_t len;
74 Bounds b;
75 struct stat statbuf;
76
77 /* load into buffer */
78 passwd = fopen(filename, "r");
79 if (!passwd) {
80 return 1;
81 }
82 stat(filename, &statbuf);
83 len = statbuf.st_size;
84 buffer = (char *) malloc(len * sizeof(char));
85
86 if (!buffer) {
87 fclose(passwd);
88 return 1;
89 }
90 fread(buffer, len, sizeof(char), passwd);
91
92 fclose(passwd);
93
94 /* find the user to remove */
95 b = boundary(buffer, login);
96 if (b.stop == 0) {
97 free(buffer);
98 return 1;
99 }
100
101 /* write the file w/o the user */
102 passwd = fopen(filename, "w");
103 if (!passwd) {
104 return 1;
105 }
106 fwrite(buffer, (b.start - 1), sizeof(char), passwd);
107 fwrite(&buffer[b.stop], (len - b.stop), sizeof(char), passwd);
108
109 fclose(passwd);
110
111 return 0;
112}
113
114/* ________________________________________________________________________ */
115int delgroup_main(int argc, char **argv)
116{
117 /* int successful; */
118 int failure;
119
120 if (argc != 2) {
121 show_usage();
122 } else {
123
124 failure = del_line_matching(argv[1], GROUP_FILE);
125#ifdef TLG_FEATURE_SHADOWPASSWDS
126 if (access(GSHADOW_FILE, W_OK) == 0) {
127 /* EDR the |= works if the error is not 0, so he had it wrong */
128 failure |= del_line_matching(argv[1], GSHADOW_FILE);
129 }
130#endif /* TLG_FEATURE_SHADOWPASSWDS */
131 /* if (!successful) { */
132 if (failure) {
133 error_msg_and_die("%s: Group could not be removed\n", argv[1]);
134 }
135
136 }
137 return (EXIT_SUCCESS);
138}
139
140/* ________________________________________________________________________ */
141int deluser_main(int argc, char **argv)
142{
143 /* int successful; */
144 int failure;
145
146 if (argc != 2) {
147 show_usage();
148 } else {
149
150 failure = del_line_matching(argv[1], PASSWD_FILE);
151 /* if (!successful) { */
152 if (failure) {
153 error_msg_and_die("%s: User could not be removed from %s\n",
154 argv[1], PASSWD_FILE);
155 }
156#ifdef TLG_FEATURE_SHADOWPASSWDS
157 failure = del_line_matching(argv[1], SHADOW_FILE);
158 /* if (!successful) { */
159 if (failure) {
160 error_msg_and_die("%s: User could not be removed from %s\n",
161 argv[1], SHADOW_FILE);
162 }
163#endif /* TLG_FEATURE_SHADOWPASSWDS */
164 failure = del_line_matching(argv[1], GROUP_FILE);
165 /* if (!successful) { */
166 if (failure) {
167 error_msg_and_die("%s: User could not be removed from %s\n",
168 argv[1], GROUP_FILE);
169 }
170
171 }
172 return (EXIT_SUCCESS);
173}
174
175/* $Id: deluser.c,v 1.1 2001/08/21 16:18:59 andersen Exp $ */
diff --git a/df.c b/df.c
deleted file mode 100644
index 8cb13fa6d..000000000
--- a/df.c
+++ /dev/null
@@ -1,158 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini df implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 * based on original code by (I think) Bruce Perens <bruce@pixar.com>.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <mntent.h>
29#include <sys/vfs.h>
30#include <getopt.h>
31#include "busybox.h"
32
33extern const char mtab_file[]; /* Defined in utility.c */
34#ifdef BB_FEATURE_HUMAN_READABLE
35static unsigned long df_disp_hr = KILOBYTE;
36#endif
37
38static int do_df(char *device, const char *mount_point)
39{
40 struct statfs s;
41 long blocks_used;
42 long blocks_percent_used;
43
44 if (statfs(mount_point, &s) != 0) {
45 perror_msg("%s", mount_point);
46 return FALSE;
47 }
48
49 if (s.f_blocks > 0) {
50 blocks_used = s.f_blocks - s.f_bfree;
51 if(blocks_used == 0)
52 blocks_percent_used = 0;
53 else {
54 blocks_percent_used = (long)
55 (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5);
56 }
57 if (strcmp(device, "/dev/root") == 0) {
58 /* Adjusts device to be the real root device,
59 * or leaves device alone if it can't find it */
60 device = find_real_root_device_name(device);
61 if(device==NULL)
62 return FALSE;
63 }
64#ifdef BB_FEATURE_HUMAN_READABLE
65 printf("%-20s %9s ", device,
66 make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr));
67
68 printf("%9s ",
69 make_human_readable_str( (s.f_blocks - s.f_bfree), s.f_bsize, df_disp_hr));
70
71 printf("%9s %3ld%% %s\n",
72 make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr),
73 blocks_percent_used, mount_point);
74#else
75 printf("%-20s %9ld %9ld %9ld %3ld%% %s\n",
76 device,
77 (long) (s.f_blocks * (s.f_bsize / (double)KILOBYTE)),
78 (long) ((s.f_blocks - s.f_bfree)*(s.f_bsize/(double)KILOBYTE)),
79 (long) (s.f_bavail * (s.f_bsize / (double)KILOBYTE)),
80 blocks_percent_used, mount_point);
81#endif
82 }
83
84 return TRUE;
85}
86
87extern int df_main(int argc, char **argv)
88{
89 int status = EXIT_SUCCESS;
90 int opt = 0;
91 int i = 0;
92 char disp_units_hdr[80] = "1k-blocks"; /* default display is kilobytes */
93
94 while ((opt = getopt(argc, argv, "k"
95#ifdef BB_FEATURE_HUMAN_READABLE
96 "hm"
97#endif
98)) > 0)
99 {
100 switch (opt) {
101#ifdef BB_FEATURE_HUMAN_READABLE
102 case 'h':
103 df_disp_hr = 0;
104 strcpy(disp_units_hdr, " Size");
105 break;
106 case 'm':
107 df_disp_hr = MEGABYTE;
108 strcpy(disp_units_hdr, "1M-blocks");
109 break;
110#endif
111 case 'k':
112 /* default display is kilobytes */
113 break;
114 default:
115 show_usage();
116 }
117 }
118
119 printf("%-20s %-14s %s %s %s %s\n", "Filesystem", disp_units_hdr,
120 "Used", "Available", "Use%", "Mounted on");
121
122 if(optind < argc) {
123 struct mntent *mount_entry;
124 for(i = optind; i < argc; i++)
125 {
126 if ((mount_entry = find_mount_point(argv[i], mtab_file)) == 0) {
127 error_msg("%s: can't find mount point.", argv[i]);
128 status = EXIT_FAILURE;
129 } else if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir))
130 status = EXIT_FAILURE;
131 }
132 } else {
133 FILE *mount_table;
134 struct mntent *mount_entry;
135
136 mount_table = setmntent(mtab_file, "r");
137 if (mount_table == 0) {
138 perror_msg("%s", mtab_file);
139 return EXIT_FAILURE;
140 }
141
142 while ((mount_entry = getmntent(mount_table))) {
143 if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir))
144 status = EXIT_FAILURE;
145 }
146 endmntent(mount_table);
147 }
148
149 return status;
150}
151
152/*
153Local Variables:
154c-file-style: "linux"
155c-basic-offset: 4
156tab-width: 4
157End:
158*/
diff --git a/dirname.c b/dirname.c
deleted file mode 100644
index b534e6950..000000000
--- a/dirname.c
+++ /dev/null
@@ -1,40 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini dirname implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24/* getopt not needed */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include "busybox.h"
30
31extern int dirname_main(int argc, char **argv)
32{
33 if ((argc < 2) || (**(argv + 1) == '-'))
34 show_usage();
35 argv++;
36
37 puts (dirname (argv[0]));
38
39 return EXIT_SUCCESS;
40}
diff --git a/dmesg.c b/dmesg.c
deleted file mode 100644
index 73de6d1ae..000000000
--- a/dmesg.c
+++ /dev/null
@@ -1,95 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/* dmesg.c -- Print out the contents of the kernel ring buffer
3 * Created: Sat Oct 9 16:19:47 1993
4 * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
5 * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
6 * This program comes with ABSOLUTELY NO WARRANTY.
7 * Modifications by Rick Sladkey (jrs@world.std.com)
8 * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch
9 * by Peeter Joot. This was also suggested by John Hudson.
10 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
11 * - added Native Language Support
12 *
13 * from util-linux -- adapted for busybox by
14 * Erik Andersen <andersee@debian.org>. I ripped out Native Language
15 * Support, replaced getopt, added some gotos for redundant stuff.
16 */
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <getopt.h>
21
22#if __GNU_LIBRARY__ < 5
23# ifdef __alpha__
24# define klogctl syslog
25# endif
26#else
27# include <sys/klog.h>
28#endif
29
30#include "busybox.h"
31
32int dmesg_main(int argc, char **argv)
33{
34 char *buf;
35 int c;
36 int bufsize = 8196;
37 int i;
38 int n;
39 int level = 0;
40 int lastc;
41 int cmd = 3;
42
43 while ((c = getopt(argc, argv, "cn:s:")) != EOF) {
44 switch (c) {
45 case 'c':
46 cmd = 4;
47 break;
48 case 'n':
49 cmd = 8;
50 if (optarg == NULL)
51 show_usage();
52 level = atoi(optarg);
53 break;
54 case 's':
55 if (optarg == NULL)
56 show_usage();
57 bufsize = atoi(optarg);
58 break;
59 default:
60 show_usage();
61 }
62 }
63
64 if (optind < argc) {
65 show_usage();
66 }
67
68 if (cmd == 8) {
69 if (klogctl(cmd, NULL, level) < 0)
70 perror_msg_and_die("klogctl");
71 return EXIT_SUCCESS;
72 }
73
74 if (bufsize < 4096)
75 bufsize = 4096;
76 buf = (char *) xmalloc(bufsize);
77 if ((n = klogctl(cmd, buf, bufsize)) < 0)
78 perror_msg_and_die("klogctl");
79
80 lastc = '\n';
81 for (i = 0; i < n; i++) {
82 if (lastc == '\n' && buf[i] == '<') {
83 i++;
84 while (buf[i] >= '0' && buf[i] <= '9')
85 i++;
86 if (buf[i] == '>')
87 i++;
88 }
89 lastc = buf[i];
90 putchar(lastc);
91 }
92 if (lastc != '\n')
93 putchar('\n');
94 return EXIT_SUCCESS;
95}
diff --git a/docs/autodocifier.pl b/docs/autodocifier.pl
index d753300c1..3016e4022 100755
--- a/docs/autodocifier.pl
+++ b/docs/autodocifier.pl
@@ -251,7 +251,7 @@ a command. I<REQUIRED>
251=item B<full> 251=item B<full>
252 252
253This should contain descriptions of each option. This will also 253This should contain descriptions of each option. This will also
254be displayed along with the trivial help if BB_FEATURE_TRIVIAL_HELP 254be displayed along with the trivial help if CONFIG_FEATURE_TRIVIAL_HELP
255is disabled. I<REQUIRED> 255is disabled. I<REQUIRED>
256 256
257=item B<notes> 257=item B<notes>
@@ -284,4 +284,4 @@ John BEPPU <beppu@lineo.com>
284 284
285=cut 285=cut
286 286
287# $Id: autodocifier.pl,v 1.21 2001/04/17 17:09:34 beppu Exp $ 287# $Id: autodocifier.pl,v 1.22 2001/10/24 04:59:20 andersen Exp $
diff --git a/docs/busybox.net/index.html b/docs/busybox.net/index.html
index b396b4b16..a0b4e6ccf 100644
--- a/docs/busybox.net/index.html
+++ b/docs/busybox.net/index.html
@@ -295,7 +295,6 @@ listed in the order I happen to add them to the web page:
295 295
296<ul> 296<ul>
297 <li> <a href="http://cvs.debian.org/boot-floppies/">Debian installer (boot floppies) project</a> 297 <li> <a href="http://cvs.debian.org/boot-floppies/">Debian installer (boot floppies) project</a>
298 <li> <a href="ftp://ftp.slackware.com/pub/slackware/slackware-8.0/source/rootdsks/">Slackware 8.0 installer</a>
299 <li> <a href="http://www.linuxrouter.org/">Linux Router Project </a> 298 <li> <a href="http://www.linuxrouter.org/">Linux Router Project </a>
300 <li> <a href="http://linux-embedded.org/">LEM</a> 299 <li> <a href="http://linux-embedded.org/">LEM</a>
301 <li> <a href="http://www.toms.net/rb/">tomsrtbt</a> 300 <li> <a href="http://www.toms.net/rb/">tomsrtbt</a>
@@ -325,7 +324,7 @@ listed in the order I happen to add them to the web page:
325 <li> <a href="http://dutnux.sourceforge.net/">DutNux</a> 324 <li> <a href="http://dutnux.sourceforge.net/">DutNux</a>
326 <li> <a href="http://www.cachier.com/">Cachier</a> 325 <li> <a href="http://www.cachier.com/">Cachier</a>
327 <li> <a href="http://www.microwerks.net/~hugo/mindi/">Mindi</a> 326 <li> <a href="http://www.microwerks.net/~hugo/mindi/">Mindi</a>
328 <li> <a href="http://www.tzi.de/~pharao90/ttylinux/">ttylinux</a> 327
329</ul> 328</ul>
330 329
331<p> Do you use BusyBox? I'd love to know about it and I'd be happy to link to 330<p> Do you use BusyBox? I'd love to know about it and I'd be happy to link to
diff --git a/docs/busybox.net/oldnews.html b/docs/busybox.net/oldnews.html
index d97bb2684..08a49caf8 100644
--- a/docs/busybox.net/oldnews.html
+++ b/docs/busybox.net/oldnews.html
@@ -74,12 +74,12 @@
74 <li> <b>Busybox Boot-Floppy Image</b> 74 <li> <b>Busybox Boot-Floppy Image</b>
75 75
76 <p>Because you asked for it, we have made available a <a href= 76 <p>Because you asked for it, we have made available a <a href=
77 "ftp://opensource.lineo.com/busybox/busybox.floppy.img"> Busybox boot floppy 77 "ftp://oss.lineo.com/busybox/busybox.floppy.img"> Busybox boot floppy
78 image</a>. Here's how you use it: 78 image</a>. Here's how you use it:
79 79
80 <ol> 80 <ol>
81 81
82 <li> <a href= "ftp://opensource.lineo.com/busybox/busybox.floppy.img"> 82 <li> <a href= "ftp://oss.lineo.com/busybox/busybox.floppy.img">
83 Download the image</a> 83 Download the image</a>
84 84
85 <li> dd it onto a floppy like so: <tt> dd if=busybox.floppy.img 85 <li> dd it onto a floppy like so: <tt> dd if=busybox.floppy.img
@@ -203,13 +203,13 @@
203 details). 203 details).
204 <p> 204 <p>
205 Also, some exciting infrastructure news! Busybox now has its own 205 Also, some exciting infrastructure news! Busybox now has its own
206 <a href="http://opensource.lineo.com/lists/busybox/">mailing list</a>, 206 <a href="http://oss.lineo.com/lists/busybox/">mailing list</a>,
207 publically browsable 207 publically browsable
208 <a href="http://opensource.lineo.com/cgi-bin/cvsweb/busybox/">CVS tree</a>, 208 <a href="http://oss.lineo.com/cgi-bin/cvsweb/busybox/">CVS tree</a>,
209 anonymous 209 anonymous
210 <a href="http://opensource.lineo.com/cvs_anon.html">CVS access</a>, and 210 <a href="http://oss.lineo.com/cvs_anon.html">CVS access</a>, and
211 for those that are actively contributing there is even 211 for those that are actively contributing there is even
212 <a href="http://opensource.lineo.com/cvs_write.html">CVS write access</a>. 212 <a href="http://oss.lineo.com/cvs_write.html">CVS write access</a>.
213 I think this will be a huge help to the ongoing development of BusyBox. 213 I think this will be a huge help to the ongoing development of BusyBox.
214 <p> 214 <p>
215 Also, for the curious, there is no 0.44 release. Somehow 0.44 got announced 215 Also, for the curious, there is no 0.44 release. Somehow 0.44 got announced
@@ -398,13 +398,10 @@
398 Freshmeat AppIndex record for BusyBox</A> 398 Freshmeat AppIndex record for BusyBox</A>
399 <p> 399 <p>
400 400
401 <li> <a href="http://opensource.lineo.com/software.html">Other cool embedded software</a>. 401 <li> <a href="http://oss.lineo.com/software.html">Cool embedded software</a>.
402 <p> 402 <p>
403 403
404 <li> <a href="http://opensource.lineo.com/">opensource.lineo.com</a>. 404 <li> <a href="http://oss.lineo.com/">oss.lineo.com</a>.
405 <p>
406
407 <li> <A HREF="http://www.lineo.com/">Lineo</A> is sponsoring BusyBox development.
408 <p> 405 <p>
409 406
410</ul> 407</ul>
@@ -425,8 +422,8 @@
425 <TD> 422 <TD>
426 <font size="-1" face="arial, helvetica, sans-serif"> 423 <font size="-1" face="arial, helvetica, sans-serif">
427 Mail all comments, insults, suggestions and bribes to 424 Mail all comments, insults, suggestions and bribes to
428 <a href="mailto:andersen@lineo.com">Erik Andersen</a><BR> 425 <a href="mailto:andersen@codepoet.org">Erik Andersen</a><BR>
429 The Busybox logo is copyright 1999,2000, Erik Andersen. 426 The Busybox logo is copyright 1999,2000,2001 Erik Andersen.
430 </font> 427 </font>
431 </TD> 428 </TD>
432 429
diff --git a/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt
index 1f5c3ebd5..a00dfcc30 100644
--- a/docs/new-applet-HOWTO.txt
+++ b/docs/new-applet-HOWTO.txt
@@ -109,7 +109,7 @@ order, or else it will break the binary-search lookup algorithm in busybox.c
109and the Gods of BusyBox smite you. Yea, verily: 109and the Gods of BusyBox smite you. Yea, verily:
110 110
111 /* all programs above here are alphabetically "less than" 'mu' */ 111 /* all programs above here are alphabetically "less than" 'mu' */
112 #ifdef BB_MU 112 #ifdef CONFIG_MU
113 APPLET("mu", mu_main, _BB_DIR_USR_BIN, mu_usage) 113 APPLET("mu", mu_main, _BB_DIR_USR_BIN, mu_usage)
114 #endif 114 #endif
115 /* all programs below here are alphabetically "greater than" 'mu' */ 115 /* all programs below here are alphabetically "greater than" 'mu' */
@@ -117,7 +117,7 @@ and the Gods of BusyBox smite you. Yea, verily:
117 117
118Finally, add a define for your applet to Config.h: 118Finally, add a define for your applet to Config.h:
119 119
120 #define BB_MU 120 #define CONFIG_MU
121 121
122 122
123Documentation 123Documentation
diff --git a/docs/style-guide.txt b/docs/style-guide.txt
index c71f1e609..25c676ca2 100644
--- a/docs/style-guide.txt
+++ b/docs/style-guide.txt
@@ -252,7 +252,7 @@ files, you can do the following in the busybox directory:
252If you want to convert all the non-K&R vars in your file all at once, follow 252If you want to convert all the non-K&R vars in your file all at once, follow
253these steps: 253these steps:
254 254
255 - In the busybox directory type 'scripts/mk2knr.pl files-to-convert'. This 255 - In the busybox directory type 'examples/mk2knr.pl files-to-convert'. This
256 does not do the actual conversion, rather, it generates a script called 256 does not do the actual conversion, rather, it generates a script called
257 'convertme.pl' that shows what will be converted, giving you a chance to 257 'convertme.pl' that shows what will be converted, giving you a chance to
258 review the changes beforehand. 258 review the changes beforehand.
@@ -269,7 +269,7 @@ these steps:
269 269
270Please be aware of changes that have cascading effects into other files. For 270Please be aware of changes that have cascading effects into other files. For
271example, if you're changing the name of something in, say utility.c, you 271example, if you're changing the name of something in, say utility.c, you
272should probably run 'scripts/mk2knr.pl utility.c' at first, but when you run 272should probably run 'examples/mk2knr.pl utility.c' at first, but when you run
273the 'convertme.pl' script you should run it on _all_ files like so: 273the 'convertme.pl' script you should run it on _all_ files like so:
274'./convertme.pl *.[ch]'. 274'./convertme.pl *.[ch]'.
275 275
@@ -343,7 +343,7 @@ used in the code.
343 ret = my_func(bar, baz); 343 ret = my_func(bar, baz);
344 if (!ret) 344 if (!ret)
345 return -1; 345 return -1;
346 #ifdef BB_FEATURE_FUNKY 346 #ifdef CONFIG_FEATURE_FUNKY
347 maybe_do_funky_stuff(bar, baz); 347 maybe_do_funky_stuff(bar, baz);
348 #endif 348 #endif
349 349
@@ -351,7 +351,7 @@ used in the code.
351 351
352 (in .h header file) 352 (in .h header file)
353 353
354 #ifdef BB_FEATURE_FUNKY 354 #ifdef CONFIG_FEATURE_FUNKY
355 static inline void maybe_do_funky_stuff (int bar, int baz) 355 static inline void maybe_do_funky_stuff (int bar, int baz)
356 { 356 {
357 /* lotsa code in here */ 357 /* lotsa code in here */
@@ -487,7 +487,7 @@ very limited stack space (e.g., uCLinux).
487A macro is declared in busybox.h that implements compile-time selection 487A macro is declared in busybox.h that implements compile-time selection
488between xmalloc() and stack creation, so you can code the line in question as 488between xmalloc() and stack creation, so you can code the line in question as
489 489
490 RESERVE_BB_BUFFER(buffer, BUFSIZ); 490 RESERVE_CONFIG_BUFFER(buffer, BUFSIZ);
491 491
492and the right thing will happen, based on your configuration. 492and the right thing will happen, based on your configuration.
493 493
diff --git a/dos2unix.c b/dos2unix.c
deleted file mode 100644
index 8b65d05de..000000000
--- a/dos2unix.c
+++ /dev/null
@@ -1,194 +0,0 @@
1/*
2 * dos2unix for BusyBox
3 *
4 * dos2unix '\n' convertor 0.5.0
5 * based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
6 * Copyright 1997,.. by Peter Hanecak <hanecak@megaloman.sk>.
7 * All rights reserved.
8 *
9 * dos2unix filters reading input from stdin and writing output to stdout.
10 * Without arguments it reverts the format (e.i. if source is in UNIX format,
11 * output is in DOS format and vice versa).
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 *
27 * See the COPYING file for license information.
28 */
29
30#include <string.h>
31#include <getopt.h>
32#include <unistd.h>
33#include <stdint.h>
34#include <fcntl.h>
35#include <sys/time.h>
36#include "busybox.h"
37
38/* We are making a lame pseudo-random string generator here. in
39 * convert(), each pass through the while loop will add more and more
40 * stuff into value, which is _supposed_ to wrap. We don't care about
41 * it being accurate. We care about it being messy, since we then mod
42 * it by the sizeof(letters) and then use that as an index into letters
43 * to pick a random letter to add to out temporary file. */
44typedef unsigned long int bb_uint64_t;
45
46static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
47
48// if fn is NULL then input is stdin and output is stdout
49static int convert(char *fn, int ConvType)
50{
51 int c, fd;
52 struct timeval tv;
53 char tempFn[BUFSIZ];
54 static bb_uint64_t value=0;
55 FILE *in = stdin, *out = stdout;
56
57 if (fn != NULL) {
58 if ((in = wfopen(fn, "rw")) == NULL) {
59 return -1;
60 }
61 strcpy(tempFn, fn);
62 c = strlen(tempFn);
63 tempFn[c] = '.';
64 while(1) {
65 if (c >=BUFSIZ)
66 error_msg_and_die("unique name not found");
67 /* Get some semi random stuff to try and make a
68 * random filename based (and in the same dir as)
69 * the input file... */
70 gettimeofday (&tv, NULL);
71 value += ((bb_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
72 tempFn[++c] = letters[value % 62];
73 tempFn[c+1] = '\0';
74 value /= 62;
75
76 if ((fd = open(tempFn, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0 ) {
77 continue;
78 }
79 out = fdopen(fd, "w+");
80 if (!out) {
81 close(fd);
82 remove(tempFn);
83 continue;
84 }
85 break;
86 }
87 }
88
89 while ((c = fgetc(in)) != EOF) {
90 if (c == '\r') {
91 if ((ConvType == CT_UNIX2DOS) && (fn != NULL)) {
92 // file is alredy in DOS format so it is not necessery to touch it
93 remove(tempFn);
94 if (fclose(in) < 0 || fclose(out) < 0) {
95 perror_msg(NULL);
96 return -2;
97 }
98 return 0;
99 }
100 if (!ConvType)
101 ConvType = CT_DOS2UNIX;
102 break;
103 }
104 if (c == '\n') {
105 if ((ConvType == CT_DOS2UNIX) && (fn != NULL)) {
106 // file is alredy in UNIX format so it is not necessery to touch it
107 remove(tempFn);
108 if ((fclose(in) < 0) || (fclose(out) < 0)) {
109 perror_msg(NULL);
110 return -2;
111 }
112 return 0;
113 }
114 if (!ConvType) {
115 ConvType = CT_UNIX2DOS;
116 }
117 if (ConvType == CT_UNIX2DOS) {
118 fputc('\r', out);
119 }
120 fputc('\n', out);
121 break;
122 }
123 fputc(c, out);
124 }
125 if (c != EOF)
126 while ((c = fgetc(in)) != EOF) {
127 if (c == '\r')
128 continue;
129 if (c == '\n') {
130 if (ConvType == CT_UNIX2DOS)
131 fputc('\r', out);
132 fputc('\n', out);
133 continue;
134 }
135 fputc(c, out);
136 }
137
138 if (fn != NULL) {
139 if (fclose(in) < 0 || fclose(out) < 0) {
140 perror_msg(NULL);
141 remove(tempFn);
142 return -2;
143 }
144
145 /* Assume they are both on the same filesystem (which
146 * should be true since we put them into the same directory
147 * so we _should_ be ok, but you never know... */
148 if (rename(tempFn, fn) < 0) {
149 perror_msg("unable to rename '%s' as '%s'", tempFn, fn);
150 return -1;
151 }
152 }
153
154 return 0;
155}
156
157int dos2unix_main(int argc, char *argv[])
158{
159 int ConvType = CT_AUTO;
160 int o;
161
162 //See if we are supposed to be doing dos2unix or unix2dos
163 if (argv[0][0]=='d') {
164 ConvType = CT_DOS2UNIX;
165 }
166 if (argv[0][0]=='u') {
167 ConvType = CT_UNIX2DOS;
168 }
169
170 // process parameters
171 while ((o = getopt(argc, argv, "du")) != EOF) {
172 switch (o) {
173 case 'd':
174 ConvType = CT_UNIX2DOS;
175 break;
176 case 'u':
177 ConvType = CT_DOS2UNIX;
178 break;
179 default:
180 show_usage();
181 }
182 }
183
184 if (optind < argc) {
185 while(optind < argc)
186 if ((o = convert(argv[optind++], ConvType)) < 0)
187 break;
188 }
189 else
190 o = convert(NULL, ConvType);
191
192 return o;
193}
194
diff --git a/dpkg.c b/dpkg.c
deleted file mode 100644
index bf0dcf3c3..000000000
--- a/dpkg.c
+++ /dev/null
@@ -1,1509 +0,0 @@
1/*
2 * Mini dpkg implementation for busybox.
3 * This is not meant as a replacemnt for dpkg
4 *
5 * Written By Glenn McGrath with the help of others
6 * Copyright (C) 2001 by Glenn McGrath
7 *
8 * Started life as a busybox implementation of udpkg
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25/*
26 * Known difference between busybox dpkg and the official dpkg that i dont
27 * consider important, its worth keeping a note of differences anyway, just to
28 * make it easier to maintain.
29 * - The first value for the Confflile: field isnt placed on a new line.
30 * - The <package>.control file is extracted and kept in the info dir.
31 * - When installing a package the Status: field is placed at the end of the
32 * section, rather than just after the Package: field.
33 * - Packages with previously unknown status are inserted at the begining of
34 * the status file
35 *
36 * Bugs that need to be fixed
37 * - (unknown, please let me know when you find any)
38 *
39 */
40
41#include <getopt.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45#include "busybox.h"
46
47/* NOTE: If you vary HASH_PRIME sizes be aware,
48 * 1) Tweaking these will have a big effect on how much memory this program uses.
49 * 2) For computational efficiency these hash tables should be at least 20%
50 * larger than the maximum number of elements stored in it.
51 * 3) All _HASH_PRIME's must be a prime number or chaos is assured, if your looking
52 * for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt
53 * 4) If you go bigger than 15 bits you may get into trouble (untested) as its
54 * sometimes cast to an unsigned int, if you go to 16 bit you will overlap
55 * int's and chaos is assured, 16381 is the max prime for 14 bit field
56 */
57
58/* NAME_HASH_PRIME, Stores package names and versions,
59 * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME,
60 * as there a lot of duplicate version numbers */
61#define NAME_HASH_PRIME 16381
62char *name_hashtable[NAME_HASH_PRIME + 1];
63
64/* PACKAGE_HASH_PRIME, Maximum number of unique packages,
65 * It must not be smaller than STATUS_HASH_PRIME,
66 * Currently only packages from status_hashtable are stored in here, but in
67 * future this may be used to store packages not only from a status file,
68 * but an available_hashtable, and even multiple packages files.
69 * Package can be stored more than once if they have different versions.
70 * e.g. The same package may have different versions in the status file
71 * and available file */
72#define PACKAGE_HASH_PRIME 10007
73typedef struct edge_s {
74 unsigned int operator:3;
75 unsigned int type:4;
76 unsigned int name:14;
77 unsigned int version:14;
78} edge_t;
79
80typedef struct common_node_s {
81 unsigned int name:14;
82 unsigned int version:14;
83 unsigned int num_of_edges:14;
84 edge_t **edge;
85} common_node_t;
86common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1];
87
88/* Currently it doesnt store packages that have state-status of not-installed
89 * So it only really has to be the size of the maximum number of packages
90 * likely to be installed at any one time, so there is a bit of leaway here */
91#define STATUS_HASH_PRIME 8191
92typedef struct status_node_s {
93 unsigned int package:14; /* has to fit PACKAGE_HASH_PRIME */
94 unsigned int status:14; /* has to fit STATUS_HASH_PRIME */
95} status_node_t;
96status_node_t *status_hashtable[STATUS_HASH_PRIME + 1];
97
98/* Even numbers are for 'extras', like ored dependecies or null */
99enum edge_type_e {
100 EDGE_NULL = 0,
101 EDGE_PRE_DEPENDS = 1,
102 EDGE_OR_PRE_DEPENDS = 2,
103 EDGE_DEPENDS = 3,
104 EDGE_OR_DEPENDS = 4,
105 EDGE_REPLACES = 5,
106 EDGE_PROVIDES = 7,
107 EDGE_CONFLICTS = 9,
108 EDGE_SUGGESTS = 11,
109 EDGE_RECOMMENDS = 13,
110 EDGE_ENHANCES = 15
111};
112enum operator_e {
113 VER_NULL = 0,
114 VER_EQUAL = 1,
115 VER_LESS = 2,
116 VER_LESS_EQUAL = 3,
117 VER_MORE = 4,
118 VER_MORE_EQUAL = 5,
119 VER_ANY = 6
120};
121
122enum dpkg_opt_e {
123 dpkg_opt_purge = 1,
124 dpkg_opt_remove = 2,
125 dpkg_opt_unpack = 4,
126 dpkg_opt_configure = 8,
127 dpkg_opt_install = 16,
128 dpkg_opt_package_name = 32,
129 dpkg_opt_filename = 64,
130 dpkg_opt_list_installed = 128,
131 dpkg_opt_force_ignore_depends = 256
132};
133
134typedef struct deb_file_s {
135 char *control_file;
136 char *filename;
137 unsigned int package:14;
138} deb_file_t;
139
140
141void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime)
142{
143 unsigned long int hash_num = key[0];
144 int len = strlen(key);
145 int i;
146
147 /* Maybe i should have uses a "proper" hashing algorithm here instead
148 * of making one up myself, seems to be working ok though. */
149 for(i = 1; i < len; i++) {
150 /* shifts the ascii based value and adds it to previous value
151 * shift amount is mod 24 because long int is 32 bit and data
152 * to be shifted is 8, dont want to shift data to where it has
153 * no effect*/
154 hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24));
155 }
156 *start = (unsigned int) hash_num % hash_prime;
157 *decrement = (unsigned int) 1 + (hash_num % (hash_prime - 1));
158}
159
160/* this adds the key to the hash table */
161int search_name_hashtable(const char *key)
162{
163 unsigned int probe_address = 0;
164 unsigned int probe_decrement = 0;
165// char *temp;
166
167 make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME);
168 while(name_hashtable[probe_address] != NULL) {
169 if (strcmp(name_hashtable[probe_address], key) == 0) {
170 return(probe_address);
171 } else {
172 probe_address -= probe_decrement;
173 if ((int)probe_address < 0) {
174 probe_address += NAME_HASH_PRIME;
175 }
176 }
177 }
178 name_hashtable[probe_address] = xstrdup(key);
179 return(probe_address);
180}
181
182/* this DOESNT add the key to the hashtable
183 * TODO make it consistent with search_name_hashtable
184 */
185unsigned int search_status_hashtable(const char *key)
186{
187 unsigned int probe_address = 0;
188 unsigned int probe_decrement = 0;
189
190 make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME);
191 while(status_hashtable[probe_address] != NULL) {
192 if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) {
193 break;
194 } else {
195 probe_address -= probe_decrement;
196 if ((int)probe_address < 0) {
197 probe_address += STATUS_HASH_PRIME;
198 }
199 }
200 }
201 return(probe_address);
202}
203
204/* Need to rethink version comparison, maybe the official dpkg has something i can use ? */
205int version_compare_part(const char *version1, const char *version2)
206{
207 int upstream_len1 = 0;
208 int upstream_len2 = 0;
209 char *name1_char;
210 char *name2_char;
211 int len1 = 0;
212 int len2 = 0;
213 int tmp_int;
214 int ver_num1;
215 int ver_num2;
216 int ret;
217
218 if (version1 == NULL) {
219 version1 = xstrdup("");
220 }
221 if (version2 == NULL) {
222 version2 = xstrdup("");
223 }
224 upstream_len1 = strlen(version1);
225 upstream_len2 = strlen(version2);
226
227 while ((len1 < upstream_len1) || (len2 < upstream_len2)) {
228 /* Compare non-digit section */
229 tmp_int = strcspn(&version1[len1], "0123456789");
230 name1_char = xstrndup(&version1[len1], tmp_int);
231 len1 += tmp_int;
232 tmp_int = strcspn(&version2[len2], "0123456789");
233 name2_char = xstrndup(&version2[len2], tmp_int);
234 len2 += tmp_int;
235 tmp_int = strcmp(name1_char, name2_char);
236 free(name1_char);
237 free(name2_char);
238 if (tmp_int != 0) {
239 ret = tmp_int;
240 goto cleanup_version_compare_part;
241 }
242
243 /* Compare digits */
244 tmp_int = strspn(&version1[len1], "0123456789");
245 name1_char = xstrndup(&version1[len1], tmp_int);
246 len1 += tmp_int;
247 tmp_int = strspn(&version2[len2], "0123456789");
248 name2_char = xstrndup(&version2[len2], tmp_int);
249 len2 += tmp_int;
250 ver_num1 = atoi(name1_char);
251 ver_num2 = atoi(name2_char);
252 free(name1_char);
253 free(name2_char);
254 if (ver_num1 < ver_num2) {
255 ret = -1;
256 goto cleanup_version_compare_part;
257 }
258 else if (ver_num1 > ver_num2) {
259 ret = 1;
260 goto cleanup_version_compare_part;
261 }
262 }
263 ret = 0;
264cleanup_version_compare_part:
265 return(ret);
266}
267
268/* if ver1 < ver2 return -1,
269 * if ver1 = ver2 return 0,
270 * if ver1 > ver2 return 1,
271 */
272int version_compare(const unsigned int ver1, const unsigned int ver2)
273{
274 char *ch_ver1 = name_hashtable[ver1];
275 char *ch_ver2 = name_hashtable[ver2];
276
277 char epoch1, epoch2;
278 char *deb_ver1, *deb_ver2;
279 char *ver1_ptr, *ver2_ptr;
280 char *upstream_ver1;
281 char *upstream_ver2;
282 int result;
283
284 /* Compare epoch */
285 if (ch_ver1[1] == ':') {
286 epoch1 = ch_ver1[0];
287 ver1_ptr = strchr(ch_ver1, ':') + 1;
288 } else {
289 epoch1 = '0';
290 ver1_ptr = ch_ver1;
291 }
292 if (ch_ver2[1] == ':') {
293 epoch2 = ch_ver2[0];
294 ver2_ptr = strchr(ch_ver2, ':') + 1;
295 } else {
296 epoch2 = '0';
297 ver2_ptr = ch_ver2;
298 }
299 if (epoch1 < epoch2) {
300 return(-1);
301 }
302 else if (epoch1 > epoch2) {
303 return(1);
304 }
305
306 /* Compare upstream version */
307 upstream_ver1 = xstrdup(ver1_ptr);
308 upstream_ver2 = xstrdup(ver2_ptr);
309
310 /* Chop off debian version, and store for later use */
311 deb_ver1 = strrchr(upstream_ver1, '-');
312 deb_ver2 = strrchr(upstream_ver2, '-');
313 if (deb_ver1) {
314 deb_ver1[0] = '\0';
315 deb_ver1++;
316 }
317 if (deb_ver2) {
318 deb_ver2[0] = '\0';
319 deb_ver2++;
320 }
321 result = version_compare_part(upstream_ver1, upstream_ver2);
322
323 free(upstream_ver1);
324 free(upstream_ver2);
325
326 if (result != 0) {
327 return(result);
328 }
329
330 /* Compare debian versions */
331 return(version_compare_part(deb_ver1, deb_ver2));
332}
333
334int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator)
335{
336 const int version_result = version_compare(version1, version2);
337 switch(operator) {
338 case (VER_ANY):
339 return(TRUE);
340 case (VER_EQUAL):
341 if (version_result == 0) {
342 return(TRUE);
343 }
344 break;
345 case (VER_LESS):
346 if (version_result < 0) {
347 return(TRUE);
348 }
349 break;
350 case (VER_LESS_EQUAL):
351 if (version_result <= 0) {
352 return(TRUE);
353 }
354 break;
355 case (VER_MORE):
356 if (version_result > 0) {
357 return(TRUE);
358 }
359 break;
360 case (VER_MORE_EQUAL):
361 if (version_result >= 0) {
362 return(TRUE);
363 }
364 break;
365 }
366 return(FALSE);
367}
368
369
370int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator)
371{
372 unsigned int probe_address = 0;
373 unsigned int probe_decrement = 0;
374
375 make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME);
376 while(package_hashtable[probe_address] != NULL) {
377 if (package_hashtable[probe_address]->name == name) {
378 if (operator == VER_ANY) {
379 return(probe_address);
380 }
381 if (test_version(package_hashtable[probe_address]->version, version, operator)) {
382 return(probe_address);
383 }
384 }
385 probe_address -= probe_decrement;
386 if ((int)probe_address < 0) {
387 probe_address += PACKAGE_HASH_PRIME;
388 }
389 }
390 return(probe_address);
391}
392
393/*
394 * Create one new node and one new edge for every dependency.
395 */
396void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type)
397{
398 char *line = xstrdup(whole_line);
399 char *line2;
400 char *line_ptr1 = NULL;
401 char *line_ptr2 = NULL;
402 char *field;
403 char *field2;
404 char *version;
405 edge_t *edge;
406 int offset_ch;
407 int type;
408
409 field = strtok_r(line, ",", &line_ptr1);
410 do {
411 line2 = xstrdup(field);
412 field2 = strtok_r(line2, "|", &line_ptr2);
413 if ((edge_type == EDGE_DEPENDS) && (strcmp(field, field2) != 0)) {
414 type = EDGE_OR_DEPENDS;
415 }
416 else if ((edge_type == EDGE_PRE_DEPENDS) && (strcmp(field, field2) != 0)) {
417 type = EDGE_OR_PRE_DEPENDS;
418 } else {
419 type = edge_type;
420 }
421
422 do {
423 edge = (edge_t *) xmalloc(sizeof(edge_t));
424 edge->type = type;
425
426 /* Skip any extra leading spaces */
427 field2 += strspn(field2, " ");
428
429 /* Get dependency version info */
430 version = strchr(field2, '(');
431 if (version == NULL) {
432 edge->operator = VER_ANY;
433 /* Get the versions hash number, adding it if the number isnt already in there */
434 edge->version = search_name_hashtable("ANY");
435 } else {
436 /* Skip leading ' ' or '(' */
437 version += strspn(field2, " ");
438 version += strspn(version, "(");
439 /* Calculate length of any operator charactors */
440 offset_ch = strspn(version, "<=>");
441 /* Determine operator */
442 if (offset_ch > 0) {
443 if (strncmp(version, "=", offset_ch) == 0) {
444 edge->operator = VER_EQUAL;
445 }
446 else if (strncmp(version, "<<", offset_ch) == 0) {
447 edge->operator = VER_LESS;
448 }
449 else if (strncmp(version, "<=", offset_ch) == 0) {
450 edge->operator = VER_LESS_EQUAL;
451 }
452 else if (strncmp(version, ">>", offset_ch) == 0) {
453 edge->operator = VER_MORE;
454 }
455 else if (strncmp(version, ">=", offset_ch) == 0) {
456 edge->operator = VER_MORE_EQUAL;
457 } else {
458 error_msg_and_die("Illegal operator\n");
459 }
460 }
461 /* skip to start of version numbers */
462 version += offset_ch;
463 version += strspn(version, " ");
464
465 /* Truncate version at trailing ' ' or ')' */
466 version[strcspn(version, " )")] = '\0';
467 /* Get the versions hash number, adding it if the number isnt already in there */
468 edge->version = search_name_hashtable(version);
469 }
470
471 /* Get the dependency name */
472 field2[strcspn(field2, " (")] = '\0';
473 edge->name = search_name_hashtable(field2);
474
475 /* link the new edge to the current node */
476 parent_node->num_of_edges++;
477 parent_node->edge = xrealloc(parent_node->edge, sizeof(edge_t) * (parent_node->num_of_edges + 1));
478 parent_node->edge[parent_node->num_of_edges - 1] = edge;
479 } while ((field2 = strtok_r(NULL, "|", &line_ptr2)) != NULL);
480 free(line2);
481 } while ((field = strtok_r(NULL, ",", &line_ptr1)) != NULL);
482 free(line);
483
484 return;
485}
486
487void free_package(common_node_t *node)
488{
489 int i;
490 if (node != NULL) {
491 for (i = 0; i < node->num_of_edges; i++) {
492 if (node->edge[i] != NULL) {
493 free(node->edge[i]);
494 }
495 }
496 if (node->edge != NULL) {
497 free(node->edge);
498 }
499 if (node != NULL) {
500 free(node);
501 }
502 }
503}
504
505unsigned int fill_package_struct(char *control_buffer)
506{
507 common_node_t *new_node = (common_node_t *) xcalloc(1, sizeof(common_node_t));
508
509 char *field_name;
510 char *field_value;
511 int field_start = 0;
512 int num = -1;
513 int buffer_length = strlen(control_buffer);
514
515 new_node->version = search_name_hashtable("unknown");
516 while (field_start < buffer_length) {
517 field_start += read_package_field(&control_buffer[field_start],
518 &field_name, &field_value);
519
520 if (field_name == NULL) {
521 goto fill_package_struct_cleanup; // Oh no, the dreaded goto statement !!
522 }
523
524 if (strcmp(field_name, "Package") == 0) {
525 new_node->name = search_name_hashtable(field_value);
526 }
527 else if (strcmp(field_name, "Version") == 0) {
528 new_node->version = search_name_hashtable(field_value);
529 }
530 else if (strcmp(field_name, "Pre-Depends") == 0) {
531 add_split_dependencies(new_node, field_value, EDGE_PRE_DEPENDS);
532 }
533 else if (strcmp(field_name, "Depends") == 0) {
534 add_split_dependencies(new_node, field_value, EDGE_DEPENDS);
535 }
536 else if (strcmp(field_name, "Replaces") == 0) {
537 add_split_dependencies(new_node, field_value, EDGE_REPLACES);
538 }
539 else if (strcmp(field_name, "Provides") == 0) {
540 add_split_dependencies(new_node, field_value, EDGE_PROVIDES);
541 }
542 else if (strcmp(field_name, "Conflicts") == 0) {
543 add_split_dependencies(new_node, field_value, EDGE_CONFLICTS);
544 }
545 else if (strcmp(field_name, "Suggests") == 0) {
546 add_split_dependencies(new_node, field_value, EDGE_SUGGESTS);
547 }
548 else if (strcmp(field_name, "Recommends") == 0) {
549 add_split_dependencies(new_node, field_value, EDGE_RECOMMENDS);
550 }
551 else if (strcmp(field_name, "Enhances") == 0) {
552 add_split_dependencies(new_node, field_value, EDGE_ENHANCES);
553 }
554fill_package_struct_cleanup:
555 if (field_name) {
556 free(field_name);
557 }
558 if (field_value) {
559 free(field_value);
560 }
561 }
562
563 if (new_node->version == search_name_hashtable("unknown")) {
564 free_package(new_node);
565 return(-1);
566 }
567 num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL);
568 if (package_hashtable[num] == NULL) {
569 package_hashtable[num] = new_node;
570 } else {
571 free_package(new_node);
572 }
573 return(num);
574}
575
576/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */
577unsigned int get_status(const unsigned int status_node, const int num)
578{
579 char *status_string = name_hashtable[status_hashtable[status_node]->status];
580 char *state_sub_string;
581 unsigned int state_sub_num;
582 int len;
583 int i;
584
585 /* set tmp_string to point to the start of the word number */
586 for (i = 1; i < num; i++) {
587 /* skip past a word */
588 status_string += strcspn(status_string, " ");
589 /* skip past the seperating spaces */
590 status_string += strspn(status_string, " ");
591 }
592 len = strcspn(status_string, " \n\0");
593 state_sub_string = xstrndup(status_string, len);
594 state_sub_num = search_name_hashtable(state_sub_string);
595 free(state_sub_string);
596 return(state_sub_num);
597}
598
599void set_status(const unsigned int status_node_num, const char *new_value, const int position)
600{
601 const unsigned int new_value_len = strlen(new_value);
602 const unsigned int new_value_num = search_name_hashtable(new_value);
603 unsigned int want = get_status(status_node_num, 1);
604 unsigned int flag = get_status(status_node_num, 2);
605 unsigned int status = get_status(status_node_num, 3);
606 int want_len = strlen(name_hashtable[want]);
607 int flag_len = strlen(name_hashtable[flag]);
608 int status_len = strlen(name_hashtable[status]);
609 char *new_status;
610
611 switch (position) {
612 case (1):
613 want = new_value_num;
614 want_len = new_value_len;
615 break;
616 case (2):
617 flag = new_value_num;
618 flag_len = new_value_len;
619 break;
620 case (3):
621 status = new_value_num;
622 status_len = new_value_len;
623 break;
624 default:
625 error_msg_and_die("DEBUG ONLY: this shouldnt happen");
626 }
627
628 new_status = (char *) xmalloc(want_len + flag_len + status_len + 3);
629 sprintf(new_status, "%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]);
630 status_hashtable[status_node_num]->status = search_name_hashtable(new_status);
631 free(new_status);
632 return;
633}
634
635void index_status_file(const char *filename)
636{
637 FILE *status_file;
638 char *control_buffer;
639 char *status_line;
640 status_node_t *status_node = NULL;
641 unsigned int status_num;
642
643 status_file = xfopen(filename, "r");
644 while ((control_buffer = fgets_str(status_file, "\n\n")) != NULL) {
645 const unsigned int package_num = fill_package_struct(control_buffer);
646 if (package_num != -1) {
647 status_node = xmalloc(sizeof(status_node_t));
648 /* fill_package_struct doesnt handle the status field */
649 status_line = strstr(control_buffer, "Status:");
650 if (status_line != NULL) {
651 status_line += 7;
652 status_line += strspn(status_line, " \n\t");
653 status_line = xstrndup(status_line, strcspn(status_line, "\n\0"));
654 status_node->status = search_name_hashtable(status_line);
655 free(status_line);
656 }
657 status_node->package = package_num;
658 status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]);
659 status_hashtable[status_num] = status_node;
660 }
661 free(control_buffer);
662 }
663 fclose(status_file);
664 return;
665}
666
667
668char *get_depends_field(common_node_t *package, const int depends_type)
669{
670 char *depends = NULL;
671 char *old_sep = (char *)xcalloc(1, 3);
672 char *new_sep = (char *)xcalloc(1, 3);
673 int line_size = 0;
674 int depends_size;
675
676 int i;
677
678 for (i = 0; i < package->num_of_edges; i++) {
679 if ((package->edge[i]->type == EDGE_OR_PRE_DEPENDS) ||
680 (package->edge[i]->type == EDGE_OR_DEPENDS)) {
681 }
682
683 if ((package->edge[i]->type == depends_type) ||
684 (package->edge[i]->type == depends_type + 1)) {
685 /* Check if its the first time through */
686
687 depends_size = 8 + strlen(name_hashtable[package->edge[i]->name])
688 + strlen(name_hashtable[package->edge[i]->version]);
689 line_size += depends_size;
690 depends = (char *) xrealloc(depends, line_size + 1);
691
692 /* Check to see if this dependency is the type we are looking for
693 * +1 to check for 'extra' types, e.g. ored dependecies */
694 strcpy(old_sep, new_sep);
695 if (package->edge[i]->type == depends_type) {
696 strcpy(new_sep, ", ");
697 }
698 else if (package->edge[i]->type == depends_type + 1) {
699 strcpy(new_sep, "| ");
700 }
701
702 if (depends_size == line_size) {
703 strcpy(depends, "");
704 } else {
705 if ((strcmp(old_sep, "| ") == 0) && (strcmp(new_sep, "| ") == 0)) {
706 strcat(depends, " | ");
707 } else {
708 strcat(depends, ", ");
709 }
710 }
711
712 strcat(depends, name_hashtable[package->edge[i]->name]);
713 if (strcmp(name_hashtable[package->edge[i]->version], "NULL") != 0) {
714 if (package->edge[i]->operator == VER_EQUAL) {
715 strcat(depends, " (= ");
716 }
717 else if (package->edge[i]->operator == VER_LESS) {
718 strcat(depends, " (<< ");
719 }
720 else if (package->edge[i]->operator == VER_LESS_EQUAL) {
721 strcat(depends, " (<= ");
722 }
723 else if (package->edge[i]->operator == VER_MORE) {
724 strcat(depends, " (>> ");
725 }
726 else if (package->edge[i]->operator == VER_MORE_EQUAL) {
727 strcat(depends, " (>= ");
728 } else {
729 strcat(depends, " (");
730 }
731 strcat(depends, name_hashtable[package->edge[i]->version]);
732 strcat(depends, ")");
733 }
734 }
735 }
736 return(depends);
737}
738
739void write_buffer_no_status(FILE *new_status_file, const char *control_buffer)
740{
741 char *name;
742 char *value;
743 int start = 0;
744 while (1) {
745 start += read_package_field(&control_buffer[start], &name, &value);
746 if (name == NULL) {
747 break;
748 }
749 if (strcmp(name, "Status") != 0) {
750 fprintf(new_status_file, "%s: %s\n", name, value);
751 }
752 }
753 return;
754}
755
756/* This could do with a cleanup */
757void write_status_file(deb_file_t **deb_file)
758{
759 FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r");
760 FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w");
761 char *package_name;
762 char *status_from_file;
763 char *control_buffer = NULL;
764 char *tmp_string;
765 int status_num;
766 int field_start = 0;
767 int write_flag;
768 int i = 0;
769
770 /* Update previously known packages */
771 while ((control_buffer = fgets_str(old_status_file, "\n\n")) != NULL) {
772 if ((tmp_string = strstr(control_buffer, "Package:")) == NULL) {
773 continue;
774 }
775
776 tmp_string += 8;
777 tmp_string += strspn(tmp_string, " \n\t");
778 package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n\0"));
779 write_flag = FALSE;
780 tmp_string = strstr(control_buffer, "Status:");
781 if (tmp_string != NULL) {
782 /* Seperate the status value from the control buffer */
783 tmp_string += 7;
784 tmp_string += strspn(tmp_string, " \n\t");
785 status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n"));
786 } else {
787 status_from_file = NULL;
788 }
789
790 /* Find this package in the status hashtable */
791 status_num = search_status_hashtable(package_name);
792 if (status_hashtable[status_num] != NULL) {
793 const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status];
794 if (strcmp(status_from_file, status_from_hashtable) != 0) {
795 /* New status isnt exactly the same as old status */
796 const int state_status = get_status(status_num, 3);
797 if ((strcmp("installed", name_hashtable[state_status]) == 0) ||
798 (strcmp("unpacked", name_hashtable[state_status]) == 0)) {
799 /* We need to add the control file from the package */
800 i = 0;
801 while(deb_file[i] != NULL) {
802 if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) {
803 /* Write a status file entry with a modified status */
804 /* remove trailing \n's */
805 write_buffer_no_status(new_status_file, deb_file[i]->control_file);
806 set_status(status_num, "ok", 2);
807 fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
808 write_flag = TRUE;
809 break;
810 }
811 i++;
812 }
813 /* This is temperary, debugging only */
814 if (deb_file[i] == NULL) {
815 error_msg_and_die("ALERT: Couldnt find a control file, your status file may be broken, status may be incorrect for %s", package_name);
816 }
817 }
818 else if (strcmp("not-installed", name_hashtable[state_status]) == 0) {
819 /* Only write the Package, Status, Priority and Section lines */
820 fprintf(new_status_file, "Package: %s\n", package_name);
821 fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
822
823 while (1) {
824 char *field_name;
825 char *field_value;
826 field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
827 if (field_name == NULL) {
828 break;
829 }
830 if ((strcmp(field_name, "Priority") == 0) ||
831 (strcmp(field_name, "Section") == 0)) {
832 fprintf(new_status_file, "%s: %s\n", field_name, field_value);
833 }
834 }
835 write_flag = TRUE;
836 fputs("\n", new_status_file);
837 }
838 else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
839 /* only change the status line */
840 while (1) {
841 char *field_name;
842 char *field_value;
843 field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
844 if (field_name == NULL) {
845 break;
846 }
847 /* Setup start point for next field */
848 if (strcmp(field_name, "Status") == 0) {
849 fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
850 } else {
851 fprintf(new_status_file, "%s: %s\n", field_name, field_value);
852 }
853 }
854 write_flag = TRUE;
855 fputs("\n", new_status_file);
856 }
857 }
858 }
859 /* If the package from the status file wasnt handle above, do it now*/
860 if (write_flag == FALSE) {
861 fprintf(new_status_file, "%s\n\n", control_buffer);
862 }
863
864 if (status_from_file != NULL) {
865 free(status_from_file);
866 }
867 free(package_name);
868 free(control_buffer);
869 }
870
871 /* Write any new packages */
872 for(i = 0; deb_file[i] != NULL; i++) {
873 status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]);
874 if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) {
875 write_buffer_no_status(new_status_file, deb_file[i]->control_file);
876 set_status(status_num, "ok", 2);
877 fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
878 }
879 }
880 fclose(old_status_file);
881 fclose(new_status_file);
882
883
884 /* Create a seperate backfile to dpkg */
885 if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) {
886 struct stat stat_buf;
887 if (stat("/var/lib/dpkg/status", &stat_buf) == 0) {
888 error_msg_and_die("Couldnt create backup status file");
889 }
890 /* Its ok if renaming the status file fails becasue status
891 * file doesnt exist, maybe we are starting from scratch */
892 error_msg("No status file found, creating new one");
893 }
894
895 if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) {
896 error_msg_and_die("DANGER: Couldnt create status file, you need to manually repair your status file");
897 }
898}
899
900int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count)
901{
902 int *conflicts = NULL;
903 int conflicts_num = 0;
904 int state_status;
905 int state_flag;
906 int state_want;
907 unsigned int status_package_num;
908 int i = deb_start;
909 int j, k;
910
911 /* Check for conflicts
912 * TODO: TEST if conflicts with other packages to be installed
913 *
914 * Add install packages and the packages they provide
915 * to the list of files to check conflicts for
916 */
917
918 /* Create array of package numbers to check against
919 * installed package for conflicts*/
920 while (deb_file[i] != NULL) {
921 const unsigned int package_num = deb_file[i]->package;
922 conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
923 conflicts[conflicts_num] = package_num;
924 conflicts_num++;
925 /* add provides to conflicts list */
926 for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
927 if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) {
928 const int conflicts_package_num = search_package_hashtable(
929 package_hashtable[package_num]->edge[j]->name,
930 package_hashtable[package_num]->edge[j]->version,
931 package_hashtable[package_num]->edge[j]->operator);
932 if (package_hashtable[conflicts_package_num] == NULL) {
933 /* create a new package */
934 common_node_t *new_node = (common_node_t *) xmalloc(sizeof(common_node_t));
935 new_node->name = package_hashtable[package_num]->edge[j]->name;
936 new_node->version = package_hashtable[package_num]->edge[j]->version;
937 new_node->num_of_edges = 0;
938 new_node->edge = NULL;
939 package_hashtable[conflicts_package_num] = new_node;
940 }
941 conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
942 conflicts[conflicts_num] = conflicts_package_num;
943 conflicts_num++;
944 }
945 }
946 i++;
947 }
948
949 /* Check conflicts */
950 for (i = 0; i < conflicts_num; i++) {
951 /* Check for conflicts */
952 for (j = 0; j < STATUS_HASH_PRIME; j++) {
953 if (status_hashtable[j] == NULL) {
954 continue;
955 }
956 state_flag = get_status(j, 2);
957 state_status = get_status(j, 3);
958 if ((state_status != search_name_hashtable("installed"))
959 && (state_flag != search_name_hashtable("want-install"))) {
960 continue;
961 }
962 status_package_num = status_hashtable[j]->package;
963 for (k = 0; k < package_hashtable[status_package_num]->num_of_edges; k++) {
964 const edge_t *package_edge = package_hashtable[status_package_num]->edge[k];
965 if (package_edge->type != EDGE_CONFLICTS) {
966 continue;
967 }
968 if (package_edge->name != package_hashtable[conflicts[i]]->name) {
969 continue;
970 }
971 /* There is a conflict against the package name
972 * check if version conflict as well */
973 if (test_version(package_hashtable[deb_file[i]->package]->version,
974 package_edge->version, package_edge->operator)) {
975 error_msg_and_die("Package %s conflict with %s",
976 name_hashtable[package_hashtable[deb_file[i]->package]->name],
977 name_hashtable[package_hashtable[status_package_num]->name]);
978 }
979 }
980 }
981 }
982
983 /* Check dependendcies */
984 i = 0;
985 while (deb_file[i] != NULL) {
986 const common_node_t *package_node = package_hashtable[deb_file[i]->package];
987 int status_num = 0;
988
989 for (j = 0; j < package_hashtable[deb_file[i]->package]->num_of_edges; j++) {
990 const edge_t *package_edge = package_node->edge[j];
991 const unsigned int package_num = search_package_hashtable(package_edge->name,
992 package_edge->version, package_edge->operator);
993
994 status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]);
995 state_status = get_status(status_num, 3);
996 state_want = get_status(status_num, 1);
997 switch (package_edge->type) {
998 case(EDGE_PRE_DEPENDS):
999 case(EDGE_OR_PRE_DEPENDS):
1000 /* It must be already installed */
1001 /* NOTE: This is untested, nothing apropriate in my status file */
1002 if ((package_hashtable[package_num] == NULL) || (state_status != search_name_hashtable("installed"))) {
1003 error_msg_and_die("Package %s pre-depends on %s, but it is not installed",
1004 name_hashtable[package_node->name],
1005 name_hashtable[package_edge->name]);
1006 }
1007 break;
1008 case(EDGE_DEPENDS):
1009 case(EDGE_OR_DEPENDS):
1010 /* It must be already installed, or to be installed */
1011 if ((package_hashtable[package_num] == NULL) ||
1012 ((state_status != search_name_hashtable("installed")) &&
1013 (state_want != search_name_hashtable("want_install")))) {
1014 error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed",
1015 name_hashtable[package_node->name],
1016 name_hashtable[package_edge->name]);
1017 }
1018 break;
1019 }
1020 }
1021 i++;
1022 }
1023 free(conflicts);
1024 return(TRUE);
1025}
1026
1027char **create_list(const char *filename)
1028{
1029 FILE *list_stream;
1030 char **file_list = xmalloc(sizeof(char *));
1031 char *line = NULL;
1032 char *last_char;
1033 int length = 0;
1034 int count = 0;
1035
1036 /* dont use [xw]fopen here, handle error ourself */
1037 list_stream = fopen(filename, "r");
1038 if (list_stream == NULL) {
1039 *file_list = NULL;
1040 return(file_list);
1041 }
1042 while (getline(&line, &length, list_stream) != -1) {
1043 file_list = xrealloc(file_list, sizeof(char *) * (length + 1));
1044 last_char = last_char_is(line, '\n');
1045 if (last_char) {
1046 *last_char = '\0';
1047 }
1048 file_list[count] = xstrdup(line);
1049 count++;
1050 }
1051 fclose(list_stream);
1052 free(line);
1053
1054 if (count == 0) {
1055 return(NULL);
1056 } else {
1057 file_list[count] = NULL;
1058 return(file_list);
1059 }
1060}
1061
1062/* maybe i should try and hook this into remove_file.c somehow */
1063int remove_file_array(char **remove_names, char **exclude_names)
1064{
1065 struct stat path_stat;
1066 int match_flag;
1067 int remove_flag = FALSE;
1068 int i,j;
1069
1070 if (remove_names == NULL) {
1071 return(FALSE);
1072 }
1073 for (i = 0; remove_names[i] != NULL; i++) {
1074 match_flag = FALSE;
1075 if (exclude_names != NULL) {
1076 for (j = 0; exclude_names[j] != 0; j++) {
1077 if (strcmp(remove_names[i], exclude_names[j]) == 0) {
1078 match_flag = TRUE;
1079 break;
1080 }
1081 }
1082 }
1083 if (!match_flag) {
1084 if (lstat(remove_names[i], &path_stat) < 0) {
1085 continue;
1086 }
1087 if (S_ISDIR(path_stat.st_mode)) {
1088 if (rmdir(remove_names[i]) != -1) {
1089 remove_flag = TRUE;
1090 }
1091 } else {
1092 if (unlink(remove_names[i]) != -1) {
1093 remove_flag = TRUE;
1094 }
1095 }
1096 }
1097 }
1098 return(remove_flag);
1099}
1100
1101int run_package_script(const char *package_name, const char *script_type)
1102{
1103 struct stat path_stat;
1104 char *script_path;
1105 int result;
1106
1107 script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21);
1108 sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type);
1109
1110 /* If the file doesnt exist is isnt a fatal */
1111 if (lstat(script_path, &path_stat) < 0) {
1112 result = EXIT_SUCCESS;
1113 } else {
1114 result = system(script_path);
1115 }
1116 free(script_path);
1117 return(result);
1118}
1119
1120void all_control_list(char **remove_files, const char *package_name)
1121{
1122 const char *all_extensions[11] = {"preinst", "postinst", "prerm", "postrm",
1123 "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL };
1124 int i;
1125
1126 /* Create a list of all /var/lib/dpkg/info/<package> files */
1127 for(i = 0; i < 10; i++) {
1128 remove_files[i] = xmalloc(strlen(package_name) + strlen(all_extensions[i]) + 21);
1129 sprintf(remove_files[i], "/var/lib/dpkg/info/%s.%s", package_name, all_extensions[i]);
1130 }
1131 remove_files[10] = NULL;
1132}
1133
1134
1135/* This function lists information on the installed packages. It loops through
1136 * the status_hashtable to retrieve the info. This results in smaller code than
1137 * scanning the status file. The resulting list, however, is unsorted.
1138 */
1139void list_packages(void)
1140{
1141 int i;
1142
1143 printf(" Name Version\n");
1144 printf("+++-==============-==============\n");
1145
1146 /* go through status hash, dereference package hash and finally strings */
1147 for (i=0; i<STATUS_HASH_PRIME+1; i++) {
1148
1149 if (status_hashtable[i]) {
1150 const char *stat_str; /* status string */
1151 const char *name_str; /* package name */
1152 const char *vers_str; /* version */
1153 char s1, s2; /* status abbreviations */
1154 int spccnt; /* space count */
1155 int j;
1156
1157 stat_str = name_hashtable[status_hashtable[i]->status];
1158 name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name];
1159 vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version];
1160
1161 /* get abbreviation for status field 1 */
1162 s1 = stat_str[0] == 'i' ? 'i' : 'r';
1163
1164 /* get abbreviation for status field 2 */
1165 for (j=0, spccnt=0; stat_str[j] && spccnt<2; j++) {
1166 if (stat_str[j] == ' ') spccnt++;
1167 }
1168 s2 = stat_str[j];
1169
1170 /* print out the line formatted like Debian dpkg */
1171 printf("%c%c %-14s %s\n", s1, s2, name_str, vers_str);
1172 }
1173 }
1174}
1175
1176void remove_package(const unsigned int package_num)
1177{
1178 const char *package_name = name_hashtable[package_hashtable[package_num]->name];
1179 const unsigned int status_num = search_status_hashtable(package_name);
1180 const int package_name_length = strlen(package_name);
1181 char **remove_files;
1182 char **exclude_files;
1183 char list_name[package_name_length + 25];
1184 char conffile_name[package_name_length + 30];
1185 int return_value;
1186
1187 printf("Removing %s ...\n", package_name);
1188
1189 /* run prerm script */
1190 return_value = run_package_script(package_name, "prerm");
1191 if (return_value == -1) {
1192 error_msg_and_die("script failed, prerm failure");
1193 }
1194
1195 /* Create a list of files to remove, and a seperate list of those to keep */
1196 sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
1197 remove_files = create_list(list_name);
1198
1199 sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name);
1200 exclude_files = create_list(conffile_name);
1201
1202 /* Some directories cant be removed straight away, so do multiple passes */
1203 while (remove_file_array(remove_files, exclude_files) == TRUE);
1204
1205 /* Create a list of all /var/lib/dpkg/info/<package> files */
1206 remove_files = xmalloc(11);
1207 all_control_list(remove_files, package_name);
1208
1209 /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */
1210 exclude_files = xmalloc(sizeof(char*) * 3);
1211 exclude_files[0] = xstrdup(conffile_name);
1212 exclude_files[1] = xmalloc(package_name_length + 27);
1213 sprintf(exclude_files[1], "/var/lib/dpkg/info/%s.postrm", package_name);
1214 exclude_files[2] = NULL;
1215
1216 remove_file_array(remove_files, exclude_files);
1217
1218 /* rename <package>.conffile to <package>.list */
1219 rename(conffile_name, list_name);
1220
1221 /* Change package status */
1222 set_status(status_num, "deinstall", 1);
1223 set_status(status_num, "config-files", 3);
1224}
1225
1226void purge_package(const unsigned int package_num)
1227{
1228 const char *package_name = name_hashtable[package_hashtable[package_num]->name];
1229 const unsigned int status_num = search_status_hashtable(package_name);
1230 char **remove_files;
1231 char **exclude_files;
1232 char list_name[strlen(package_name) + 25];
1233
1234 /* run prerm script */
1235 if (run_package_script(package_name, "prerm") != 0) {
1236 error_msg_and_die("script failed, prerm failure");
1237 }
1238
1239 /* Create a list of files to remove */
1240 sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
1241 remove_files = create_list(list_name);
1242
1243 exclude_files = xmalloc(1);
1244 exclude_files[0] = NULL;
1245
1246 /* Some directories cant be removed straight away, so do multiple passes */
1247 while (remove_file_array(remove_files, exclude_files) == TRUE);
1248
1249 /* Create a list of all /var/lib/dpkg/info/<package> files */
1250 remove_files = xmalloc(11);
1251 all_control_list(remove_files, package_name);
1252 remove_file_array(remove_files, exclude_files);
1253
1254 /* run postrm script */
1255 if (run_package_script(package_name, "postrm") == -1) {
1256 error_msg_and_die("postrm fialure.. set status to what?");
1257 }
1258
1259 /* Change package status */
1260 set_status(status_num, "purge", 1);
1261 set_status(status_num, "not-installed", 3);
1262}
1263
1264void unpack_package(deb_file_t *deb_file)
1265{
1266 const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
1267 const unsigned int status_num = search_status_hashtable(package_name);
1268 const unsigned int status_package_num = status_hashtable[status_num]->package;
1269
1270 FILE *out_stream;
1271 char *info_prefix;
1272
1273 /* If existing version, remove it first */
1274 if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) {
1275 /* Package is already installed, remove old version first */
1276 printf("Preparing to replace %s %s (using %s) ...\n", package_name,
1277 name_hashtable[package_hashtable[status_package_num]->version],
1278 deb_file->filename);
1279 remove_package(status_package_num);
1280 } else {
1281 printf("Unpacking %s (from %s) ...\n", package_name, deb_file->filename);
1282 }
1283
1284 /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */
1285 info_prefix = (char *) xmalloc(sizeof(package_name) + 20 + 4 + 1);
1286 sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name);
1287 deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs | extract_unconditional), info_prefix, NULL);
1288
1289 /* Run the preinst prior to extracting */
1290 if (run_package_script(package_name, "preinst") != 0) {
1291 /* when preinst returns exit code != 0 then quit installation process */
1292 error_msg_and_die("subprocess pre-installation script returned error.");
1293 }
1294
1295 /* Extract data.tar.gz to the root directory */
1296 deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs | extract_unconditional), "/", NULL);
1297
1298 /* Create the list file */
1299 strcat(info_prefix, "list");
1300 out_stream = xfopen(info_prefix, "w");
1301 deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), "/", NULL);
1302 fclose(out_stream);
1303
1304 /* change status */
1305 set_status(status_num, "install", 1);
1306 set_status(status_num, "unpacked", 3);
1307
1308 free(info_prefix);
1309}
1310
1311void configure_package(deb_file_t *deb_file)
1312{
1313 const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
1314 const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version];
1315 const int status_num = search_status_hashtable(package_name);
1316
1317 printf("Setting up %s (%s)\n", package_name, package_version);
1318
1319 /* Run the postinst script */
1320 if (run_package_script(package_name, "postinst") != 0) {
1321 /* TODO: handle failure gracefully */
1322 error_msg_and_die("postrm failure.. set status to what?");
1323 }
1324 /* Change status to reflect success */
1325 set_status(status_num, "install", 1);
1326 set_status(status_num, "installed", 3);
1327}
1328
1329extern int dpkg_main(int argc, char **argv)
1330{
1331 deb_file_t **deb_file = NULL;
1332 status_node_t *status_node;
1333 char opt = 0;
1334 int package_num;
1335 int dpkg_opt = 0;
1336 int deb_count = 0;
1337 int state_status;
1338 int status_num;
1339 int i;
1340
1341 while ((opt = getopt(argc, argv, "CF:ilPru")) != -1) {
1342 switch (opt) {
1343 case 'C': // equivalent to --configure in official dpkg
1344 dpkg_opt |= dpkg_opt_configure;
1345 dpkg_opt |= dpkg_opt_package_name;
1346 break;
1347 case 'F': // equivalent to --force in official dpkg
1348 if (strcmp(optarg, "depends") == 0) {
1349 dpkg_opt |= dpkg_opt_force_ignore_depends;
1350 }
1351 case 'i':
1352 dpkg_opt |= dpkg_opt_install;
1353 dpkg_opt |= dpkg_opt_filename;
1354 break;
1355 case 'l':
1356 dpkg_opt |= dpkg_opt_list_installed;
1357 break;
1358 case 'P':
1359 dpkg_opt |= dpkg_opt_purge;
1360 dpkg_opt |= dpkg_opt_package_name;
1361 break;
1362 case 'r':
1363 dpkg_opt |= dpkg_opt_remove;
1364 dpkg_opt |= dpkg_opt_package_name;
1365 break;
1366 case 'u': /* Equivalent to --unpack in official dpkg */
1367 dpkg_opt |= dpkg_opt_unpack;
1368 dpkg_opt |= dpkg_opt_filename;
1369 break;
1370 default:
1371 show_usage();
1372 }
1373 }
1374 /* check for non-otion argument if expected */
1375 if ((dpkg_opt == 0) || ((argc == optind) && !(dpkg_opt && dpkg_opt_list_installed))) {
1376 show_usage();
1377 }
1378
1379/* puts("(Reading database ... xxxxx files and directories installed.)"); */
1380 index_status_file("/var/lib/dpkg/status");
1381
1382 /* if the list action was given print the installed packages and exit */
1383 if (dpkg_opt & dpkg_opt_list_installed) {
1384 list_packages();
1385 return(EXIT_SUCCESS);
1386 }
1387
1388 /* Read arguments and store relevant info in structs */
1389 deb_file = xmalloc(sizeof(deb_file_t));
1390 while (optind < argc) {
1391 deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t));
1392 if (dpkg_opt & dpkg_opt_filename) {
1393 deb_file[deb_count]->filename = xstrdup(argv[optind]);
1394 deb_file[deb_count]->control_file = deb_extract(argv[optind], stdout, (extract_control_tar_gz | extract_one_to_buffer), NULL, "./control");
1395 if (deb_file[deb_count]->control_file == NULL) {
1396 error_msg_and_die("Couldnt extract control file");
1397 }
1398 package_num = fill_package_struct(deb_file[deb_count]->control_file);
1399
1400 if (package_num == -1) {
1401 error_msg("Invalid control file in %s", argv[optind]);
1402 continue;
1403 }
1404 deb_file[deb_count]->package = (unsigned int) package_num;
1405 /* Add the package to the status hashtable */
1406 if ((dpkg_opt & dpkg_opt_unpack) || (dpkg_opt & dpkg_opt_install)) {
1407 status_node = (status_node_t *) xmalloc(sizeof(status_node_t));
1408 status_node->package = deb_file[deb_count]->package;
1409
1410 /* Try and find a currently installed version of this package */
1411 status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
1412 /* If no previous entry was found initialise a new entry */
1413 if ((status_hashtable[status_num] == NULL) ||
1414 (status_hashtable[status_num]->status == 0)) {
1415 /* reinstreq isnt changed to "ok" until the package control info
1416 * is written to the status file*/
1417 status_node->status = search_name_hashtable("install reinstreq not-installed");
1418 status_hashtable[status_num] = status_node;
1419 } else {
1420 status_hashtable[status_num]->status = search_name_hashtable("install reinstreq installed");
1421 }
1422 }
1423 }
1424 else if (dpkg_opt & dpkg_opt_package_name) {
1425 deb_file[deb_count]->filename = NULL;
1426 deb_file[deb_count]->control_file = NULL;
1427 deb_file[deb_count]->package = search_package_hashtable(
1428 search_name_hashtable(argv[optind]),
1429 search_name_hashtable("ANY"), VER_ANY);
1430 if (package_hashtable[deb_file[deb_count]->package] == NULL) {
1431 error_msg_and_die("Package %s is uninstalled or unknown\n", argv[optind]);
1432 }
1433 state_status = get_status(search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]), 3);
1434
1435 /* check package status is "installed" */
1436 if (dpkg_opt & dpkg_opt_remove) {
1437 if ((strcmp(name_hashtable[state_status], "not-installed") == 0) ||
1438 (strcmp(name_hashtable[state_status], "config-files") == 0)) {
1439 error_msg_and_die("%s is already removed.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
1440 }
1441 }
1442 else if (dpkg_opt & dpkg_opt_purge) {
1443 /* if package status is "conf-files" then its ok */
1444 if (strcmp(name_hashtable[state_status], "not-installed") == 0) {
1445 error_msg_and_die("%s is already purged.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
1446 }
1447 }
1448 }
1449 deb_count++;
1450 optind++;
1451 }
1452 deb_file[deb_count] = NULL;
1453
1454 /* Check that the deb file arguments are installable */
1455 /* TODO: check dependencies before removing */
1456 if ((dpkg_opt & dpkg_opt_force_ignore_depends) != dpkg_opt_force_ignore_depends) {
1457 if (!check_deps(deb_file, 0, deb_count)) {
1458 error_msg_and_die("Dependency check failed");
1459 }
1460 }
1461
1462 for (i = 0; i < deb_count; i++) {
1463 /* Remove or purge packages */
1464 if (dpkg_opt & dpkg_opt_remove) {
1465 remove_package(deb_file[i]->package);
1466 }
1467 else if (dpkg_opt & dpkg_opt_purge) {
1468 purge_package(deb_file[i]->package);
1469 }
1470 else if (dpkg_opt & dpkg_opt_unpack) {
1471 unpack_package(deb_file[i]);
1472 }
1473 else if (dpkg_opt & dpkg_opt_install) {
1474 unpack_package(deb_file[i]);
1475 configure_package(deb_file[i]);
1476 }
1477 else if (dpkg_opt & dpkg_opt_configure) {
1478 configure_package(deb_file[i]);
1479 }
1480 }
1481
1482 write_status_file(deb_file);
1483
1484 for (i = 0; i < deb_count; i++) {
1485 free(deb_file[i]->control_file);
1486 free(deb_file[i]->filename);
1487 free(deb_file[i]);
1488 }
1489 free(deb_file);
1490
1491 for (i = 0; i < NAME_HASH_PRIME; i++) {
1492 if (name_hashtable[i] != NULL) {
1493 free(name_hashtable[i]);
1494 }
1495 }
1496
1497 for (i = 0; i < PACKAGE_HASH_PRIME; i++) {
1498 free_package(package_hashtable[i]);
1499 }
1500
1501 for (i = 0; i < STATUS_HASH_PRIME; i++) {
1502 if (status_hashtable[i] != NULL) {
1503 free(status_hashtable[i]);
1504 }
1505 }
1506
1507 return(EXIT_SUCCESS);
1508}
1509
diff --git a/dpkg_deb.c b/dpkg_deb.c
deleted file mode 100644
index a933c6948..000000000
--- a/dpkg_deb.c
+++ /dev/null
@@ -1,130 +0,0 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19#include <getopt.h>
20#include "busybox.h"
21
22extern int dpkg_deb_main(int argc, char **argv)
23{
24 char *prefix = NULL;
25 char *filename = NULL;
26 char *output_buffer = NULL;
27 int opt = 0;
28 int arg_type = 0;
29 int deb_extract_funct = extract_create_leading_dirs | extract_unconditional;
30
31 const int arg_type_prefix = 1;
32 const int arg_type_field = 2;
33 const int arg_type_filename = 4;
34// const int arg_type_un_ar_gz = 8;
35
36 while ((opt = getopt(argc, argv, "ceftXxI")) != -1) {
37 switch (opt) {
38 case 'c':
39 deb_extract_funct |= extract_data_tar_gz;
40 deb_extract_funct |= extract_verbose_list;
41 break;
42 case 'e':
43 arg_type = arg_type_prefix;
44 deb_extract_funct |= extract_control_tar_gz;
45 deb_extract_funct |= extract_all_to_fs;
46 break;
47 case 'f':
48 arg_type = arg_type_field;
49 deb_extract_funct |= extract_control_tar_gz;
50 deb_extract_funct |= extract_one_to_buffer;
51 filename = xstrdup("./control");
52 break;
53 case 't': /* --fsys-tarfile, i just made up this short name */
54 /* Integrate the functionality needed with some code from ar.c */
55 error_msg_and_die("Option disabled");
56// arg_type = arg_type_un_ar_gz;
57 break;
58 case 'X':
59 arg_type = arg_type_prefix;
60 deb_extract_funct |= extract_data_tar_gz;
61 deb_extract_funct |= extract_all_to_fs;
62 deb_extract_funct |= extract_list;
63 case 'x':
64 arg_type = arg_type_prefix;
65 deb_extract_funct |= extract_data_tar_gz;
66 deb_extract_funct |= extract_all_to_fs;
67 break;
68 case 'I':
69 arg_type = arg_type_filename;
70 deb_extract_funct |= extract_control_tar_gz;
71 deb_extract_funct |= extract_one_to_buffer;
72 break;
73 default:
74 show_usage();
75 }
76 }
77
78 if (optind == argc) {
79 show_usage();
80 }
81
82 /* Workout where to extract the files */
83 if (arg_type == arg_type_prefix) {
84 /* argument is a dir name */
85 if ((optind + 1) == argc ) {
86 prefix = xstrdup("./DEBIAN/");
87 } else {
88 prefix = (char *) xmalloc(strlen(argv[optind + 1]) + 2);
89 strcpy(prefix, argv[optind + 1]);
90 /* Make sure the directory has a trailing '/' */
91 if (last_char_is(prefix, '/') == NULL) {
92 strcat(prefix, "/");
93 }
94 }
95 mkdir(prefix, 0777);
96 }
97
98 if (arg_type == arg_type_filename) {
99 if ((optind + 1) != argc) {
100 filename = xstrdup(argv[optind + 1]);
101 } else {
102 error_msg_and_die("-I currently requires a filename to be specified");
103 }
104 }
105
106 output_buffer = deb_extract(argv[optind], stdout, deb_extract_funct, prefix, filename);
107
108 if ((arg_type == arg_type_filename) && (output_buffer != NULL)) {
109 puts(output_buffer);
110 }
111 else if (arg_type == arg_type_field) {
112 char *field = NULL;
113 char *name;
114 char *value;
115 int field_start = 0;
116
117 while (1) {
118 field_start += read_package_field(&output_buffer[field_start], &name, &value);
119 if (name == NULL) {
120 break;
121 }
122 if (strcmp(name, argv[optind + 1]) == 0) {
123 puts(value);
124 }
125 free(field);
126 }
127 }
128
129 return(EXIT_SUCCESS);
130}
diff --git a/du.c b/du.c
deleted file mode 100644
index fb649aee5..000000000
--- a/du.c
+++ /dev/null
@@ -1,257 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini du implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by John Beppu <beppu@lineo.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <sys/types.h>
26#include <fcntl.h>
27#include <dirent.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <getopt.h>
31#include <string.h>
32#include <errno.h>
33#include "busybox.h"
34
35
36#ifdef BB_FEATURE_HUMAN_READABLE
37static unsigned long disp_hr = KILOBYTE;
38#endif
39
40typedef void (Display) (long, char *);
41
42static int du_depth = 0;
43static int count_hardlinks = 0;
44
45static Display *print;
46
47static void print_normal(long size, char *filename)
48{
49#ifdef BB_FEATURE_HUMAN_READABLE
50 printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename);
51#else
52 printf("%ld\t%s\n", size, filename);
53#endif
54}
55
56static void print_summary(long size, char *filename)
57{
58 if (du_depth == 1) {
59 print_normal(size, filename);
60 }
61}
62
63#define HASH_SIZE 311 /* Should be prime */
64#define hash_inode(i) ((i) % HASH_SIZE)
65
66typedef struct ino_dev_hash_bucket_struct {
67 struct ino_dev_hash_bucket_struct *next;
68 ino_t ino;
69 dev_t dev;
70 char name[1];
71} ino_dev_hashtable_bucket_t;
72
73static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
74
75/*
76 * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
77 * `ino_dev_hashtable', else return 0
78 *
79 * If NAME is a non-NULL pointer to a character pointer, and there is
80 * a match, then set *NAME to the value of the name slot in that
81 * bucket.
82 */
83static int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
84{
85 ino_dev_hashtable_bucket_t *bucket;
86
87 bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
88 while (bucket != NULL) {
89 if ((bucket->ino == statbuf->st_ino) &&
90 (bucket->dev == statbuf->st_dev))
91 {
92 if (name) *name = bucket->name;
93 return 1;
94 }
95 bucket = bucket->next;
96 }
97 return 0;
98}
99
100/* Add statbuf to statbuf hash table */
101static void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
102{
103 int i;
104 size_t s;
105 ino_dev_hashtable_bucket_t *bucket;
106
107 i = hash_inode(statbuf->st_ino);
108 s = name ? strlen(name) : 0;
109 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
110 bucket->ino = statbuf->st_ino;
111 bucket->dev = statbuf->st_dev;
112 if (name)
113 strcpy(bucket->name, name);
114 else
115 bucket->name[0] = '\0';
116 bucket->next = ino_dev_hashtable[i];
117 ino_dev_hashtable[i] = bucket;
118}
119
120/* Clear statbuf hash table */
121static void reset_ino_dev_hashtable(void)
122{
123 int i;
124 ino_dev_hashtable_bucket_t *bucket;
125
126 for (i = 0; i < HASH_SIZE; i++) {
127 while (ino_dev_hashtable[i] != NULL) {
128 bucket = ino_dev_hashtable[i]->next;
129 free(ino_dev_hashtable[i]);
130 ino_dev_hashtable[i] = bucket;
131 }
132 }
133}
134
135/* tiny recursive du */
136static long du(char *filename)
137{
138 struct stat statbuf;
139 long sum;
140
141 if ((lstat(filename, &statbuf)) != 0) {
142 perror_msg("%s", filename);
143 return 0;
144 }
145
146 du_depth++;
147 sum = (statbuf.st_blocks >> 1);
148
149 /* Don't add in stuff pointed to by symbolic links */
150 if (S_ISLNK(statbuf.st_mode)) {
151 sum = 0L;
152 if (du_depth == 1) {
153 }
154 }
155 if (S_ISDIR(statbuf.st_mode)) {
156 DIR *dir;
157 struct dirent *entry;
158 char *newfile;
159
160 dir = opendir(filename);
161 if (!dir) {
162 du_depth--;
163 return 0;
164 }
165
166 newfile = last_char_is(filename, '/');
167 if (newfile)
168 *newfile = '\0';
169
170 while ((entry = readdir(dir))) {
171 char *name = entry->d_name;
172
173 if ((strcmp(name, "..") == 0)
174 || (strcmp(name, ".") == 0)) {
175 continue;
176 }
177 newfile = concat_path_file(filename, name);
178 sum += du(newfile);
179 free(newfile);
180 }
181 closedir(dir);
182 print(sum, filename);
183 }
184 else if (statbuf.st_nlink > 1 && !count_hardlinks) {
185 /* Add files with hard links only once */
186 if (is_in_ino_dev_hashtable(&statbuf, NULL)) {
187 sum = 0L;
188 if (du_depth == 1)
189 print(sum, filename);
190 }
191 else {
192 add_to_ino_dev_hashtable(&statbuf, NULL);
193 }
194 }
195 du_depth--;
196 return sum;
197}
198
199int du_main(int argc, char **argv)
200{
201 int status = EXIT_SUCCESS;
202 int i;
203 int c;
204
205 /* default behaviour */
206 print = print_normal;
207
208 /* parse argv[] */
209 while ((c = getopt(argc, argv, "sl"
210#ifdef BB_FEATURE_HUMAN_READABLE
211"hm"
212#endif
213"k")) != EOF) {
214 switch (c) {
215 case 's':
216 print = print_summary;
217 break;
218 case 'l':
219 count_hardlinks = 1;
220 break;
221#ifdef BB_FEATURE_HUMAN_READABLE
222 case 'h': disp_hr = 0; break;
223 case 'm': disp_hr = MEGABYTE; break;
224#endif
225 case 'k': break;
226 default:
227 show_usage();
228 }
229 }
230
231 /* go through remaining args (if any) */
232 if (optind >= argc) {
233 if (du(".") == 0)
234 status = EXIT_FAILURE;
235 } else {
236 long sum;
237
238 for (i=optind; i < argc; i++) {
239 sum = du(argv[i]);
240 if(is_directory(argv[i], FALSE, NULL)==FALSE) {
241 print_normal(sum, argv[i]);
242 }
243 reset_ino_dev_hashtable();
244 }
245 }
246
247 return status;
248}
249
250/* $Id: du.c,v 1.50 2001/06/30 17:54:20 andersen Exp $ */
251/*
252Local Variables:
253c-file-style: "linux"
254c-basic-offset: 4
255tab-width: 4
256End:
257*/
diff --git a/dumpkmap.c b/dumpkmap.c
deleted file mode 100644
index 22652a5e2..000000000
--- a/dumpkmap.c
+++ /dev/null
@@ -1,95 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini dumpkmap implementation for busybox
4 *
5 * Copyright (C) Arne Bernin <arne@matrix.loopback.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <errno.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <unistd.h>
27#include <string.h>
28#include <stdlib.h>
29#include <sys/ioctl.h>
30#include "busybox.h"
31
32/* From <linux/kd.h> */
33struct kbentry {
34 unsigned char kb_table;
35 unsigned char kb_index;
36 unsigned short kb_value;
37};
38static const int KDGKBENT = 0x4B46; /* gets one entry in translation table */
39
40/* From <linux/keyboard.h> */
41static const int NR_KEYS = 128;
42static const int MAX_NR_KEYMAPS = 256;
43
44int dumpkmap_main(int argc, char **argv)
45{
46 struct kbentry ke;
47 int i, j, fd;
48 char flags[MAX_NR_KEYMAPS], magic[] = "bkeymap";
49
50 if (argc>=2 && *argv[1]=='-') {
51 show_usage();
52 }
53
54 fd = open(CURRENT_VC, O_RDWR);
55 if (fd < 0) {
56 perror_msg("Error opening " CURRENT_VC);
57 return EXIT_FAILURE;
58 }
59
60 write(1, magic, 7);
61
62 for (i=0; i < MAX_NR_KEYMAPS; i++) flags[i]=0;
63 flags[0]=1;
64 flags[1]=1;
65 flags[2]=1;
66 flags[4]=1;
67 flags[5]=1;
68 flags[6]=1;
69 flags[8]=1;
70 flags[9]=1;
71 flags[10]=1;
72 flags[12]=1;
73
74 /* dump flags */
75 for (i=0; i < MAX_NR_KEYMAPS; i++) write(1,&flags[i],1);
76
77 for (i = 0; i < MAX_NR_KEYMAPS; i++) {
78 if (flags[i] == 1) {
79 for (j = 0; j < NR_KEYS; j++) {
80 ke.kb_index = j;
81 ke.kb_table = i;
82 if (ioctl(fd, KDGKBENT, &ke) < 0) {
83
84 error_msg("ioctl returned: %s, %s, %s, %xqq", strerror(errno),(char *)&ke.kb_index,(char *)&ke.kb_table,(int)&ke.kb_value);
85 }
86 else {
87 write(1,(void*)&ke.kb_value,2);
88 }
89
90 }
91 }
92 }
93 close(fd);
94 return EXIT_SUCCESS;
95}
diff --git a/dutmp.c b/dutmp.c
deleted file mode 100644
index df7f64d30..000000000
--- a/dutmp.c
+++ /dev/null
@@ -1,64 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
4 *
5 * dutmp
6 * Takes utmp formated file on stdin and dumps it's contents
7 * out in colon delimited fields. Easy to 'cut' for shell based
8 * versions of 'who', 'last', etc. IP Addr is output in hex,
9 * little endian on x86.
10 *
11 * Modified to support all sorts of libcs by
12 * Erik Andersen <andersen@lineo.com>
13 */
14
15#include <sys/types.h>
16#include <fcntl.h>
17
18#include <errno.h>
19#include <utmp.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include "busybox.h"
23
24extern int dutmp_main(int argc, char **argv)
25{
26
27 int file;
28 struct utmp ut;
29
30 if (argc<2) {
31 file = fileno(stdin);
32 } else if (*argv[1] == '-' ) {
33 show_usage();
34 } else {
35 file = open(argv[1], O_RDONLY);
36 if (file < 0) {
37 perror_msg_and_die(io_error, argv[1]);
38 }
39 }
40
41/* Kludge around the fact that the binary format for utmp has changed. */
42#if __GNU_LIBRARY__ < 5 || defined __UCLIBC__
43 /* Linux libc5 */
44 while (read(file, (void*)&ut, sizeof(struct utmp))) {
45 printf("%d|%d|%s|%s|%s|%s|%s|%lx\n",
46 ut.ut_type, ut.ut_pid, ut.ut_line,
47 ut.ut_id, ut.ut_user, ut.ut_host,
48 ctime(&(ut.ut_time)),
49 (long)ut.ut_addr);
50 }
51#else
52 /* Glibc, uClibc, etc. */
53 while (read(file, (void*)&ut, sizeof(struct utmp))) {
54 printf("%d|%d|%s|%s|%s|%s|%d|%d|%ld|%ld|%ld|%x\n",
55 ut.ut_type, ut.ut_pid, ut.ut_line,
56 ut.ut_id, ut.ut_user, ut.ut_host,
57 ut.ut_exit.e_termination, ut.ut_exit.e_exit,
58 ut.ut_session,
59 ut.ut_tv.tv_sec, ut.ut_tv.tv_usec,
60 ut.ut_addr);
61 }
62#endif
63 return EXIT_SUCCESS;
64}
diff --git a/echo.c b/echo.c
deleted file mode 100644
index 31c031528..000000000
--- a/echo.c
+++ /dev/null
@@ -1,152 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * echo implementation for busybox
4 *
5 * Copyright (c) 1991, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Original copyright notice is retained at the end of this file.
23 */
24
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include "busybox.h"
29
30extern int
31echo_main(int argc, char** argv)
32{
33 int nflag = 0;
34 int eflag = 0;
35
36 /* Skip argv[0]. */
37 argc--;
38 argv++;
39
40 while (argc > 0 && *argv[0] == '-')
41 {
42 register char *temp;
43 register int ix;
44
45 /*
46 * If it appears that we are handling options, then make sure
47 * that all of the options specified are actually valid.
48 * Otherwise, the string should just be echoed.
49 */
50 temp = argv[0] + 1;
51
52 for (ix = 0; temp[ix]; ix++)
53 {
54 if (strrchr("neE", temp[ix]) == 0)
55 goto just_echo;
56 }
57
58 if (!*temp)
59 goto just_echo;
60
61 /*
62 * All of the options in temp are valid options to echo.
63 * Handle them.
64 */
65 while (*temp)
66 {
67 if (*temp == 'n')
68 nflag = 1;
69 else if (*temp == 'e')
70 eflag = 1;
71 else if (*temp == 'E')
72 eflag = 0;
73 else
74 goto just_echo;
75
76 temp++;
77 }
78 argc--;
79 argv++;
80 }
81
82just_echo:
83 while (argc > 0) {
84 const char *arg = argv[0];
85 register int c;
86
87 while ((c = *arg++)) {
88
89 /* Check for escape sequence. */
90 if (c == '\\' && eflag && *arg) {
91 if (*arg == 'c') {
92 /* '\c' means cancel newline. */
93 nflag = 1;
94 arg++;
95 continue;
96 } else {
97 c = process_escape_sequence(&arg);
98 }
99 }
100
101 putchar(c);
102 }
103 argc--;
104 argv++;
105 if (argc > 0)
106 putchar(' ');
107 }
108 if (!nflag)
109 putchar('\n');
110 fflush(stdout);
111
112 return EXIT_SUCCESS;
113}
114
115/*-
116 * Copyright (c) 1991, 1993
117 * The Regents of the University of California. All rights reserved.
118 *
119 * This code is derived from software contributed to Berkeley by
120 * Kenneth Almquist.
121 *
122 * Redistribution and use in source and binary forms, with or without
123 * modification, are permitted provided that the following conditions
124 * are met:
125 * 1. Redistributions of source code must retain the above copyright
126 * notice, this list of conditions and the following disclaimer.
127 * 2. Redistributions in binary form must reproduce the above copyright
128 * notice, this list of conditions and the following disclaimer in the
129 * documentation and/or other materials provided with the distribution.
130 *
131 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
132 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
133 *
134 * California, Berkeley and its contributors.
135 * 4. Neither the name of the University nor the names of its contributors
136 * may be used to endorse or promote products derived from this software
137 * without specific prior written permission.
138 *
139 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
140 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
141 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
142 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
143 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
144 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
145 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
146 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
147 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
148 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
149 * SUCH DAMAGE.
150 *
151 * @(#)echo.c 8.1 (Berkeley) 5/31/93
152 */
diff --git a/editors/Makefile b/editors/Makefile
new file mode 100644
index 000000000..7d8d96582
--- /dev/null
+++ b/editors/Makefile
@@ -0,0 +1,36 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := editors.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27obj-$(CONFIG_SED) += sed.o
28obj-$(CONFIG_VI) += vi.o
29
30
31# Hand off to toplevel Rules.mak
32include $(TOPDIR)/Rules.mak
33
34clean:
35 rm -f $(L_TARGET) *.o core
36
diff --git a/editors/config.in b/editors/config.in
new file mode 100644
index 000000000..6c1d6cebe
--- /dev/null
+++ b/editors/config.in
@@ -0,0 +1,12 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Editors'
8
9bool 'sed' CONFIG_SED
10bool 'vi' CONFIG_VI
11endmenu
12
diff --git a/editors/sed.c b/editors/sed.c
index 709fb13a8..10cab7d56 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -1,8 +1,8 @@
1/* 1/*
2 * sed.c - very minimalist version of sed 2 * sed.c - very minimalist version of sed
3 * 3 *
4 * Copyright (C) 1999,2000,2001 by Lineo, inc. 4 * Copyright (C) 1999,2000,2001 by Lineo, inc. and Mark Whitley
5 * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org> 5 * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -104,7 +104,7 @@ static int ncmds = 0; /* number of sed commands */
104 104
105/*static char *cur_file = NULL;*/ /* file currently being processed XXX: do I need this? */ 105/*static char *cur_file = NULL;*/ /* file currently being processed XXX: do I need this? */
106 106
107#ifdef BB_FEATURE_CLEAN_UP 107#ifdef CONFIG_FEATURE_CLEAN_UP
108static void destroy_cmd_strs() 108static void destroy_cmd_strs()
109{ 109{
110 if (sed_cmds == NULL) 110 if (sed_cmds == NULL)
@@ -791,7 +791,7 @@ extern int sed_main(int argc, char **argv)
791{ 791{
792 int opt; 792 int opt;
793 793
794#ifdef BB_FEATURE_CLEAN_UP 794#ifdef CONFIG_FEATURE_CLEAN_UP
795 /* destroy command strings on exit */ 795 /* destroy command strings on exit */
796 if (atexit(destroy_cmd_strs) == -1) 796 if (atexit(destroy_cmd_strs) == -1)
797 perror_msg_and_die("atexit"); 797 perror_msg_and_die("atexit");
diff --git a/editors/vi.c b/editors/vi.c
index 8d7506d0f..ddc2edc75 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -19,13 +19,13 @@
19 */ 19 */
20 20
21static const char vi_Version[] = 21static const char vi_Version[] =
22 "$Id: vi.c,v 1.15 2001/08/02 05:26:41 andersen Exp $"; 22 "$Id: vi.c,v 1.16 2001/10/24 04:59:23 andersen Exp $";
23 23
24/* 24/*
25 * To compile for standalone use: 25 * To compile for standalone use:
26 * gcc -Wall -Os -s -DSTANDALONE -o vi vi.c 26 * gcc -Wall -Os -s -DSTANDALONE -o vi vi.c
27 * or 27 * or
28 * gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c # include testing features 28 * gcc -Wall -Os -s -DSTANDALONE -DCONFIG_FEATURE_VI_CRASHME -o vi vi.c # include testing features
29 * strip vi 29 * strip vi
30 */ 30 */
31 31
@@ -48,21 +48,21 @@ static const char vi_Version[] =
48//---- Feature -------------- Bytes to immplement 48//---- Feature -------------- Bytes to immplement
49#ifdef STANDALONE 49#ifdef STANDALONE
50#define vi_main main 50#define vi_main main
51#define BB_FEATURE_VI_COLON // 4288 51#define CONFIG_FEATURE_VI_COLON // 4288
52#define BB_FEATURE_VI_YANKMARK // 1408 52#define CONFIG_FEATURE_VI_YANKMARK // 1408
53#define BB_FEATURE_VI_SEARCH // 1088 53#define CONFIG_FEATURE_VI_SEARCH // 1088
54#define BB_FEATURE_VI_USE_SIGNALS // 1056 54#define CONFIG_FEATURE_VI_USE_SIGNALS // 1056
55#define BB_FEATURE_VI_DOT_CMD // 576 55#define CONFIG_FEATURE_VI_DOT_CMD // 576
56#define BB_FEATURE_VI_READONLY // 128 56#define CONFIG_FEATURE_VI_READONLY // 128
57#define BB_FEATURE_VI_SETOPTS // 576 57#define CONFIG_FEATURE_VI_SETOPTS // 576
58#define BB_FEATURE_VI_SET // 224 58#define CONFIG_FEATURE_VI_SET // 224
59#define BB_FEATURE_VI_WIN_RESIZE // 256 WIN_RESIZE 59#define CONFIG_FEATURE_VI_WIN_RESIZE // 256 WIN_RESIZE
60// To test editor using CRASHME: 60// To test editor using CRASHME:
61// vi -C filename 61// vi -C filename
62// To stop testing, wait until all to text[] is deleted, or 62// To stop testing, wait until all to text[] is deleted, or
63// Ctrl-Z and kill -9 %1 63// Ctrl-Z and kill -9 %1
64// while in the editor Ctrl-T will toggle the crashme function on and off. 64// while in the editor Ctrl-T will toggle the crashme function on and off.
65//#define BB_FEATURE_VI_CRASHME // randomly pick commands to execute 65//#define CONFIG_FEATURE_VI_CRASHME // randomly pick commands to execute
66#endif /* STANDALONE */ 66#endif /* STANDALONE */
67 67
68#include <stdio.h> 68#include <stdio.h>
@@ -161,40 +161,40 @@ static Byte *dot; // where all the action takes place
161static int tabstop; 161static int tabstop;
162static struct termios term_orig, term_vi; // remember what the cooked mode was 162static struct termios term_orig, term_vi; // remember what the cooked mode was
163 163
164#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR 164#ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
165static int last_row; // where the cursor was last moved to 165static int last_row; // where the cursor was last moved to
166#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ 166#endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
167#ifdef BB_FEATURE_VI_USE_SIGNALS 167#ifdef CONFIG_FEATURE_VI_USE_SIGNALS
168static jmp_buf restart; // catch_sig() 168static jmp_buf restart; // catch_sig()
169#endif /* BB_FEATURE_VI_USE_SIGNALS */ 169#endif /* CONFIG_FEATURE_VI_USE_SIGNALS */
170#ifdef BB_FEATURE_VI_WIN_RESIZE 170#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
171static struct winsize winsize; // remember the window size 171static struct winsize winsize; // remember the window size
172#endif /* BB_FEATURE_VI_WIN_RESIZE */ 172#endif /* CONFIG_FEATURE_VI_WIN_RESIZE */
173#ifdef BB_FEATURE_VI_DOT_CMD 173#ifdef CONFIG_FEATURE_VI_DOT_CMD
174static int adding2q; // are we currently adding user input to q 174static int adding2q; // are we currently adding user input to q
175static Byte *last_modifying_cmd; // last modifying cmd for "." 175static Byte *last_modifying_cmd; // last modifying cmd for "."
176static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read" 176static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read"
177#endif /* BB_FEATURE_VI_DOT_CMD */ 177#endif /* CONFIG_FEATURE_VI_DOT_CMD */
178#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK) 178#if defined(CONFIG_FEATURE_VI_DOT_CMD) || defined(CONFIG_FEATURE_VI_YANKMARK)
179static Byte *modifying_cmds; // cmds that modify text[] 179static Byte *modifying_cmds; // cmds that modify text[]
180#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */ 180#endif /* CONFIG_FEATURE_VI_DOT_CMD || CONFIG_FEATURE_VI_YANKMARK */
181#ifdef BB_FEATURE_VI_READONLY 181#ifdef CONFIG_FEATURE_VI_READONLY
182static int vi_readonly, readonly; 182static int vi_readonly, readonly;
183#endif /* BB_FEATURE_VI_READONLY */ 183#endif /* CONFIG_FEATURE_VI_READONLY */
184#ifdef BB_FEATURE_VI_SETOPTS 184#ifdef CONFIG_FEATURE_VI_SETOPTS
185static int autoindent; 185static int autoindent;
186static int showmatch; 186static int showmatch;
187static int ignorecase; 187static int ignorecase;
188#endif /* BB_FEATURE_VI_SETOPTS */ 188#endif /* CONFIG_FEATURE_VI_SETOPTS */
189#ifdef BB_FEATURE_VI_YANKMARK 189#ifdef CONFIG_FEATURE_VI_YANKMARK
190static Byte *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 190static Byte *reg[28]; // named register a-z, "D", and "U" 0-25,26,27
191static int YDreg, Ureg; // default delete register and orig line for "U" 191static int YDreg, Ureg; // default delete register and orig line for "U"
192static Byte *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' 192static Byte *mark[28]; // user marks points somewhere in text[]- a-z and previous context ''
193static Byte *context_start, *context_end; 193static Byte *context_start, *context_end;
194#endif /* BB_FEATURE_VI_YANKMARK */ 194#endif /* CONFIG_FEATURE_VI_YANKMARK */
195#ifdef BB_FEATURE_VI_SEARCH 195#ifdef CONFIG_FEATURE_VI_SEARCH
196static Byte *last_search_pattern; // last pattern from a '/' or '?' search 196static Byte *last_search_pattern; // last pattern from a '/' or '?' search
197#endif /* BB_FEATURE_VI_SEARCH */ 197#endif /* CONFIG_FEATURE_VI_SEARCH */
198 198
199 199
200static void edit_file(Byte *); // edit one file 200static void edit_file(Byte *); // edit one file
@@ -259,59 +259,59 @@ static void redraw(int); // force a full screen refresh
259static void format_line(Byte*, Byte*, int); 259static void format_line(Byte*, Byte*, int);
260static void refresh(int); // update the terminal from screen[] 260static void refresh(int); // update the terminal from screen[]
261 261
262#ifdef BB_FEATURE_VI_SEARCH 262#ifdef CONFIG_FEATURE_VI_SEARCH
263static Byte *char_search(Byte *, Byte *, int, int); // search for pattern starting at p 263static Byte *char_search(Byte *, Byte *, int, int); // search for pattern starting at p
264static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase" 264static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase"
265#endif /* BB_FEATURE_VI_SEARCH */ 265#endif /* CONFIG_FEATURE_VI_SEARCH */
266#ifdef BB_FEATURE_VI_COLON 266#ifdef CONFIG_FEATURE_VI_COLON
267static void Hit_Return(void); 267static void Hit_Return(void);
268static Byte *get_one_address(Byte *, int *); // get colon addr, if present 268static Byte *get_one_address(Byte *, int *); // get colon addr, if present
269static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present 269static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present
270static void colon(Byte *); // execute the "colon" mode cmds 270static void colon(Byte *); // execute the "colon" mode cmds
271#endif /* BB_FEATURE_VI_COLON */ 271#endif /* CONFIG_FEATURE_VI_COLON */
272static Byte *get_input_line(Byte *); // get input line- use "status line" 272static Byte *get_input_line(Byte *); // get input line- use "status line"
273#ifdef BB_FEATURE_VI_USE_SIGNALS 273#ifdef CONFIG_FEATURE_VI_USE_SIGNALS
274static void winch_sig(int); // catch window size changes 274static void winch_sig(int); // catch window size changes
275static void suspend_sig(int); // catch ctrl-Z 275static void suspend_sig(int); // catch ctrl-Z
276static void alarm_sig(int); // catch alarm time-outs 276static void alarm_sig(int); // catch alarm time-outs
277static void catch_sig(int); // catch ctrl-C 277static void catch_sig(int); // catch ctrl-C
278static void core_sig(int); // catch a core dump signal 278static void core_sig(int); // catch a core dump signal
279#endif /* BB_FEATURE_VI_USE_SIGNALS */ 279#endif /* CONFIG_FEATURE_VI_USE_SIGNALS */
280#ifdef BB_FEATURE_VI_DOT_CMD 280#ifdef CONFIG_FEATURE_VI_DOT_CMD
281static void start_new_cmd_q(Byte); // new queue for command 281static void start_new_cmd_q(Byte); // new queue for command
282static void end_cmd_q(); // stop saving input chars 282static void end_cmd_q(); // stop saving input chars
283#else /* BB_FEATURE_VI_DOT_CMD */ 283#else /* CONFIG_FEATURE_VI_DOT_CMD */
284#define end_cmd_q() 284#define end_cmd_q()
285#endif /* BB_FEATURE_VI_DOT_CMD */ 285#endif /* CONFIG_FEATURE_VI_DOT_CMD */
286#ifdef BB_FEATURE_VI_WIN_RESIZE 286#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
287static void window_size_get(int); // find out what size the window is 287static void window_size_get(int); // find out what size the window is
288#endif /* BB_FEATURE_VI_WIN_RESIZE */ 288#endif /* CONFIG_FEATURE_VI_WIN_RESIZE */
289#ifdef BB_FEATURE_VI_SETOPTS 289#ifdef CONFIG_FEATURE_VI_SETOPTS
290static void showmatching(Byte *); // show the matching pair () [] {} 290static void showmatching(Byte *); // show the matching pair () [] {}
291#endif /* BB_FEATURE_VI_SETOPTS */ 291#endif /* CONFIG_FEATURE_VI_SETOPTS */
292#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) 292#if defined(CONFIG_FEATURE_VI_YANKMARK) || defined(CONFIG_FEATURE_VI_COLON) || defined(CONFIG_FEATURE_VI_CRASHME)
293static Byte *string_insert(Byte *, Byte *); // insert the string at 'p' 293static Byte *string_insert(Byte *, Byte *); // insert the string at 'p'
294#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ 294#endif /* CONFIG_FEATURE_VI_YANKMARK || CONFIG_FEATURE_VI_COLON || CONFIG_FEATURE_VI_CRASHME */
295#ifdef BB_FEATURE_VI_YANKMARK 295#ifdef CONFIG_FEATURE_VI_YANKMARK
296static Byte *text_yank(Byte *, Byte *, int); // save copy of "p" into a register 296static Byte *text_yank(Byte *, Byte *, int); // save copy of "p" into a register
297static Byte what_reg(void); // what is letter of current YDreg 297static Byte what_reg(void); // what is letter of current YDreg
298static void check_context(Byte); // remember context for '' command 298static void check_context(Byte); // remember context for '' command
299static Byte *swap_context(Byte *); // goto new context for '' command 299static Byte *swap_context(Byte *); // goto new context for '' command
300#endif /* BB_FEATURE_VI_YANKMARK */ 300#endif /* CONFIG_FEATURE_VI_YANKMARK */
301#ifdef BB_FEATURE_VI_CRASHME 301#ifdef CONFIG_FEATURE_VI_CRASHME
302static void crash_dummy(); 302static void crash_dummy();
303static void crash_test(); 303static void crash_test();
304static int crashme = 0; 304static int crashme = 0;
305#endif /* BB_FEATURE_VI_CRASHME */ 305#endif /* CONFIG_FEATURE_VI_CRASHME */
306 306
307 307
308extern int vi_main(int argc, char **argv) 308extern int vi_main(int argc, char **argv)
309{ 309{
310 int c; 310 int c;
311 311
312#ifdef BB_FEATURE_VI_YANKMARK 312#ifdef CONFIG_FEATURE_VI_YANKMARK
313 int i; 313 int i;
314#endif /* BB_FEATURE_VI_YANKMARK */ 314#endif /* CONFIG_FEATURE_VI_YANKMARK */
315 315
316 CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence 316 CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence
317 CMup= "\033[A"; // move cursor up one line, same col 317 CMup= "\033[A"; // move cursor up one line, same col
@@ -321,46 +321,46 @@ extern int vi_main(int argc, char **argv)
321 SOs = "\033[7m"; // Terminal standout mode on 321 SOs = "\033[7m"; // Terminal standout mode on
322 SOn = "\033[0m"; // Terminal standout mode off 322 SOn = "\033[0m"; // Terminal standout mode off
323 bell= "\007"; // Terminal bell sequence 323 bell= "\007"; // Terminal bell sequence
324#ifdef BB_FEATURE_VI_CRASHME 324#ifdef CONFIG_FEATURE_VI_CRASHME
325 (void) srand((long) getpid()); 325 (void) srand((long) getpid());
326#endif /* BB_FEATURE_VI_CRASHME */ 326#endif /* CONFIG_FEATURE_VI_CRASHME */
327 status_buffer = (Byte *) malloc(200); // hold messages to user 327 status_buffer = (Byte *) malloc(200); // hold messages to user
328#ifdef BB_FEATURE_VI_READONLY 328#ifdef CONFIG_FEATURE_VI_READONLY
329 vi_readonly = readonly = FALSE; 329 vi_readonly = readonly = FALSE;
330 if (strncmp(argv[0], "view", 4) == 0) { 330 if (strncmp(argv[0], "view", 4) == 0) {
331 readonly = TRUE; 331 readonly = TRUE;
332 vi_readonly = TRUE; 332 vi_readonly = TRUE;
333 } 333 }
334#endif /* BB_FEATURE_VI_READONLY */ 334#endif /* CONFIG_FEATURE_VI_READONLY */
335#ifdef BB_FEATURE_VI_SETOPTS 335#ifdef CONFIG_FEATURE_VI_SETOPTS
336 autoindent = 1; 336 autoindent = 1;
337 ignorecase = 1; 337 ignorecase = 1;
338 showmatch = 1; 338 showmatch = 1;
339#endif /* BB_FEATURE_VI_SETOPTS */ 339#endif /* CONFIG_FEATURE_VI_SETOPTS */
340#ifdef BB_FEATURE_VI_YANKMARK 340#ifdef CONFIG_FEATURE_VI_YANKMARK
341 for (i = 0; i < 28; i++) { 341 for (i = 0; i < 28; i++) {
342 reg[i] = 0; 342 reg[i] = 0;
343 } // init the yank regs 343 } // init the yank regs
344#endif /* BB_FEATURE_VI_YANKMARK */ 344#endif /* CONFIG_FEATURE_VI_YANKMARK */
345#ifdef BB_FEATURE_VI_DOT_CMD 345#ifdef CONFIG_FEATURE_VI_DOT_CMD
346 modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] 346 modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[]
347#endif /* BB_FEATURE_VI_DOT_CMD */ 347#endif /* CONFIG_FEATURE_VI_DOT_CMD */
348 348
349 // 1- process $HOME/.exrc file 349 // 1- process $HOME/.exrc file
350 // 2- process EXINIT variable from environment 350 // 2- process EXINIT variable from environment
351 // 3- process command line args 351 // 3- process command line args
352 while ((c = getopt(argc, argv, "hCR")) != -1) { 352 while ((c = getopt(argc, argv, "hCR")) != -1) {
353 switch (c) { 353 switch (c) {
354#ifdef BB_FEATURE_VI_CRASHME 354#ifdef CONFIG_FEATURE_VI_CRASHME
355 case 'C': 355 case 'C':
356 crashme = 1; 356 crashme = 1;
357 break; 357 break;
358#endif /* BB_FEATURE_VI_CRASHME */ 358#endif /* CONFIG_FEATURE_VI_CRASHME */
359#ifdef BB_FEATURE_VI_READONLY 359#ifdef CONFIG_FEATURE_VI_READONLY
360 case 'R': // Read-only flag 360 case 'R': // Read-only flag
361 readonly = TRUE; 361 readonly = TRUE;
362 break; 362 break;
363#endif /* BB_FEATURE_VI_READONLY */ 363#endif /* CONFIG_FEATURE_VI_READONLY */
364 //case 'r': // recover flag- ignore- we don't use tmp file 364 //case 'r': // recover flag- ignore- we don't use tmp file
365 //case 'x': // encryption flag- ignore 365 //case 'x': // encryption flag- ignore
366 //case 'c': // execute command first 366 //case 'c': // execute command first
@@ -399,21 +399,21 @@ static void edit_file(Byte * fn)
399 char c; 399 char c;
400 int cnt, size, ch; 400 int cnt, size, ch;
401 401
402#ifdef BB_FEATURE_VI_USE_SIGNALS 402#ifdef CONFIG_FEATURE_VI_USE_SIGNALS
403 char *msg; 403 char *msg;
404 int sig; 404 int sig;
405#endif /* BB_FEATURE_VI_USE_SIGNALS */ 405#endif /* CONFIG_FEATURE_VI_USE_SIGNALS */
406#ifdef BB_FEATURE_VI_YANKMARK 406#ifdef CONFIG_FEATURE_VI_YANKMARK
407 static Byte *cur_line; 407 static Byte *cur_line;
408#endif /* BB_FEATURE_VI_YANKMARK */ 408#endif /* CONFIG_FEATURE_VI_YANKMARK */
409 409
410 rawmode(); 410 rawmode();
411 rows = 24; 411 rows = 24;
412 columns = 80; 412 columns = 80;
413 ch= -1; 413 ch= -1;
414#ifdef BB_FEATURE_VI_WIN_RESIZE 414#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
415 window_size_get(0); 415 window_size_get(0);
416#endif /* BB_FEATURE_VI_WIN_RESIZE */ 416#endif /* CONFIG_FEATURE_VI_WIN_RESIZE */
417 new_screen(rows, columns); // get memory for virtual screen 417 new_screen(rows, columns); // get memory for virtual screen
418 418
419 cnt = file_size(fn); // file size 419 cnt = file_size(fn); // file size
@@ -427,14 +427,14 @@ static void edit_file(Byte * fn)
427 (void) char_insert(text, '\n'); // start empty buf with dummy line 427 (void) char_insert(text, '\n'); // start empty buf with dummy line
428 } 428 }
429 file_modified = FALSE; 429 file_modified = FALSE;
430#ifdef BB_FEATURE_VI_YANKMARK 430#ifdef CONFIG_FEATURE_VI_YANKMARK
431 YDreg = 26; // default Yank/Delete reg 431 YDreg = 26; // default Yank/Delete reg
432 Ureg = 27; // hold orig line for "U" cmd 432 Ureg = 27; // hold orig line for "U" cmd
433 for (cnt = 0; cnt < 28; cnt++) { 433 for (cnt = 0; cnt < 28; cnt++) {
434 mark[cnt] = 0; 434 mark[cnt] = 0;
435 } // init the marks 435 } // init the marks
436 mark[26] = mark[27] = text; // init "previous context" 436 mark[26] = mark[27] = text; // init "previous context"
437#endif /* BB_FEATURE_VI_YANKMARK */ 437#endif /* CONFIG_FEATURE_VI_YANKMARK */
438 438
439 err_method = 1; // flash 439 err_method = 1; // flash
440 last_forward_char = last_input_char = '\0'; 440 last_forward_char = last_input_char = '\0';
@@ -442,7 +442,7 @@ static void edit_file(Byte * fn)
442 ccol = 0; 442 ccol = 0;
443 edit_status(); 443 edit_status();
444 444
445#ifdef BB_FEATURE_VI_USE_SIGNALS 445#ifdef CONFIG_FEATURE_VI_USE_SIGNALS
446 signal(SIGHUP, catch_sig); 446 signal(SIGHUP, catch_sig);
447 signal(SIGINT, catch_sig); 447 signal(SIGINT, catch_sig);
448 signal(SIGALRM, alarm_sig); 448 signal(SIGALRM, alarm_sig);
@@ -481,7 +481,7 @@ static void edit_file(Byte * fn)
481 psbs("-- caught signal %d %s--", sig, msg); 481 psbs("-- caught signal %d %s--", sig, msg);
482 screenbegin = dot = text; 482 screenbegin = dot = text;
483 } 483 }
484#endif /* BB_FEATURE_VI_USE_SIGNALS */ 484#endif /* CONFIG_FEATURE_VI_USE_SIGNALS */
485 485
486 editing = 1; 486 editing = 1;
487 cmd_mode = 0; // 0=command 1=insert 2='R'eplace 487 cmd_mode = 0; // 0=command 1=insert 2='R'eplace
@@ -489,20 +489,20 @@ static void edit_file(Byte * fn)
489 tabstop = 8; 489 tabstop = 8;
490 offset = 0; // no horizontal offset 490 offset = 0; // no horizontal offset
491 c = '\0'; 491 c = '\0';
492#ifdef BB_FEATURE_VI_DOT_CMD 492#ifdef CONFIG_FEATURE_VI_DOT_CMD
493 if (last_modifying_cmd != 0) 493 if (last_modifying_cmd != 0)
494 free(last_modifying_cmd); 494 free(last_modifying_cmd);
495 if (ioq_start != NULL) 495 if (ioq_start != NULL)
496 free(ioq_start); 496 free(ioq_start);
497 ioq = ioq_start = last_modifying_cmd = 0; 497 ioq = ioq_start = last_modifying_cmd = 0;
498 adding2q = 0; 498 adding2q = 0;
499#endif /* BB_FEATURE_VI_DOT_CMD */ 499#endif /* CONFIG_FEATURE_VI_DOT_CMD */
500 redraw(FALSE); // dont force every col re-draw 500 redraw(FALSE); // dont force every col re-draw
501 show_status_line(); 501 show_status_line();
502 502
503 //------This is the main Vi cmd handling loop ----------------------- 503 //------This is the main Vi cmd handling loop -----------------------
504 while (editing > 0) { 504 while (editing > 0) {
505#ifdef BB_FEATURE_VI_CRASHME 505#ifdef CONFIG_FEATURE_VI_CRASHME
506 if (crashme > 0) { 506 if (crashme > 0) {
507 if ((end - text) > 1) { 507 if ((end - text) > 1) {
508 crash_dummy(); // generate a random command 508 crash_dummy(); // generate a random command
@@ -513,23 +513,23 @@ static void edit_file(Byte * fn)
513 refresh(FALSE); 513 refresh(FALSE);
514 } 514 }
515 } 515 }
516#endif /* BB_FEATURE_VI_CRASHME */ 516#endif /* CONFIG_FEATURE_VI_CRASHME */
517 last_input_char = c = get_one_char(); // get a cmd from user 517 last_input_char = c = get_one_char(); // get a cmd from user
518#ifdef BB_FEATURE_VI_YANKMARK 518#ifdef CONFIG_FEATURE_VI_YANKMARK
519 // save a copy of the current line- for the 'U" command 519 // save a copy of the current line- for the 'U" command
520 if (begin_line(dot) != cur_line) { 520 if (begin_line(dot) != cur_line) {
521 cur_line = begin_line(dot); 521 cur_line = begin_line(dot);
522 text_yank(begin_line(dot), end_line(dot), Ureg); 522 text_yank(begin_line(dot), end_line(dot), Ureg);
523 } 523 }
524#endif /* BB_FEATURE_VI_YANKMARK */ 524#endif /* CONFIG_FEATURE_VI_YANKMARK */
525#ifdef BB_FEATURE_VI_DOT_CMD 525#ifdef CONFIG_FEATURE_VI_DOT_CMD
526 // These are commands that change text[]. 526 // These are commands that change text[].
527 // Remember the input for the "." command 527 // Remember the input for the "." command
528 if (!adding2q && ioq_start == 0 528 if (!adding2q && ioq_start == 0
529 && strchr((char *) modifying_cmds, c) != NULL) { 529 && strchr((char *) modifying_cmds, c) != NULL) {
530 start_new_cmd_q(c); 530 start_new_cmd_q(c);
531 } 531 }
532#endif /* BB_FEATURE_VI_DOT_CMD */ 532#endif /* CONFIG_FEATURE_VI_DOT_CMD */
533 do_cmd(c); // execute the user command 533 do_cmd(c); // execute the user command
534 // 534 //
535 // poll to see if there is input already waiting. if we are 535 // poll to see if there is input already waiting. if we are
@@ -540,10 +540,10 @@ static void edit_file(Byte * fn)
540 refresh(FALSE); 540 refresh(FALSE);
541 show_status_line(); 541 show_status_line();
542 } 542 }
543#ifdef BB_FEATURE_VI_CRASHME 543#ifdef CONFIG_FEATURE_VI_CRASHME
544 if (crashme > 0) 544 if (crashme > 0)
545 crash_test(); // test editor variables 545 crash_test(); // test editor variables
546#endif /* BB_FEATURE_VI_CRASHME */ 546#endif /* CONFIG_FEATURE_VI_CRASHME */
547 } 547 }
548 //------------------------------------------------------------------- 548 //-------------------------------------------------------------------
549 549
@@ -554,7 +554,7 @@ static void edit_file(Byte * fn)
554 554
555static Byte readbuffer[BUFSIZ]; 555static Byte readbuffer[BUFSIZ];
556 556
557#ifdef BB_FEATURE_VI_CRASHME 557#ifdef CONFIG_FEATURE_VI_CRASHME
558static int totalcmds = 0; 558static int totalcmds = 0;
559static int Mp = 85; // Movement command Probability 559static int Mp = 85; // Movement command Probability
560static int Np = 90; // Non-movement command Probability 560static int Np = 90; // Non-movement command Probability
@@ -756,7 +756,7 @@ static void crash_test()
756 } 756 }
757 return; 757 return;
758} 758}
759#endif /* BB_FEATURE_VI_CRASHME */ 759#endif /* CONFIG_FEATURE_VI_CRASHME */
760 760
761//--------------------------------------------------------------------- 761//---------------------------------------------------------------------
762//----- the Ascii Chart ----------------------------------------------- 762//----- the Ascii Chart -----------------------------------------------
@@ -822,11 +822,11 @@ static void do_cmd(Byte c)
822 //case 0x10: // dle 822 //case 0x10: // dle
823 //case 0x11: // dc1 823 //case 0x11: // dc1
824 //case 0x13: // dc3 824 //case 0x13: // dc3
825#ifdef BB_FEATURE_VI_CRASHME 825#ifdef CONFIG_FEATURE_VI_CRASHME
826 case 0x14: // dc4 ctrl-T 826 case 0x14: // dc4 ctrl-T
827 crashme = (crashme == 0) ? 1 : 0; 827 crashme = (crashme == 0) ? 1 : 0;
828 break; 828 break;
829#endif /* BB_FEATURE_VI_CRASHME */ 829#endif /* CONFIG_FEATURE_VI_CRASHME */
830 //case 0x16: // syn 830 //case 0x16: // syn
831 //case 0x17: // etb 831 //case 0x17: // etb
832 //case 0x18: // can 832 //case 0x18: // can
@@ -873,14 +873,14 @@ static void do_cmd(Byte c)
873 case VI_K_PAGEUP: // Cursor Key Page Up 873 case VI_K_PAGEUP: // Cursor Key Page Up
874 dot_scroll(rows - 2, -1); 874 dot_scroll(rows - 2, -1);
875 break; 875 break;
876#ifdef BB_FEATURE_VI_USE_SIGNALS 876#ifdef CONFIG_FEATURE_VI_USE_SIGNALS
877 case 0x03: // ctrl-C interrupt 877 case 0x03: // ctrl-C interrupt
878 longjmp(restart, 1); 878 longjmp(restart, 1);
879 break; 879 break;
880 case 26: // ctrl-Z suspend 880 case 26: // ctrl-Z suspend
881 suspend_sig(SIGTSTP); 881 suspend_sig(SIGTSTP);
882 break; 882 break;
883#endif /* BB_FEATURE_VI_USE_SIGNALS */ 883#endif /* CONFIG_FEATURE_VI_USE_SIGNALS */
884 case 4: // ctrl-D scroll down half screen 884 case 4: // ctrl-D scroll down half screen
885 dot_scroll((rows - 2) / 2, 1); 885 dot_scroll((rows - 2) / 2, 1);
886 break; 886 break;
@@ -949,7 +949,7 @@ static void do_cmd(Byte c)
949 } // repeat cnt 949 } // repeat cnt
950 dot_right(); 950 dot_right();
951 break; 951 break;
952#ifdef BB_FEATURE_VI_YANKMARK 952#ifdef CONFIG_FEATURE_VI_YANKMARK
953 case '"': // "- name a register to use for Delete/Yank 953 case '"': // "- name a register to use for Delete/Yank
954 c1 = get_one_char(); 954 c1 = get_one_char();
955 c1 = tolower(c1); 955 c1 = tolower(c1);
@@ -1031,7 +1031,7 @@ static void do_cmd(Byte c)
1031 dot_skip_over_ws(); 1031 dot_skip_over_ws();
1032 } 1032 }
1033 break; 1033 break;
1034#endif /* BB_FEATURE_VI_YANKMARK */ 1034#endif /* CONFIG_FEATURE_VI_YANKMARK */
1035 case '$': // $- goto end of line 1035 case '$': // $- goto end of line
1036 case VI_K_END: // Cursor Key End 1036 case VI_K_END: // Cursor Key End
1037 if (cmdcnt-- > 1) { 1037 if (cmdcnt-- > 1) {
@@ -1080,7 +1080,7 @@ static void do_cmd(Byte c)
1080 dot_prev(); 1080 dot_prev();
1081 dot_skip_over_ws(); 1081 dot_skip_over_ws();
1082 break; 1082 break;
1083#ifdef BB_FEATURE_VI_DOT_CMD 1083#ifdef CONFIG_FEATURE_VI_DOT_CMD
1084 case '.': // .- repeat the last modifying command 1084 case '.': // .- repeat the last modifying command
1085 // Stuff the last_modifying_cmd back into stdin 1085 // Stuff the last_modifying_cmd back into stdin
1086 // and let it be re-executed. 1086 // and let it be re-executed.
@@ -1088,8 +1088,8 @@ static void do_cmd(Byte c)
1088 ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd); 1088 ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd);
1089 } 1089 }
1090 break; 1090 break;
1091#endif /* BB_FEATURE_VI_DOT_CMD */ 1091#endif /* CONFIG_FEATURE_VI_DOT_CMD */
1092#ifdef BB_FEATURE_VI_SEARCH 1092#ifdef CONFIG_FEATURE_VI_SEARCH
1093 case '?': // /- search for a pattern 1093 case '?': // /- search for a pattern
1094 case '/': // /- search for a pattern 1094 case '/': // /- search for a pattern
1095 buf[0] = c; 1095 buf[0] = c;
@@ -1175,7 +1175,7 @@ static void do_cmd(Byte c)
1175 dot = next_line(q); // move to next blank line 1175 dot = next_line(q); // move to next blank line
1176 } 1176 }
1177 break; 1177 break;
1178#endif /* BB_FEATURE_VI_SEARCH */ 1178#endif /* CONFIG_FEATURE_VI_SEARCH */
1179 case '0': // 0- goto begining of line 1179 case '0': // 0- goto begining of line
1180 case '1': // 1- 1180 case '1': // 1-
1181 case '2': // 2- 1181 case '2': // 2-
@@ -1194,9 +1194,9 @@ static void do_cmd(Byte c)
1194 break; 1194 break;
1195 case ':': // :- the colon mode commands 1195 case ':': // :- the colon mode commands
1196 p = get_input_line((Byte *) ":"); // get input line- use "status line" 1196 p = get_input_line((Byte *) ":"); // get input line- use "status line"
1197#ifdef BB_FEATURE_VI_COLON 1197#ifdef CONFIG_FEATURE_VI_COLON
1198 colon(p); // execute the command 1198 colon(p); // execute the command
1199#else /* BB_FEATURE_VI_COLON */ 1199#else /* CONFIG_FEATURE_VI_COLON */
1200 if (*p == ':') 1200 if (*p == ':')
1201 p++; // move past the ':' 1201 p++; // move past the ':'
1202 cnt = strlen((char *) p); 1202 cnt = strlen((char *) p);
@@ -1225,7 +1225,7 @@ static void do_cmd(Byte c)
1225 } else { // unrecognised cmd 1225 } else { // unrecognised cmd
1226 ni((Byte *) p); 1226 ni((Byte *) p);
1227 } 1227 }
1228#endif /* BB_FEATURE_VI_COLON */ 1228#endif /* CONFIG_FEATURE_VI_COLON */
1229 break; 1229 break;
1230 case '<': // <- Left shift something 1230 case '<': // <- Left shift something
1231 case '>': // >- Right shift something 1231 case '>': // >- Right shift something
@@ -1289,10 +1289,10 @@ static void do_cmd(Byte c)
1289 dot = yank_delete(save_dot, dot, 0, YANKDEL); // delete to e-o-l 1289 dot = yank_delete(save_dot, dot, 0, YANKDEL); // delete to e-o-l
1290 if (c == 'C') 1290 if (c == 'C')
1291 goto dc_i; // start inserting 1291 goto dc_i; // start inserting
1292#ifdef BB_FEATURE_VI_DOT_CMD 1292#ifdef CONFIG_FEATURE_VI_DOT_CMD
1293 if (c == 'D') 1293 if (c == 'D')
1294 end_cmd_q(); // stop adding to q 1294 end_cmd_q(); // stop adding to q
1295#endif /* BB_FEATURE_VI_DOT_CMD */ 1295#endif /* CONFIG_FEATURE_VI_DOT_CMD */
1296 break; 1296 break;
1297 case 'G': // G- goto to a line number (default= E-O-F) 1297 case 'G': // G- goto to a line number (default= E-O-F)
1298 dot = end - 1; // assume E-O-F 1298 dot = end - 1; // assume E-O-F
@@ -1396,10 +1396,10 @@ static void do_cmd(Byte c)
1396 break; 1396 break;
1397 } 1397 }
1398 if (file_modified == TRUE 1398 if (file_modified == TRUE
1399#ifdef BB_FEATURE_VI_READONLY 1399#ifdef CONFIG_FEATURE_VI_READONLY
1400 && vi_readonly == FALSE 1400 && vi_readonly == FALSE
1401 && readonly == FALSE 1401 && readonly == FALSE
1402#endif /* BB_FEATURE_VI_READONLY */ 1402#endif /* CONFIG_FEATURE_VI_READONLY */
1403 ) { 1403 ) {
1404 cnt = file_write(cfn, text, end - 1); 1404 cnt = file_write(cfn, text, end - 1);
1405 if (cnt == (end - 1 - text + 1)) { 1405 if (cnt == (end - 1 - text + 1)) {
@@ -1435,15 +1435,15 @@ static void do_cmd(Byte c)
1435 break; 1435 break;
1436 case 'c': // c- change something 1436 case 'c': // c- change something
1437 case 'd': // d- delete something 1437 case 'd': // d- delete something
1438#ifdef BB_FEATURE_VI_YANKMARK 1438#ifdef CONFIG_FEATURE_VI_YANKMARK
1439 case 'y': // y- yank something 1439 case 'y': // y- yank something
1440 case 'Y': // Y- Yank a line 1440 case 'Y': // Y- Yank a line
1441#endif /* BB_FEATURE_VI_YANKMARK */ 1441#endif /* CONFIG_FEATURE_VI_YANKMARK */
1442 yf = YANKDEL; // assume either "c" or "d" 1442 yf = YANKDEL; // assume either "c" or "d"
1443#ifdef BB_FEATURE_VI_YANKMARK 1443#ifdef CONFIG_FEATURE_VI_YANKMARK
1444 if (c == 'y' || c == 'Y') 1444 if (c == 'y' || c == 'Y')
1445 yf = YANKONLY; 1445 yf = YANKONLY;
1446#endif /* BB_FEATURE_VI_YANKMARK */ 1446#endif /* CONFIG_FEATURE_VI_YANKMARK */
1447 c1 = 'y'; 1447 c1 = 'y';
1448 if (c != 'Y') 1448 if (c != 'Y')
1449 c1 = get_one_char(); // get the type of thing to delete 1449 c1 = get_one_char(); // get the type of thing to delete
@@ -1490,7 +1490,7 @@ static void do_cmd(Byte c)
1490 if (c == 'd') { 1490 if (c == 'd') {
1491 strcpy((char *) buf, "Delete"); 1491 strcpy((char *) buf, "Delete");
1492 } 1492 }
1493#ifdef BB_FEATURE_VI_YANKMARK 1493#ifdef CONFIG_FEATURE_VI_YANKMARK
1494 if (c == 'y' || c == 'Y') { 1494 if (c == 'y' || c == 'Y') {
1495 strcpy((char *) buf, "Yank"); 1495 strcpy((char *) buf, "Yank");
1496 } 1496 }
@@ -1502,7 +1502,7 @@ static void do_cmd(Byte c)
1502 } 1502 }
1503 psb("%s %d lines (%d chars) using [%c]", 1503 psb("%s %d lines (%d chars) using [%c]",
1504 buf, cnt, strlen((char *) reg[YDreg]), what_reg()); 1504 buf, cnt, strlen((char *) reg[YDreg]), what_reg());
1505#endif /* BB_FEATURE_VI_YANKMARK */ 1505#endif /* CONFIG_FEATURE_VI_YANKMARK */
1506 end_cmd_q(); // stop adding to q 1506 end_cmd_q(); // stop adding to q
1507 } 1507 }
1508 break; 1508 break;
@@ -1601,9 +1601,9 @@ static void do_cmd(Byte c)
1601 if (dot != end) { 1601 if (dot != end) {
1602 dot = bound_dot(dot); // make sure "dot" is valid 1602 dot = bound_dot(dot); // make sure "dot" is valid
1603 } 1603 }
1604#ifdef BB_FEATURE_VI_YANKMARK 1604#ifdef CONFIG_FEATURE_VI_YANKMARK
1605 check_context(c); // update the current context 1605 check_context(c); // update the current context
1606#endif /* BB_FEATURE_VI_YANKMARK */ 1606#endif /* CONFIG_FEATURE_VI_YANKMARK */
1607 1607
1608 if (!isdigit(c)) 1608 if (!isdigit(c))
1609 cmdcnt = 0; // cmd was not a number, reset cmdcnt 1609 cmdcnt = 0; // cmd was not a number, reset cmdcnt
@@ -1614,25 +1614,25 @@ static void do_cmd(Byte c)
1614} 1614}
1615 1615
1616//----- The Colon commands ------------------------------------- 1616//----- The Colon commands -------------------------------------
1617#ifdef BB_FEATURE_VI_COLON 1617#ifdef CONFIG_FEATURE_VI_COLON
1618static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present 1618static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present
1619{ 1619{
1620 int st; 1620 int st;
1621 Byte *q; 1621 Byte *q;
1622 1622
1623#ifdef BB_FEATURE_VI_YANKMARK 1623#ifdef CONFIG_FEATURE_VI_YANKMARK
1624 Byte c; 1624 Byte c;
1625#endif /* BB_FEATURE_VI_YANKMARK */ 1625#endif /* CONFIG_FEATURE_VI_YANKMARK */
1626#ifdef BB_FEATURE_VI_SEARCH 1626#ifdef CONFIG_FEATURE_VI_SEARCH
1627 Byte *pat, buf[BUFSIZ]; 1627 Byte *pat, buf[BUFSIZ];
1628#endif /* BB_FEATURE_VI_SEARCH */ 1628#endif /* CONFIG_FEATURE_VI_SEARCH */
1629 1629
1630 *addr = -1; // assume no addr 1630 *addr = -1; // assume no addr
1631 if (*p == '.') { // the current line 1631 if (*p == '.') { // the current line
1632 p++; 1632 p++;
1633 q = begin_line(dot); 1633 q = begin_line(dot);
1634 *addr = count_lines(text, q); 1634 *addr = count_lines(text, q);
1635#ifdef BB_FEATURE_VI_YANKMARK 1635#ifdef CONFIG_FEATURE_VI_YANKMARK
1636 } else if (*p == '\'') { // is this a mark addr 1636 } else if (*p == '\'') { // is this a mark addr
1637 p++; 1637 p++;
1638 c = tolower(*p); 1638 c = tolower(*p);
@@ -1645,8 +1645,8 @@ static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present
1645 *addr = count_lines(text, q); // count lines 1645 *addr = count_lines(text, q); // count lines
1646 } 1646 }
1647 } 1647 }
1648#endif /* BB_FEATURE_VI_YANKMARK */ 1648#endif /* CONFIG_FEATURE_VI_YANKMARK */
1649#ifdef BB_FEATURE_VI_SEARCH 1649#ifdef CONFIG_FEATURE_VI_SEARCH
1650 } else if (*p == '/') { // a search pattern 1650 } else if (*p == '/') { // a search pattern
1651 q = buf; 1651 q = buf;
1652 for (p++; *p; p++) { 1652 for (p++; *p; p++) {
@@ -1663,7 +1663,7 @@ static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present
1663 *addr = count_lines(text, q); 1663 *addr = count_lines(text, q);
1664 } 1664 }
1665 free(pat); 1665 free(pat);
1666#endif /* BB_FEATURE_VI_SEARCH */ 1666#endif /* CONFIG_FEATURE_VI_SEARCH */
1667 } else if (*p == '$') { // the last line in file 1667 } else if (*p == '$') { // the last line in file
1668 p++; 1668 p++;
1669 q = begin_line(end - 1); 1669 q = begin_line(end - 1);
@@ -1871,7 +1871,7 @@ static void colon(Byte * buf)
1871 ch= 1; 1871 ch= 1;
1872 } 1872 }
1873 file_modified = FALSE; 1873 file_modified = FALSE;
1874#ifdef BB_FEATURE_VI_YANKMARK 1874#ifdef CONFIG_FEATURE_VI_YANKMARK
1875 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { 1875 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
1876 free(reg[Ureg]); // free orig line reg- for 'U' 1876 free(reg[Ureg]); // free orig line reg- for 'U'
1877 reg[Ureg]= 0; 1877 reg[Ureg]= 0;
@@ -1883,18 +1883,18 @@ static void colon(Byte * buf)
1883 for (li = 0; li < 28; li++) { 1883 for (li = 0; li < 28; li++) {
1884 mark[li] = 0; 1884 mark[li] = 0;
1885 } // init the marks 1885 } // init the marks
1886#endif /* BB_FEATURE_VI_YANKMARK */ 1886#endif /* CONFIG_FEATURE_VI_YANKMARK */
1887 // how many lines in text[]? 1887 // how many lines in text[]?
1888 li = count_lines(text, end - 1); 1888 li = count_lines(text, end - 1);
1889 psb("\"%s\"%s" 1889 psb("\"%s\"%s"
1890#ifdef BB_FEATURE_VI_READONLY 1890#ifdef CONFIG_FEATURE_VI_READONLY
1891 "%s" 1891 "%s"
1892#endif /* BB_FEATURE_VI_READONLY */ 1892#endif /* CONFIG_FEATURE_VI_READONLY */
1893 " %dL, %dC", cfn, 1893 " %dL, %dC", cfn,
1894 (sr < 0 ? " [New file]" : ""), 1894 (sr < 0 ? " [New file]" : ""),
1895#ifdef BB_FEATURE_VI_READONLY 1895#ifdef CONFIG_FEATURE_VI_READONLY
1896 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), 1896 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
1897#endif /* BB_FEATURE_VI_READONLY */ 1897#endif /* CONFIG_FEATURE_VI_READONLY */
1898 li, ch); 1898 li, ch);
1899 } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this 1899 } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
1900 if (b != -1 || e != -1) { 1900 if (b != -1 || e != -1) {
@@ -1940,9 +1940,9 @@ static void colon(Byte * buf)
1940 if (c > '~') 1940 if (c > '~')
1941 standout_end(); 1941 standout_end();
1942 } 1942 }
1943#ifdef BB_FEATURE_VI_SET 1943#ifdef CONFIG_FEATURE_VI_SET
1944 vc2: 1944 vc2:
1945#endif /* BB_FEATURE_VI_SET */ 1945#endif /* CONFIG_FEATURE_VI_SET */
1946 Hit_Return(); 1946 Hit_Return();
1947 } else if ((strncasecmp((char *) cmd, "quit", i) == 0) || // Quit 1947 } else if ((strncasecmp((char *) cmd, "quit", i) == 0) || // Quit
1948 (strncasecmp((char *) cmd, "next", i) == 0)) { // edit next file 1948 (strncasecmp((char *) cmd, "next", i) == 0)) { // edit next file
@@ -1982,11 +1982,11 @@ static void colon(Byte * buf)
1982 // read after current line- unless user said ":0r foo" 1982 // read after current line- unless user said ":0r foo"
1983 if (b != 0) 1983 if (b != 0)
1984 q = next_line(q); 1984 q = next_line(q);
1985#ifdef BB_FEATURE_VI_READONLY 1985#ifdef CONFIG_FEATURE_VI_READONLY
1986 l= readonly; // remember current files' status 1986 l= readonly; // remember current files' status
1987#endif 1987#endif
1988 ch = file_insert(fn, q, file_size(fn)); 1988 ch = file_insert(fn, q, file_size(fn));
1989#ifdef BB_FEATURE_VI_READONLY 1989#ifdef CONFIG_FEATURE_VI_READONLY
1990 readonly= l; 1990 readonly= l;
1991#endif 1991#endif
1992 if (ch < 0) 1992 if (ch < 0)
@@ -1994,13 +1994,13 @@ static void colon(Byte * buf)
1994 // how many lines in text[]? 1994 // how many lines in text[]?
1995 li = count_lines(q, q + ch - 1); 1995 li = count_lines(q, q + ch - 1);
1996 psb("\"%s\"" 1996 psb("\"%s\""
1997#ifdef BB_FEATURE_VI_READONLY 1997#ifdef CONFIG_FEATURE_VI_READONLY
1998 "%s" 1998 "%s"
1999#endif /* BB_FEATURE_VI_READONLY */ 1999#endif /* CONFIG_FEATURE_VI_READONLY */
2000 " %dL, %dC", fn, 2000 " %dL, %dC", fn,
2001#ifdef BB_FEATURE_VI_READONLY 2001#ifdef CONFIG_FEATURE_VI_READONLY
2002 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), 2002 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
2003#endif /* BB_FEATURE_VI_READONLY */ 2003#endif /* CONFIG_FEATURE_VI_READONLY */
2004 li, ch); 2004 li, ch);
2005 if (ch > 0) { 2005 if (ch > 0) {
2006 // if the insert is before "dot" then we need to update 2006 // if the insert is before "dot" then we need to update
@@ -2016,7 +2016,7 @@ static void colon(Byte * buf)
2016 optind = fn_start - 1; 2016 optind = fn_start - 1;
2017 editing = 0; 2017 editing = 0;
2018 } 2018 }
2019#ifdef BB_FEATURE_VI_SET 2019#ifdef CONFIG_FEATURE_VI_SET
2020 } else if (strncasecmp((char *) cmd, "set", i) == 0) { // set or clear features 2020 } else if (strncasecmp((char *) cmd, "set", i) == 0) { // set or clear features
2021 i = 0; // offset into args 2021 i = 0; // offset into args
2022 if (strlen((char *) args) == 0) { 2022 if (strlen((char *) args) == 0) {
@@ -2024,7 +2024,7 @@ static void colon(Byte * buf)
2024 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen 2024 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
2025 clear_to_eol(); // clear the line 2025 clear_to_eol(); // clear the line
2026 printf("----------------------------------------\r\n"); 2026 printf("----------------------------------------\r\n");
2027#ifdef BB_FEATURE_VI_SETOPTS 2027#ifdef CONFIG_FEATURE_VI_SETOPTS
2028 if (!autoindent) 2028 if (!autoindent)
2029 printf("no"); 2029 printf("no");
2030 printf("autoindent "); 2030 printf("autoindent ");
@@ -2038,13 +2038,13 @@ static void colon(Byte * buf)
2038 printf("no"); 2038 printf("no");
2039 printf("showmatch "); 2039 printf("showmatch ");
2040 printf("tabstop=%d ", tabstop); 2040 printf("tabstop=%d ", tabstop);
2041#endif /* BB_FEATURE_VI_SETOPTS */ 2041#endif /* CONFIG_FEATURE_VI_SETOPTS */
2042 printf("\r\n"); 2042 printf("\r\n");
2043 goto vc2; 2043 goto vc2;
2044 } 2044 }
2045 if (strncasecmp((char *) args, "no", 2) == 0) 2045 if (strncasecmp((char *) args, "no", 2) == 0)
2046 i = 2; // ":set noautoindent" 2046 i = 2; // ":set noautoindent"
2047#ifdef BB_FEATURE_VI_SETOPTS 2047#ifdef CONFIG_FEATURE_VI_SETOPTS
2048 if (strncasecmp((char *) args + i, "autoindent", 10) == 0 || 2048 if (strncasecmp((char *) args + i, "autoindent", 10) == 0 ||
2049 strncasecmp((char *) args + i, "ai", 2) == 0) { 2049 strncasecmp((char *) args + i, "ai", 2) == 0) {
2050 autoindent = (i == 2) ? 0 : 1; 2050 autoindent = (i == 2) ? 0 : 1;
@@ -2066,9 +2066,9 @@ static void colon(Byte * buf)
2066 if (ch > 0 && ch < columns - 1) 2066 if (ch > 0 && ch < columns - 1)
2067 tabstop = ch; 2067 tabstop = ch;
2068 } 2068 }
2069#endif /* BB_FEATURE_VI_SETOPTS */ 2069#endif /* CONFIG_FEATURE_VI_SETOPTS */
2070#endif /* BB_FEATURE_VI_SET */ 2070#endif /* CONFIG_FEATURE_VI_SET */
2071#ifdef BB_FEATURE_VI_SEARCH 2071#ifdef CONFIG_FEATURE_VI_SEARCH
2072 } else if (strncasecmp((char *) cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern 2072 } else if (strncasecmp((char *) cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern
2073 Byte *ls, *F, *R; 2073 Byte *ls, *F, *R;
2074 int gflag; 2074 int gflag;
@@ -2115,7 +2115,7 @@ static void colon(Byte * buf)
2115 } 2115 }
2116 q = next_line(ls); 2116 q = next_line(ls);
2117 } 2117 }
2118#endif /* BB_FEATURE_VI_SEARCH */ 2118#endif /* CONFIG_FEATURE_VI_SEARCH */
2119 } else if (strncasecmp((char *) cmd, "version", i) == 0) { // show software version 2119 } else if (strncasecmp((char *) cmd, "version", i) == 0) { // show software version
2120 psb("%s", vi_Version); 2120 psb("%s", vi_Version);
2121 } else if ((strncasecmp((char *) cmd, "write", i) == 0) || // write text to file 2121 } else if ((strncasecmp((char *) cmd, "write", i) == 0) || // write text to file
@@ -2124,12 +2124,12 @@ static void colon(Byte * buf)
2124 if (strlen((char *) args) > 0) { 2124 if (strlen((char *) args) > 0) {
2125 fn = args; 2125 fn = args;
2126 } 2126 }
2127#ifdef BB_FEATURE_VI_READONLY 2127#ifdef CONFIG_FEATURE_VI_READONLY
2128 if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) { 2128 if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) {
2129 psbs("\"%s\" File is read only", fn); 2129 psbs("\"%s\" File is read only", fn);
2130 goto vc3; 2130 goto vc3;
2131 } 2131 }
2132#endif /* BB_FEATURE_VI_READONLY */ 2132#endif /* CONFIG_FEATURE_VI_READONLY */
2133 // how many lines in text[]? 2133 // how many lines in text[]?
2134 li = count_lines(q, r); 2134 li = count_lines(q, r);
2135 ch = r - q + 1; 2135 ch = r - q + 1;
@@ -2153,10 +2153,10 @@ static void colon(Byte * buf)
2153 if (cmd[1] == 'q' && l == ch) { 2153 if (cmd[1] == 'q' && l == ch) {
2154 editing = 0; 2154 editing = 0;
2155 } 2155 }
2156#ifdef BB_FEATURE_VI_READONLY 2156#ifdef CONFIG_FEATURE_VI_READONLY
2157 vc3:; 2157 vc3:;
2158#endif /* BB_FEATURE_VI_READONLY */ 2158#endif /* CONFIG_FEATURE_VI_READONLY */
2159#ifdef BB_FEATURE_VI_YANKMARK 2159#ifdef CONFIG_FEATURE_VI_YANKMARK
2160 } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines 2160 } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines
2161 if (b < 0) { // no addr given- use defaults 2161 if (b < 0) { // no addr given- use defaults
2162 q = begin_line(dot); // assume .,. for the range 2162 q = begin_line(dot); // assume .,. for the range
@@ -2166,7 +2166,7 @@ static void colon(Byte * buf)
2166 li = count_lines(q, r); 2166 li = count_lines(q, r);
2167 psb("Yank %d lines (%d chars) into [%c]", 2167 psb("Yank %d lines (%d chars) into [%c]",
2168 li, strlen((char *) reg[YDreg]), what_reg()); 2168 li, strlen((char *) reg[YDreg]), what_reg());
2169#endif /* BB_FEATURE_VI_YANKMARK */ 2169#endif /* CONFIG_FEATURE_VI_YANKMARK */
2170 } else { 2170 } else {
2171 // cmd unknown 2171 // cmd unknown
2172 ni((Byte *) cmd); 2172 ni((Byte *) cmd);
@@ -2174,7 +2174,7 @@ static void colon(Byte * buf)
2174 vc1: 2174 vc1:
2175 dot = bound_dot(dot); // make sure "dot" is valid 2175 dot = bound_dot(dot); // make sure "dot" is valid
2176 return; 2176 return;
2177#ifdef BB_FEATURE_VI_SEARCH 2177#ifdef CONFIG_FEATURE_VI_SEARCH
2178colon_s_fail: 2178colon_s_fail:
2179 psb(":s expression missing delimiters"); 2179 psb(":s expression missing delimiters");
2180 return; 2180 return;
@@ -2193,7 +2193,7 @@ static void Hit_Return(void)
2193 ; 2193 ;
2194 redraw(TRUE); // force redraw all 2194 redraw(TRUE); // force redraw all
2195} 2195}
2196#endif /* BB_FEATURE_VI_COLON */ 2196#endif /* CONFIG_FEATURE_VI_COLON */
2197 2197
2198//----- Synchronize the cursor to Dot -------------------------- 2198//----- Synchronize the cursor to Dot --------------------------
2199static void sync_cursor(Byte * d, int *row, int *col) 2199static void sync_cursor(Byte * d, int *row, int *col)
@@ -2518,17 +2518,17 @@ static Byte *new_text(int size)
2518 return (text); 2518 return (text);
2519} 2519}
2520 2520
2521#ifdef BB_FEATURE_VI_SEARCH 2521#ifdef CONFIG_FEATURE_VI_SEARCH
2522static int mycmp(Byte * s1, Byte * s2, int len) 2522static int mycmp(Byte * s1, Byte * s2, int len)
2523{ 2523{
2524 int i; 2524 int i;
2525 2525
2526 i = strncmp((char *) s1, (char *) s2, len); 2526 i = strncmp((char *) s1, (char *) s2, len);
2527#ifdef BB_FEATURE_VI_SETOPTS 2527#ifdef CONFIG_FEATURE_VI_SETOPTS
2528 if (ignorecase) { 2528 if (ignorecase) {
2529 i = strncasecmp((char *) s1, (char *) s2, len); 2529 i = strncasecmp((char *) s1, (char *) s2, len);
2530 } 2530 }
2531#endif /* BB_FEATURE_VI_SETOPTS */ 2531#endif /* CONFIG_FEATURE_VI_SETOPTS */
2532 return (i); 2532 return (i);
2533} 2533}
2534 2534
@@ -2623,7 +2623,7 @@ static Byte *char_search(Byte * p, Byte * pat, int dir, int range) // search for
2623 return (p); 2623 return (p);
2624#endif /*REGEX_SEARCH */ 2624#endif /*REGEX_SEARCH */
2625} 2625}
2626#endif /* BB_FEATURE_VI_SEARCH */ 2626#endif /* CONFIG_FEATURE_VI_SEARCH */
2627 2627
2628static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p' 2628static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
2629{ 2629{
@@ -2648,7 +2648,7 @@ static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
2648 if ((p[-1] != '\n') && (dot>text)) { 2648 if ((p[-1] != '\n') && (dot>text)) {
2649 p--; 2649 p--;
2650 p = text_hole_delete(p, p); // shrink buffer 1 char 2650 p = text_hole_delete(p, p); // shrink buffer 1 char
2651#ifdef BB_FEATURE_VI_DOT_CMD 2651#ifdef CONFIG_FEATURE_VI_DOT_CMD
2652 // also rmove char from last_modifying_cmd 2652 // also rmove char from last_modifying_cmd
2653 if (strlen((char *) last_modifying_cmd) > 0) { 2653 if (strlen((char *) last_modifying_cmd) > 0) {
2654 Byte *q; 2654 Byte *q;
@@ -2657,7 +2657,7 @@ static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
2657 q[strlen((char *) q) - 1] = '\0'; // erase BS 2657 q[strlen((char *) q) - 1] = '\0'; // erase BS
2658 q[strlen((char *) q) - 1] = '\0'; // erase prev char 2658 q[strlen((char *) q) - 1] = '\0'; // erase prev char
2659 } 2659 }
2660#endif /* BB_FEATURE_VI_DOT_CMD */ 2660#endif /* CONFIG_FEATURE_VI_DOT_CMD */
2661 } 2661 }
2662 } else { 2662 } else {
2663 // insert a char into text[] 2663 // insert a char into text[]
@@ -2667,7 +2667,7 @@ static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
2667 c = '\n'; // translate \r to \n 2667 c = '\n'; // translate \r to \n
2668 sp = p; // remember addr of insert 2668 sp = p; // remember addr of insert
2669 p = stupid_insert(p, c); // insert the char 2669 p = stupid_insert(p, c); // insert the char
2670#ifdef BB_FEATURE_VI_SETOPTS 2670#ifdef CONFIG_FEATURE_VI_SETOPTS
2671 if (showmatch && strchr(")]}", *sp) != NULL) { 2671 if (showmatch && strchr(")]}", *sp) != NULL) {
2672 showmatching(sp); 2672 showmatching(sp);
2673 } 2673 }
@@ -2679,7 +2679,7 @@ static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
2679 p = stupid_insert(p, *q); // insert the char 2679 p = stupid_insert(p, *q); // insert the char
2680 } 2680 }
2681 } 2681 }
2682#endif /* BB_FEATURE_VI_SETOPTS */ 2682#endif /* CONFIG_FEATURE_VI_SETOPTS */
2683 } 2683 }
2684 return (p); 2684 return (p);
2685} 2685}
@@ -2844,7 +2844,7 @@ static Byte *find_pair(Byte * p, Byte c)
2844 return (q); 2844 return (q);
2845} 2845}
2846 2846
2847#ifdef BB_FEATURE_VI_SETOPTS 2847#ifdef CONFIG_FEATURE_VI_SETOPTS
2848// show the matching char of a pair, () [] {} 2848// show the matching char of a pair, () [] {}
2849static void showmatching(Byte * p) 2849static void showmatching(Byte * p)
2850{ 2850{
@@ -2864,7 +2864,7 @@ static void showmatching(Byte * p)
2864 refresh(FALSE); 2864 refresh(FALSE);
2865 } 2865 }
2866} 2866}
2867#endif /* BB_FEATURE_VI_SETOPTS */ 2867#endif /* CONFIG_FEATURE_VI_SETOPTS */
2868 2868
2869// open a hole in text[] 2869// open a hole in text[]
2870static Byte *text_hole_make(Byte * p, int size) // at "p", make a 'size' byte hole 2870static Byte *text_hole_make(Byte * p, int size) // at "p", make a 'size' byte hole
@@ -2951,9 +2951,9 @@ static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf)
2951 } 2951 }
2952 } 2952 }
2953 p = start; 2953 p = start;
2954#ifdef BB_FEATURE_VI_YANKMARK 2954#ifdef CONFIG_FEATURE_VI_YANKMARK
2955 text_yank(start, stop, YDreg); 2955 text_yank(start, stop, YDreg);
2956#endif /* BB_FEATURE_VI_YANKMARK */ 2956#endif /* CONFIG_FEATURE_VI_YANKMARK */
2957 if (yf == YANKDEL) { 2957 if (yf == YANKDEL) {
2958 p = text_hole_delete(start, stop); 2958 p = text_hole_delete(start, stop);
2959 } // delete lines 2959 } // delete lines
@@ -2963,33 +2963,33 @@ static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf)
2963static void show_help(void) 2963static void show_help(void)
2964{ 2964{
2965 puts("These features are available:" 2965 puts("These features are available:"
2966#ifdef BB_FEATURE_VI_SEARCH 2966#ifdef CONFIG_FEATURE_VI_SEARCH
2967 "\n\tPattern searches with / and ?" 2967 "\n\tPattern searches with / and ?"
2968#endif /* BB_FEATURE_VI_SEARCH */ 2968#endif /* CONFIG_FEATURE_VI_SEARCH */
2969#ifdef BB_FEATURE_VI_DOT_CMD 2969#ifdef CONFIG_FEATURE_VI_DOT_CMD
2970 "\n\tLast command repeat with \'.\'" 2970 "\n\tLast command repeat with \'.\'"
2971#endif /* BB_FEATURE_VI_DOT_CMD */ 2971#endif /* CONFIG_FEATURE_VI_DOT_CMD */
2972#ifdef BB_FEATURE_VI_YANKMARK 2972#ifdef CONFIG_FEATURE_VI_YANKMARK
2973 "\n\tLine marking with 'x" 2973 "\n\tLine marking with 'x"
2974 "\n\tNamed buffers with \"x" 2974 "\n\tNamed buffers with \"x"
2975#endif /* BB_FEATURE_VI_YANKMARK */ 2975#endif /* CONFIG_FEATURE_VI_YANKMARK */
2976#ifdef BB_FEATURE_VI_READONLY 2976#ifdef CONFIG_FEATURE_VI_READONLY
2977 "\n\tReadonly if vi is called as \"view\"" 2977 "\n\tReadonly if vi is called as \"view\""
2978 "\n\tReadonly with -R command line arg" 2978 "\n\tReadonly with -R command line arg"
2979#endif /* BB_FEATURE_VI_READONLY */ 2979#endif /* CONFIG_FEATURE_VI_READONLY */
2980#ifdef BB_FEATURE_VI_SET 2980#ifdef CONFIG_FEATURE_VI_SET
2981 "\n\tSome colon mode commands with \':\'" 2981 "\n\tSome colon mode commands with \':\'"
2982#endif /* BB_FEATURE_VI_SET */ 2982#endif /* CONFIG_FEATURE_VI_SET */
2983#ifdef BB_FEATURE_VI_SETOPTS 2983#ifdef CONFIG_FEATURE_VI_SETOPTS
2984 "\n\tSettable options with \":set\"" 2984 "\n\tSettable options with \":set\""
2985#endif /* BB_FEATURE_VI_SETOPTS */ 2985#endif /* CONFIG_FEATURE_VI_SETOPTS */
2986#ifdef BB_FEATURE_VI_USE_SIGNALS 2986#ifdef CONFIG_FEATURE_VI_USE_SIGNALS
2987 "\n\tSignal catching- ^C" 2987 "\n\tSignal catching- ^C"
2988 "\n\tJob suspend and resume with ^Z" 2988 "\n\tJob suspend and resume with ^Z"
2989#endif /* BB_FEATURE_VI_USE_SIGNALS */ 2989#endif /* CONFIG_FEATURE_VI_USE_SIGNALS */
2990#ifdef BB_FEATURE_VI_WIN_RESIZE 2990#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
2991 "\n\tAdapt to window re-sizes" 2991 "\n\tAdapt to window re-sizes"
2992#endif /* BB_FEATURE_VI_WIN_RESIZE */ 2992#endif /* CONFIG_FEATURE_VI_WIN_RESIZE */
2993 ); 2993 );
2994} 2994}
2995 2995
@@ -3021,7 +3021,7 @@ static void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprin
3021 } 3021 }
3022} 3022}
3023 3023
3024#ifdef BB_FEATURE_VI_DOT_CMD 3024#ifdef CONFIG_FEATURE_VI_DOT_CMD
3025static void start_new_cmd_q(Byte c) 3025static void start_new_cmd_q(Byte c)
3026{ 3026{
3027 // release old cmd 3027 // release old cmd
@@ -3041,15 +3041,15 @@ static void start_new_cmd_q(Byte c)
3041 3041
3042static void end_cmd_q() 3042static void end_cmd_q()
3043{ 3043{
3044#ifdef BB_FEATURE_VI_YANKMARK 3044#ifdef CONFIG_FEATURE_VI_YANKMARK
3045 YDreg = 26; // go back to default Yank/Delete reg 3045 YDreg = 26; // go back to default Yank/Delete reg
3046#endif /* BB_FEATURE_VI_YANKMARK */ 3046#endif /* CONFIG_FEATURE_VI_YANKMARK */
3047 adding2q = 0; 3047 adding2q = 0;
3048 return; 3048 return;
3049} 3049}
3050#endif /* BB_FEATURE_VI_DOT_CMD */ 3050#endif /* CONFIG_FEATURE_VI_DOT_CMD */
3051 3051
3052#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) 3052#if defined(CONFIG_FEATURE_VI_YANKMARK) || defined(CONFIG_FEATURE_VI_COLON) || defined(CONFIG_FEATURE_VI_CRASHME)
3053static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p' 3053static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p'
3054{ 3054{
3055 int cnt, i; 3055 int cnt, i;
@@ -3061,14 +3061,14 @@ static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p'
3061 if (*s == '\n') 3061 if (*s == '\n')
3062 cnt++; 3062 cnt++;
3063 } 3063 }
3064#ifdef BB_FEATURE_VI_YANKMARK 3064#ifdef CONFIG_FEATURE_VI_YANKMARK
3065 psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); 3065 psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
3066#endif /* BB_FEATURE_VI_YANKMARK */ 3066#endif /* CONFIG_FEATURE_VI_YANKMARK */
3067 return (p); 3067 return (p);
3068} 3068}
3069#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ 3069#endif /* CONFIG_FEATURE_VI_YANKMARK || CONFIG_FEATURE_VI_COLON || CONFIG_FEATURE_VI_CRASHME */
3070 3070
3071#ifdef BB_FEATURE_VI_YANKMARK 3071#ifdef CONFIG_FEATURE_VI_YANKMARK
3072static Byte *text_yank(Byte * p, Byte * q, int dest) // copy text into a register 3072static Byte *text_yank(Byte * p, Byte * q, int dest) // copy text into a register
3073{ 3073{
3074 Byte *t; 3074 Byte *t;
@@ -3142,7 +3142,7 @@ static Byte *swap_context(Byte * p) // goto new context for '' command make this
3142 } 3142 }
3143 return (p); 3143 return (p);
3144} 3144}
3145#endif /* BB_FEATURE_VI_YANKMARK */ 3145#endif /* CONFIG_FEATURE_VI_YANKMARK */
3146 3146
3147static int isblnk(Byte c) // is the char a blank or tab 3147static int isblnk(Byte c) // is the char a blank or tab
3148{ 3148{
@@ -3170,7 +3170,7 @@ static void cookmode(void)
3170 tcsetattr(0, TCSANOW, &term_orig); 3170 tcsetattr(0, TCSANOW, &term_orig);
3171} 3171}
3172 3172
3173#ifdef BB_FEATURE_VI_WIN_RESIZE 3173#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
3174//----- See what the window size currently is -------------------- 3174//----- See what the window size currently is --------------------
3175static void window_size_get(int sig) 3175static void window_size_get(int sig)
3176{ 3176{
@@ -3191,16 +3191,16 @@ static void window_size_get(int sig)
3191 rows = (int) winsize.ws_row; 3191 rows = (int) winsize.ws_row;
3192 columns = (int) winsize.ws_col; 3192 columns = (int) winsize.ws_col;
3193} 3193}
3194#endif /* BB_FEATURE_VI_WIN_RESIZE */ 3194#endif /* CONFIG_FEATURE_VI_WIN_RESIZE */
3195 3195
3196//----- Come here when we get a window resize signal --------- 3196//----- Come here when we get a window resize signal ---------
3197#ifdef BB_FEATURE_VI_USE_SIGNALS 3197#ifdef CONFIG_FEATURE_VI_USE_SIGNALS
3198static void winch_sig(int sig) 3198static void winch_sig(int sig)
3199{ 3199{
3200 signal(SIGWINCH, winch_sig); 3200 signal(SIGWINCH, winch_sig);
3201#ifdef BB_FEATURE_VI_WIN_RESIZE 3201#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
3202 window_size_get(0); 3202 window_size_get(0);
3203#endif /* BB_FEATURE_VI_WIN_RESIZE */ 3203#endif /* CONFIG_FEATURE_VI_WIN_RESIZE */
3204 new_screen(rows, columns); // get memory for virtual screen 3204 new_screen(rows, columns); // get memory for virtual screen
3205 redraw(TRUE); // re-draw the screen 3205 redraw(TRUE); // re-draw the screen
3206} 3206}
@@ -3263,7 +3263,7 @@ static void core_sig(int sig)
3263 3263
3264 longjmp(restart, sig); 3264 longjmp(restart, sig);
3265} 3265}
3266#endif /* BB_FEATURE_VI_USE_SIGNALS */ 3266#endif /* CONFIG_FEATURE_VI_USE_SIGNALS */
3267 3267
3268static int mysleep(int hund) // sleep for 'h' 1/100 seconds 3268static int mysleep(int hund) // sleep for 'h' 1/100 seconds
3269{ 3269{
@@ -3396,7 +3396,7 @@ static Byte get_one_char()
3396{ 3396{
3397 static Byte c; 3397 static Byte c;
3398 3398
3399#ifdef BB_FEATURE_VI_DOT_CMD 3399#ifdef CONFIG_FEATURE_VI_DOT_CMD
3400 // ! adding2q && ioq == 0 read() 3400 // ! adding2q && ioq == 0 read()
3401 // ! adding2q && ioq != 0 *ioq 3401 // ! adding2q && ioq != 0 *ioq
3402 // adding2q *last_modifying_cmd= read() 3402 // adding2q *last_modifying_cmd= read()
@@ -3424,9 +3424,9 @@ static Byte get_one_char()
3424 last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c; 3424 last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c;
3425 } 3425 }
3426 } 3426 }
3427#else /* BB_FEATURE_VI_DOT_CMD */ 3427#else /* CONFIG_FEATURE_VI_DOT_CMD */
3428 c = readit(); // get the users input 3428 c = readit(); // get the users input
3429#endif /* BB_FEATURE_VI_DOT_CMD */ 3429#endif /* CONFIG_FEATURE_VI_DOT_CMD */
3430 return (c); // return the char, where ever it came from 3430 return (c); // return the char, where ever it came from
3431} 3431}
3432 3432
@@ -3489,9 +3489,9 @@ static int file_insert(Byte * fn, Byte * p, int size)
3489 int fd, cnt; 3489 int fd, cnt;
3490 3490
3491 cnt = -1; 3491 cnt = -1;
3492#ifdef BB_FEATURE_VI_READONLY 3492#ifdef CONFIG_FEATURE_VI_READONLY
3493 readonly = FALSE; 3493 readonly = FALSE;
3494#endif /* BB_FEATURE_VI_READONLY */ 3494#endif /* CONFIG_FEATURE_VI_READONLY */
3495 if (fn == 0 || strlen((char*) fn) <= 0) { 3495 if (fn == 0 || strlen((char*) fn) <= 0) {
3496 psbs("No filename given"); 3496 psbs("No filename given");
3497 goto fi0; 3497 goto fi0;
@@ -3511,13 +3511,13 @@ static int file_insert(Byte * fn, Byte * p, int size)
3511 } 3511 }
3512 3512
3513 // see if we can open the file 3513 // see if we can open the file
3514#ifdef BB_FEATURE_VI_READONLY 3514#ifdef CONFIG_FEATURE_VI_READONLY
3515 if (vi_readonly == TRUE) goto fi1; // do not try write-mode 3515 if (vi_readonly == TRUE) goto fi1; // do not try write-mode
3516#endif 3516#endif
3517 fd = open((char *) fn, O_RDWR); // assume read & write 3517 fd = open((char *) fn, O_RDWR); // assume read & write
3518 if (fd < 0) { 3518 if (fd < 0) {
3519 // could not open for writing- maybe file is read only 3519 // could not open for writing- maybe file is read only
3520#ifdef BB_FEATURE_VI_READONLY 3520#ifdef CONFIG_FEATURE_VI_READONLY
3521 fi1: 3521 fi1:
3522#endif 3522#endif
3523 fd = open((char *) fn, O_RDONLY); // try read-only 3523 fd = open((char *) fn, O_RDONLY); // try read-only
@@ -3525,10 +3525,10 @@ static int file_insert(Byte * fn, Byte * p, int size)
3525 psbs("\"%s\" %s", fn, "could not open file"); 3525 psbs("\"%s\" %s", fn, "could not open file");
3526 goto fi0; 3526 goto fi0;
3527 } 3527 }
3528#ifdef BB_FEATURE_VI_READONLY 3528#ifdef CONFIG_FEATURE_VI_READONLY
3529 // got the file- read-only 3529 // got the file- read-only
3530 readonly = TRUE; 3530 readonly = TRUE;
3531#endif /* BB_FEATURE_VI_READONLY */ 3531#endif /* CONFIG_FEATURE_VI_READONLY */
3532 } 3532 }
3533 p = text_hole_make(p, size); 3533 p = text_hole_make(p, size);
3534 cnt = read(fd, p, size); 3534 cnt = read(fd, p, size);
@@ -3591,12 +3591,12 @@ static void place_cursor(int row, int col, int opti)
3591 char cm1[BUFSIZ]; 3591 char cm1[BUFSIZ];
3592 char *cm; 3592 char *cm;
3593 int l; 3593 int l;
3594#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR 3594#ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
3595 char cm2[BUFSIZ]; 3595 char cm2[BUFSIZ];
3596 Byte *screenp; 3596 Byte *screenp;
3597 // char cm3[BUFSIZ]; 3597 // char cm3[BUFSIZ];
3598 int Rrow= last_row; 3598 int Rrow= last_row;
3599#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ 3599#endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
3600 3600
3601 memset(cm1, '\0', BUFSIZ - 1); // clear the buffer 3601 memset(cm1, '\0', BUFSIZ - 1); // clear the buffer
3602 3602
@@ -3610,7 +3610,7 @@ static void place_cursor(int row, int col, int opti)
3610 cm= cm1; 3610 cm= cm1;
3611 if (opti == FALSE) goto pc0; 3611 if (opti == FALSE) goto pc0;
3612 3612
3613#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR 3613#ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
3614 //----- find the minimum # of chars to move cursor ------------- 3614 //----- find the minimum # of chars to move cursor -------------
3615 //----- 2. Try moving with discreet chars (Newline, [back]space, ...) 3615 //----- 2. Try moving with discreet chars (Newline, [back]space, ...)
3616 memset(cm2, '\0', BUFSIZ - 1); // clear the buffer 3616 memset(cm2, '\0', BUFSIZ - 1); // clear the buffer
@@ -3643,7 +3643,7 @@ static void place_cursor(int row, int col, int opti)
3643 } /* else if (strlen(cm3) < strlen(cm)) { 3643 } /* else if (strlen(cm3) < strlen(cm)) {
3644 cm= cm3; 3644 cm= cm3;
3645 } */ 3645 } */
3646#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ 3646#endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
3647 pc0: 3647 pc0:
3648 l= strlen(cm); 3648 l= strlen(cm);
3649 if (l) write(1, cm, l); // move the cursor 3649 if (l) write(1, cm, l); // move the cursor
@@ -3690,10 +3690,10 @@ static void beep()
3690 3690
3691static void indicate_error(char c) 3691static void indicate_error(char c)
3692{ 3692{
3693#ifdef BB_FEATURE_VI_CRASHME 3693#ifdef CONFIG_FEATURE_VI_CRASHME
3694 if (crashme > 0) 3694 if (crashme > 0)
3695 return; // generate a random command 3695 return; // generate a random command
3696#endif /* BB_FEATURE_VI_CRASHME */ 3696#endif /* CONFIG_FEATURE_VI_CRASHME */
3697 if (err_method == 0) { 3697 if (err_method == 0) {
3698 beep(); 3698 beep();
3699 } else { 3699 } else {
@@ -3777,14 +3777,14 @@ static void edit_status(void) // show file status on status line
3777 percent = 100; 3777 percent = 100;
3778 } 3778 }
3779 psb("\"%s\"" 3779 psb("\"%s\""
3780#ifdef BB_FEATURE_VI_READONLY 3780#ifdef CONFIG_FEATURE_VI_READONLY
3781 "%s" 3781 "%s"
3782#endif /* BB_FEATURE_VI_READONLY */ 3782#endif /* CONFIG_FEATURE_VI_READONLY */
3783 "%s line %d of %d --%d%%--", 3783 "%s line %d of %d --%d%%--",
3784 (cfn != 0 ? (char *) cfn : "No file"), 3784 (cfn != 0 ? (char *) cfn : "No file"),
3785#ifdef BB_FEATURE_VI_READONLY 3785#ifdef CONFIG_FEATURE_VI_READONLY
3786 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), 3786 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
3787#endif /* BB_FEATURE_VI_READONLY */ 3787#endif /* CONFIG_FEATURE_VI_READONLY */
3788 (file_modified == TRUE ? " [modified]" : ""), 3788 (file_modified == TRUE ? " [modified]" : ""),
3789 cur, tot, percent); 3789 cur, tot, percent);
3790} 3790}
@@ -3847,13 +3847,13 @@ static void refresh(int full_screen)
3847 int li, changed; 3847 int li, changed;
3848 Byte buf[MAX_SCR_COLS]; 3848 Byte buf[MAX_SCR_COLS];
3849 Byte *tp, *sp; // pointer into text[] and screen[] 3849 Byte *tp, *sp; // pointer into text[] and screen[]
3850#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR 3850#ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
3851 int last_li= -2; // last line that changed- for optimizing cursor movement 3851 int last_li= -2; // last line that changed- for optimizing cursor movement
3852#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ 3852#endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
3853 3853
3854#ifdef BB_FEATURE_VI_WIN_RESIZE 3854#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
3855 window_size_get(0); 3855 window_size_get(0);
3856#endif /* BB_FEATURE_VI_WIN_RESIZE */ 3856#endif /* CONFIG_FEATURE_VI_WIN_RESIZE */
3857 sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot") 3857 sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot")
3858 tp = screenbegin; // index into text[] of top line 3858 tp = screenbegin; // index into text[] of top line
3859 3859
@@ -3916,31 +3916,31 @@ static void refresh(int full_screen)
3916 // to handle offsets correctly 3916 // to handle offsets correctly
3917 place_cursor(li, cs, FALSE); 3917 place_cursor(li, cs, FALSE);
3918 } else { 3918 } else {
3919#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR 3919#ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
3920 // if this just the next line 3920 // if this just the next line
3921 // try to optimize cursor movement 3921 // try to optimize cursor movement
3922 // otherwise, use standard ESC sequence 3922 // otherwise, use standard ESC sequence
3923 place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE); 3923 place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
3924 last_li= li; 3924 last_li= li;
3925#else /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ 3925#else /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
3926 place_cursor(li, cs, FALSE); // use standard ESC sequence 3926 place_cursor(li, cs, FALSE); // use standard ESC sequence
3927#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ 3927#endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
3928 } 3928 }
3929 3929
3930 // write line out to terminal 3930 // write line out to terminal
3931 write(1, sp+cs, ce-cs+1); 3931 write(1, sp+cs, ce-cs+1);
3932#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR 3932#ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
3933 last_row = li; 3933 last_row = li;
3934#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ 3934#endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
3935 } 3935 }
3936 } 3936 }
3937 3937
3938#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR 3938#ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
3939 place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE); 3939 place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE);
3940 last_row = crow; 3940 last_row = crow;
3941#else 3941#else
3942 place_cursor(crow, ccol, FALSE); 3942 place_cursor(crow, ccol, FALSE);
3943#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ 3943#endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
3944 3944
3945 if (offset != old_offset) 3945 if (offset != old_offset)
3946 old_offset = offset; 3946 old_offset = offset;
diff --git a/env.c b/env.c
deleted file mode 100644
index 8bb690b72..000000000
--- a/env.c
+++ /dev/null
@@ -1,106 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * env implementation for busybox
4 *
5 * Copyright (c) 1988, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Original copyright notice is retained at the end of this file.
23 *
24 * Modified for BusyBox by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
25 */
26
27#include <stdio.h>
28#include <string.h>
29#include <getopt.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include "busybox.h"
33
34extern int env_main(int argc, char** argv)
35{
36 char **ep, *p;
37 char *cleanenv[1];
38 int ignore_environment = 0;
39 int ch;
40
41 while ((ch = getopt(argc, argv, "+iu:")) != -1) {
42 switch(ch) {
43 case 'i':
44 ignore_environment = 1;
45 break;
46 case 'u':
47 unsetenv(optarg);
48 break;
49 default:
50 show_usage();
51 }
52 }
53 if (optind != argc && !strcmp(argv[optind], "-")) {
54 ignore_environment = 1;
55 argv++;
56 }
57 if (ignore_environment) {
58 environ = cleanenv;
59 cleanenv[0] = NULL;
60 }
61 for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv)
62 if (putenv(*argv) < 0)
63 perror_msg_and_die("%s", *argv);
64 if (*argv) {
65 execvp(*argv, argv);
66 perror_msg_and_die("%s", *argv);
67 }
68 for (ep = environ; *ep; ep++)
69 puts(*ep);
70 return 0;
71}
72
73/*
74 * Copyright (c) 1988, 1993, 1994
75 * The Regents of the University of California. All rights reserved.
76 *
77 * Redistribution and use in source and binary forms, with or without
78 * modification, are permitted provided that the following conditions
79 * are met:
80 * 1. Redistributions of source code must retain the above copyright
81 * notice, this list of conditions and the following disclaimer.
82 * 2. Redistributions in binary form must reproduce the above copyright
83 * notice, this list of conditions and the following disclaimer in the
84 * documentation and/or other materials provided with the distribution.
85 *
86 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
87 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
88 *
89 * 4. Neither the name of the University nor the names of its contributors
90 * may be used to endorse or promote products derived from this software
91 * without specific prior written permission.
92 *
93 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
94 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
95 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
96 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
97 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
98 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
99 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
101 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
102 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
103 * SUCH DAMAGE.
104 */
105
106
diff --git a/examples/inittab b/examples/inittab
index 8e7e945b3..45f5a61fe 100644
--- a/examples/inittab
+++ b/examples/inittab
@@ -1,7 +1,7 @@
1# /etc/inittab init(8) configuration for BusyBox 1# /etc/inittab init(8) configuration for BusyBox
2# 2#
3# Copyright (C) 1999 by Lineo, inc. Written by Erik Andersen 3# Copyright (C) 1999 by Lineo, inc. and Erik Andersen
4# <andersen@lineo.com>, <andersee@debian.org> 4# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
5# 5#
6# 6#
7# Note, BusyBox init doesn't support runlevels. The runlevels field is 7# Note, BusyBox init doesn't support runlevels. The runlevels field is
diff --git a/examples/kernel-patches/devps.patch.9_25_2000 b/examples/kernel-patches/devps.patch.9_25_2000
index d74a26a99..086205cf2 100644
--- a/examples/kernel-patches/devps.patch.9_25_2000
+++ b/examples/kernel-patches/devps.patch.9_25_2000
@@ -44,7 +44,7 @@ diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-
44+/* 44+/*
45+ * linux/drivers/char/devmtab.c 45+ * linux/drivers/char/devmtab.c
46+ * 46+ *
47+ * Copyright (C) 2000 Erik Andersen <andersee@debian.org> 47+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
48+ * 48+ *
49+ * May be copied or modified under the terms of the GNU General Public License. 49+ * May be copied or modified under the terms of the GNU General Public License.
50+ * See linux/COPYING for more information. 50+ * See linux/COPYING for more information.
@@ -343,7 +343,7 @@ diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-
343+/* 343+/*
344+ * linux/drivers/char/devps.c 344+ * linux/drivers/char/devps.c
345+ * 345+ *
346+ * Copyright (C) 2000 Erik Andersen <andersee@debian.org> 346+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
347+ * 347+ *
348+ * May be copied or modified under the terms of the GNU General Public License. 348+ * May be copied or modified under the terms of the GNU General Public License.
349+ * See linux/COPYING for more information. 349+ * See linux/COPYING for more information.
@@ -900,7 +900,7 @@ diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-
900+ * devmtab tester 900+ * devmtab tester
901+ * 901+ *
902+ * 902+ *
903+ * Copyright (C) 2000 by Erik Andersen <andersee@debian.org> 903+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
904+ * 904+ *
905+ * This program is free software; you can redistribute it and/or modify 905+ * This program is free software; you can redistribute it and/or modify
906+ * it under the terms of the GNU General Public License as published by 906+ * it under the terms of the GNU General Public License as published by
@@ -1020,7 +1020,7 @@ diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-
1020+ * Mini ps implementation for use with the Linux devps driver 1020+ * Mini ps implementation for use with the Linux devps driver
1021+ * 1021+ *
1022+ * 1022+ *
1023+ * Copyright (C) 2000 by Erik Andersen <andersee@debian.org> 1023+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
1024+ * 1024+ *
1025+ * This program is free software; you can redistribute it and/or modify 1025+ * This program is free software; you can redistribute it and/or modify
1026+ * it under the terms of the GNU General Public License as published by 1026+ * it under the terms of the GNU General Public License as published by
@@ -1311,7 +1311,7 @@ diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-
1311+/* 1311+/*
1312+ * -- <linux/devmtab.h> 1312+ * -- <linux/devmtab.h>
1313+ * 1313+ *
1314+ * Copyright (C) 2000 Erik Andersen <andersee@debian.org> 1314+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
1315+ * 1315+ *
1316+ * May be copied or modified under the terms of the GNU General Public License. 1316+ * May be copied or modified under the terms of the GNU General Public License.
1317+ * See linux/COPYING for more information. 1317+ * See linux/COPYING for more information.
@@ -1369,7 +1369,7 @@ diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-
1369+/* 1369+/*
1370+ * -- <linux/devps.h> 1370+ * -- <linux/devps.h>
1371+ * 1371+ *
1372+ * Copyright (C) 2000 Erik Andersen <andersee@debian.org> 1372+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
1373+ * 1373+ *
1374+ * May be copied or modified under the terms of the GNU General Public License. 1374+ * May be copied or modified under the terms of the GNU General Public License.
1375+ * See linux/COPYING for more information. 1375+ * See linux/COPYING for more information.
diff --git a/examples/mk2knr.pl b/examples/mk2knr.pl
index aaf4963b1..1259b8436 100755
--- a/examples/mk2knr.pl
+++ b/examples/mk2knr.pl
@@ -3,7 +3,7 @@
3# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style 3# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style
4# 4#
5# How to use this script: 5# How to use this script:
6# - In the busybox directory type 'scripts/mk2knr.pl files-you-want-to-convert' 6# - In the busybox directory type 'examples/mk2knr.pl files-to-convert'
7# - Review the 'convertme.pl' script generated and remove / edit any of the 7# - Review the 'convertme.pl' script generated and remove / edit any of the
8# substitutions in there (please especially check for false positives) 8# substitutions in there (please especially check for false positives)
9# - Type './convertme.pl same-files-as-before' 9# - Type './convertme.pl same-files-as-before'
diff --git a/expr.c b/expr.c
deleted file mode 100644
index d6cc82e3e..000000000
--- a/expr.c
+++ /dev/null
@@ -1,535 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini expr implementation for busybox
4 *
5 * based on GNU expr Mike Parker.
6 * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc.
7 *
8 * Busybox modifications
9 * Copyright (c) 2000 Edward Betts <edward@debian.org>.
10 *
11 * this program is free software; you can redistribute it and/or modify
12 * it under the terms of the gnu general public license as published by
13 * the free software foundation; either version 2 of the license, or
14 * (at your option) any later version.
15 *
16 * this program is distributed in the hope that it will be useful,
17 * but without any warranty; without even the implied warranty of
18 * merchantability or fitness for a particular purpose. see the gnu
19 * general public license for more details.
20 *
21 * you should have received a copy of the gnu general public license
22 * along with this program; if not, write to the free software
23 * foundation, inc., 59 temple place, suite 330, boston, ma 02111-1307 usa
24 *
25 */
26
27/* This program evaluates expressions. Each token (operator, operand,
28 * parenthesis) of the expression must be a seperate argument. The
29 * parser used is a reasonably general one, though any incarnation of
30 * it is language-specific. It is especially nice for expressions.
31 *
32 * No parse tree is needed; a new node is evaluated immediately.
33 * One function can handle multiple operators all of equal precedence,
34 * provided they all associate ((x op x) op x). */
35
36/* no getopt needed */
37
38#include <stdio.h>
39#include <string.h>
40#include <stdlib.h>
41#include <regex.h>
42#include <sys/types.h>
43#include "busybox.h"
44
45
46/* The kinds of value we can have. */
47enum valtype {
48 integer,
49 string
50};
51typedef enum valtype TYPE;
52
53/* A value is.... */
54struct valinfo {
55 TYPE type; /* Which kind. */
56 union { /* The value itself. */
57 int i;
58 char *s;
59 } u;
60};
61typedef struct valinfo VALUE;
62
63/* The arguments given to the program, minus the program name. */
64static char **args;
65
66static VALUE *docolon (VALUE *sv, VALUE *pv);
67static VALUE *eval (void);
68static VALUE *int_value (int i);
69static VALUE *str_value (char *s);
70static int nextarg (char *str);
71static int null (VALUE *v);
72static int toarith (VALUE *v);
73static void freev (VALUE *v);
74static void tostring (VALUE *v);
75
76int expr_main (int argc, char **argv)
77{
78 VALUE *v;
79
80 if (argc == 1) {
81 error_msg_and_die("too few arguments");
82 }
83
84 args = argv + 1;
85
86 v = eval ();
87 if (*args)
88 error_msg_and_die ("syntax error");
89
90 if (v->type == integer)
91 printf ("%d\n", v->u.i);
92 else
93 puts (v->u.s);
94
95 exit (null (v));
96}
97
98/* Return a VALUE for I. */
99
100static VALUE *int_value (int i)
101{
102 VALUE *v;
103
104 v = xmalloc (sizeof(VALUE));
105 v->type = integer;
106 v->u.i = i;
107 return v;
108}
109
110/* Return a VALUE for S. */
111
112static VALUE *str_value (char *s)
113{
114 VALUE *v;
115
116 v = xmalloc (sizeof(VALUE));
117 v->type = string;
118 v->u.s = strdup (s);
119 return v;
120}
121
122/* Free VALUE V, including structure components. */
123
124static void freev (VALUE *v)
125{
126 if (v->type == string)
127 free (v->u.s);
128 free (v);
129}
130
131/* Return nonzero if V is a null-string or zero-number. */
132
133static int null (VALUE *v)
134{
135 switch (v->type) {
136 case integer:
137 return v->u.i == 0;
138 case string:
139 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
140 default:
141 abort ();
142 }
143}
144
145/* Coerce V to a string value (can't fail). */
146
147static void tostring (VALUE *v)
148{
149 char *temp;
150
151 if (v->type == integer) {
152 temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
153 sprintf (temp, "%d", v->u.i);
154 v->u.s = temp;
155 v->type = string;
156 }
157}
158
159/* Coerce V to an integer value. Return 1 on success, 0 on failure. */
160
161static int toarith (VALUE *v)
162{
163 int i;
164
165 switch (v->type) {
166 case integer:
167 return 1;
168 case string:
169 i = 0;
170 /* Don't interpret the empty string as an integer. */
171 if (v->u.s == 0)
172 return 0;
173 i = atoi(v->u.s);
174 free (v->u.s);
175 v->u.i = i;
176 v->type = integer;
177 return 1;
178 default:
179 abort ();
180 }
181}
182
183/* Return nonzero if the next token matches STR exactly.
184 STR must not be NULL. */
185
186static int
187nextarg (char *str)
188{
189 if (*args == NULL)
190 return 0;
191 return strcmp (*args, str) == 0;
192}
193
194/* The comparison operator handling functions. */
195
196#define cmpf(name, rel) \
197static int name (l, r) VALUE *l; VALUE *r; \
198{ \
199 if (l->type == string || r->type == string) { \
200 tostring (l); \
201 tostring (r); \
202 return strcmp (l->u.s, r->u.s) rel 0; \
203 } \
204 else \
205 return l->u.i rel r->u.i; \
206}
207 cmpf (less_than, <)
208 cmpf (less_equal, <=)
209 cmpf (equal, ==)
210 cmpf (not_equal, !=)
211 cmpf (greater_equal, >=)
212 cmpf (greater_than, >)
213
214#undef cmpf
215
216/* The arithmetic operator handling functions. */
217
218#define arithf(name, op) \
219static \
220int name (l, r) VALUE *l; VALUE *r; \
221{ \
222 if (!toarith (l) || !toarith (r)) \
223 error_msg_and_die ("non-numeric argument"); \
224 return l->u.i op r->u.i; \
225}
226
227#define arithdivf(name, op) \
228static int name (l, r) VALUE *l; VALUE *r; \
229{ \
230 if (!toarith (l) || !toarith (r)) \
231 error_msg_and_die ( "non-numeric argument"); \
232 if (r->u.i == 0) \
233 error_msg_and_die ( "division by zero"); \
234 return l->u.i op r->u.i; \
235}
236
237 arithf (plus, +)
238 arithf (minus, -)
239 arithf (multiply, *)
240 arithdivf (divide, /)
241 arithdivf (mod, %)
242
243#undef arithf
244#undef arithdivf
245
246/* Do the : operator.
247 SV is the VALUE for the lhs (the string),
248 PV is the VALUE for the rhs (the pattern). */
249
250static VALUE *docolon (VALUE *sv, VALUE *pv)
251{
252 VALUE *v;
253 const char *errmsg;
254 struct re_pattern_buffer re_buffer;
255 struct re_registers re_regs;
256 int len;
257
258 tostring (sv);
259 tostring (pv);
260
261 if (pv->u.s[0] == '^') {
262 fprintf (stderr, "\
263warning: unportable BRE: `%s': using `^' as the first character\n\
264of a basic regular expression is not portable; it is being ignored",
265 pv->u.s);
266 }
267
268 len = strlen (pv->u.s);
269 memset (&re_buffer, 0, sizeof (re_buffer));
270 memset (&re_regs, 0, sizeof (re_regs));
271 re_buffer.allocated = 2 * len;
272 re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
273 re_buffer.translate = 0;
274 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
275 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
276 if (errmsg) {
277 error_msg_and_die("%s", errmsg);
278 }
279
280 len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
281 if (len >= 0) {
282 /* Were \(...\) used? */
283 if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */
284 sv->u.s[re_regs.end[1]] = '\0';
285 v = str_value (sv->u.s + re_regs.start[1]);
286 }
287 else
288 v = int_value (len);
289 }
290 else {
291 /* Match failed -- return the right kind of null. */
292 if (re_buffer.re_nsub > 0)
293 v = str_value ("");
294 else
295 v = int_value (0);
296 }
297 free (re_buffer.buffer);
298 return v;
299}
300
301/* Handle bare operands and ( expr ) syntax. */
302
303static VALUE *eval7 (void)
304{
305 VALUE *v;
306
307 if (!*args)
308 error_msg_and_die ( "syntax error");
309
310 if (nextarg ("(")) {
311 args++;
312 v = eval ();
313 if (!nextarg (")"))
314 error_msg_and_die ( "syntax error");
315 args++;
316 return v;
317 }
318
319 if (nextarg (")"))
320 error_msg_and_die ( "syntax error");
321
322 return str_value (*args++);
323}
324
325/* Handle match, substr, index, length, and quote keywords. */
326
327static VALUE *eval6 (void)
328{
329 VALUE *l, *r, *v, *i1, *i2;
330
331 if (nextarg ("quote")) {
332 args++;
333 if (!*args)
334 error_msg_and_die ( "syntax error");
335 return str_value (*args++);
336 }
337 else if (nextarg ("length")) {
338 args++;
339 r = eval6 ();
340 tostring (r);
341 v = int_value (strlen (r->u.s));
342 freev (r);
343 return v;
344 }
345 else if (nextarg ("match")) {
346 args++;
347 l = eval6 ();
348 r = eval6 ();
349 v = docolon (l, r);
350 freev (l);
351 freev (r);
352 return v;
353 }
354 else if (nextarg ("index")) {
355 args++;
356 l = eval6 ();
357 r = eval6 ();
358 tostring (l);
359 tostring (r);
360 v = int_value (strcspn (l->u.s, r->u.s) + 1);
361 if (v->u.i == (int) strlen (l->u.s) + 1)
362 v->u.i = 0;
363 freev (l);
364 freev (r);
365 return v;
366 }
367 else if (nextarg ("substr")) {
368 args++;
369 l = eval6 ();
370 i1 = eval6 ();
371 i2 = eval6 ();
372 tostring (l);
373 if (!toarith (i1) || !toarith (i2)
374 || i1->u.i > (int) strlen (l->u.s)
375 || i1->u.i <= 0 || i2->u.i <= 0)
376 v = str_value ("");
377 else {
378 v = xmalloc (sizeof(VALUE));
379 v->type = string;
380 v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
381 l->u.s + i1->u.i - 1, i2->u.i);
382 v->u.s[i2->u.i] = 0;
383 }
384 freev (l);
385 freev (i1);
386 freev (i2);
387 return v;
388 }
389 else
390 return eval7 ();
391}
392
393/* Handle : operator (pattern matching).
394 Calls docolon to do the real work. */
395
396static VALUE *eval5 (void)
397{
398 VALUE *l, *r, *v;
399
400 l = eval6 ();
401 while (nextarg (":")) {
402 args++;
403 r = eval6 ();
404 v = docolon (l, r);
405 freev (l);
406 freev (r);
407 l = v;
408 }
409 return l;
410}
411
412/* Handle *, /, % operators. */
413
414static VALUE *eval4 (void)
415{
416 VALUE *l, *r;
417 int (*fxn) (), val;
418
419 l = eval5 ();
420 while (1) {
421 if (nextarg ("*"))
422 fxn = multiply;
423 else if (nextarg ("/"))
424 fxn = divide;
425 else if (nextarg ("%"))
426 fxn = mod;
427 else
428 return l;
429 args++;
430 r = eval5 ();
431 val = (*fxn) (l, r);
432 freev (l);
433 freev (r);
434 l = int_value (val);
435 }
436}
437
438/* Handle +, - operators. */
439
440static VALUE *eval3 (void)
441{
442 VALUE *l, *r;
443 int (*fxn) (), val;
444
445 l = eval4 ();
446 while (1) {
447 if (nextarg ("+"))
448 fxn = plus;
449 else if (nextarg ("-"))
450 fxn = minus;
451 else
452 return l;
453 args++;
454 r = eval4 ();
455 val = (*fxn) (l, r);
456 freev (l);
457 freev (r);
458 l = int_value (val);
459 }
460}
461
462/* Handle comparisons. */
463
464static VALUE *eval2 (void)
465{
466 VALUE *l, *r;
467 int (*fxn) (), val;
468
469 l = eval3 ();
470 while (1) {
471 if (nextarg ("<"))
472 fxn = less_than;
473 else if (nextarg ("<="))
474 fxn = less_equal;
475 else if (nextarg ("=") || nextarg ("=="))
476 fxn = equal;
477 else if (nextarg ("!="))
478 fxn = not_equal;
479 else if (nextarg (">="))
480 fxn = greater_equal;
481 else if (nextarg (">"))
482 fxn = greater_than;
483 else
484 return l;
485 args++;
486 r = eval3 ();
487 toarith (l);
488 toarith (r);
489 val = (*fxn) (l, r);
490 freev (l);
491 freev (r);
492 l = int_value (val);
493 }
494}
495
496/* Handle &. */
497
498static VALUE *eval1 (void)
499{
500 VALUE *l, *r;
501
502 l = eval2 ();
503 while (nextarg ("&")) {
504 args++;
505 r = eval2 ();
506 if (null (l) || null (r)) {
507 freev (l);
508 freev (r);
509 l = int_value (0);
510 }
511 else
512 freev (r);
513 }
514 return l;
515}
516
517/* Handle |. */
518
519static VALUE *eval (void)
520{
521 VALUE *l, *r;
522
523 l = eval1 ();
524 while (nextarg ("|")) {
525 args++;
526 r = eval1 ();
527 if (null (l)) {
528 freev (l);
529 l = r;
530 }
531 else
532 freev (r);
533 }
534 return l;
535}
diff --git a/fbset.c b/fbset.c
deleted file mode 100644
index 5ccd80e79..000000000
--- a/fbset.c
+++ /dev/null
@@ -1,424 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini fbset implementation for busybox
4 *
5 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * This is a from-scratch implementation of fbset; but the de facto fbset
22 * implementation was a good reference. fbset (original) is released under
23 * the GPL, and is (c) 1995-1999 by:
24 * Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <unistd.h>
30#include <fcntl.h>
31#include <errno.h>
32#include <ctype.h>
33#include <string.h>
34#include <sys/ioctl.h>
35#include "busybox.h"
36
37#define DEFAULTFBDEV "/dev/fb0"
38#define DEFAULTFBMODE "/etc/fb.modes"
39
40static const int OPT_CHANGE = (1 << 0);
41static const int OPT_INFO = (1 << 1);
42static const int OPT_READMODE = (1 << 2);
43
44enum {
45 CMD_FB = 1,
46 CMD_DB = 2,
47 CMD_GEOMETRY = 3,
48 CMD_TIMING = 4,
49 CMD_ACCEL = 5,
50 CMD_HSYNC = 6,
51 CMD_VSYNC = 7,
52 CMD_LACED = 8,
53 CMD_DOUBLE = 9,
54/* CMD_XCOMPAT = 10, */
55 CMD_ALL = 11,
56 CMD_INFO = 12,
57 CMD_CHANGE = 13,
58
59#ifdef BB_FEATURE_FBSET_FANCY
60 CMD_XRES = 100,
61 CMD_YRES = 101,
62 CMD_VXRES = 102,
63 CMD_VYRES = 103,
64 CMD_DEPTH = 104,
65 CMD_MATCH = 105,
66 CMD_PIXCLOCK = 106,
67 CMD_LEFT = 107,
68 CMD_RIGHT = 108,
69 CMD_UPPER = 109,
70 CMD_LOWER = 110,
71 CMD_HSLEN = 111,
72 CMD_VSLEN = 112,
73 CMD_CSYNC = 113,
74 CMD_GSYNC = 114,
75 CMD_EXTSYNC = 115,
76 CMD_BCAST = 116,
77 CMD_RGBA = 117,
78 CMD_STEP = 118,
79 CMD_MOVE = 119,
80#endif
81};
82
83static unsigned int g_options = 0;
84
85/* Stuff stolen from the kernel's fb.h */
86static const int FBIOGET_VSCREENINFO = 0x4600;
87static const int FBIOPUT_VSCREENINFO = 0x4601;
88#define __u32 u_int32_t
89struct fb_bitfield {
90 __u32 offset; /* beginning of bitfield */
91 __u32 length; /* length of bitfield */
92 __u32 msb_right; /* != 0 : Most significant bit is */
93 /* right */
94};
95struct fb_var_screeninfo {
96 __u32 xres; /* visible resolution */
97 __u32 yres;
98 __u32 xres_virtual; /* virtual resolution */
99 __u32 yres_virtual;
100 __u32 xoffset; /* offset from virtual to visible */
101 __u32 yoffset; /* resolution */
102
103 __u32 bits_per_pixel; /* guess what */
104 __u32 grayscale; /* != 0 Graylevels instead of colors */
105
106 struct fb_bitfield red; /* bitfield in fb mem if true color, */
107 struct fb_bitfield green; /* else only length is significant */
108 struct fb_bitfield blue;
109 struct fb_bitfield transp; /* transparency */
110
111 __u32 nonstd; /* != 0 Non standard pixel format */
112
113 __u32 activate; /* see FB_ACTIVATE_* */
114
115 __u32 height; /* height of picture in mm */
116 __u32 width; /* width of picture in mm */
117
118 __u32 accel_flags; /* acceleration flags (hints) */
119
120 /* Timing: All values in pixclocks, except pixclock (of course) */
121 __u32 pixclock; /* pixel clock in ps (pico seconds) */
122 __u32 left_margin; /* time from sync to picture */
123 __u32 right_margin; /* time from picture to sync */
124 __u32 upper_margin; /* time from sync to picture */
125 __u32 lower_margin;
126 __u32 hsync_len; /* length of horizontal sync */
127 __u32 vsync_len; /* length of vertical sync */
128 __u32 sync; /* see FB_SYNC_* */
129 __u32 vmode; /* see FB_VMODE_* */
130 __u32 reserved[6]; /* Reserved for future compatibility */
131};
132
133
134static struct cmdoptions_t {
135 char *name;
136 unsigned char param_count;
137 unsigned char code;
138} g_cmdoptions[] = {
139 {
140 "-fb", 1, CMD_FB}, {
141 "-db", 1, CMD_DB}, {
142 "-a", 0, CMD_ALL}, {
143 "-i", 0, CMD_INFO}, {
144 "-g", 5, CMD_GEOMETRY}, {
145 "-t", 7, CMD_TIMING}, {
146 "-accel", 1, CMD_ACCEL}, {
147 "-hsync", 1, CMD_HSYNC}, {
148 "-vsync", 1, CMD_VSYNC}, {
149 "-laced", 1, CMD_LACED}, {
150 "-double", 1, CMD_DOUBLE}, {
151 "-n", 0, CMD_CHANGE}, {
152#ifdef BB_FEATURE_FBSET_FANCY
153 "-all", 0, CMD_ALL}, {
154 "-xres", 1, CMD_XRES}, {
155 "-yres", 1, CMD_YRES}, {
156 "-vxres", 1, CMD_VXRES}, {
157 "-vyres", 1, CMD_VYRES}, {
158 "-depth", 1, CMD_DEPTH}, {
159 "-match", 0, CMD_MATCH}, {
160 "-geometry", 5, CMD_GEOMETRY}, {
161 "-pixclock", 1, CMD_PIXCLOCK}, {
162 "-left", 1, CMD_LEFT}, {
163 "-right", 1, CMD_RIGHT}, {
164 "-upper", 1, CMD_UPPER}, {
165 "-lower", 1, CMD_LOWER}, {
166 "-hslen", 1, CMD_HSLEN}, {
167 "-vslen", 1, CMD_VSLEN}, {
168 "-timings", 7, CMD_TIMING}, {
169 "-csync", 1, CMD_CSYNC}, {
170 "-gsync", 1, CMD_GSYNC}, {
171 "-extsync", 1, CMD_EXTSYNC}, {
172 "-bcast", 1, CMD_BCAST}, {
173 "-rgba", 1, CMD_RGBA}, {
174 "-step", 1, CMD_STEP}, {
175 "-move", 1, CMD_MOVE}, {
176#endif
177 0, 0, 0}
178};
179
180#ifdef BB_FEATURE_FBSET_READMODE
181/* taken from linux/fb.h */
182static const int FB_VMODE_INTERLACED = 1; /* interlaced */
183static const int FB_VMODE_DOUBLE = 2; /* double scan */
184static const int FB_SYNC_HOR_HIGH_ACT = 1; /* horizontal sync high active */
185static const int FB_SYNC_VERT_HIGH_ACT = 2; /* vertical sync high active */
186static const int FB_SYNC_EXT = 4; /* external sync */
187static const int FB_SYNC_COMP_HIGH_ACT = 8; /* composite sync high active */
188#endif
189static int readmode(struct fb_var_screeninfo *base, const char *fn,
190 const char *mode)
191{
192#ifdef BB_FEATURE_FBSET_READMODE
193 FILE *f;
194 char buf[256];
195 char *p = buf;
196
197 f = xfopen(fn, "r");
198 while (!feof(f)) {
199 fgets(buf, sizeof(buf), f);
200 if ((p = strstr(buf, "mode ")) || (p = strstr(buf, "mode\t"))) {
201 p += 5;
202 if ((p = strstr(buf, mode))) {
203 p += strlen(mode);
204 if (!isspace(*p) && (*p != 0) && (*p != '"')
205 && (*p != '\r') && (*p != '\n'))
206 continue; /* almost, but not quite */
207 while (!feof(f)) {
208 fgets(buf, sizeof(buf), f);
209
210 if ((p = strstr(buf, "geometry "))) {
211 p += 9;
212
213 sscanf(p, "%d %d %d %d %d",
214 &(base->xres), &(base->yres),
215 &(base->xres_virtual), &(base->yres_virtual),
216 &(base->bits_per_pixel));
217 } else if ((p = strstr(buf, "timings "))) {
218 p += 8;
219
220 sscanf(p, "%d %d %d %d %d %d %d",
221 &(base->pixclock),
222 &(base->left_margin), &(base->right_margin),
223 &(base->upper_margin), &(base->lower_margin),
224 &(base->hsync_len), &(base->vsync_len));
225 } else if ((p = strstr(buf, "laced "))) {
226 p += 6;
227
228 if (strstr(buf, "false")) {
229 base->vmode &= ~FB_VMODE_INTERLACED;
230 } else {
231 base->vmode |= FB_VMODE_INTERLACED;
232 }
233 } else if ((p = strstr(buf, "double "))) {
234 p += 7;
235
236 if (strstr(buf, "false")) {
237 base->vmode &= ~FB_VMODE_DOUBLE;
238 } else {
239 base->vmode |= FB_VMODE_DOUBLE;
240 }
241 } else if ((p = strstr(buf, "vsync "))) {
242 p += 6;
243
244 if (strstr(buf, "low")) {
245 base->sync &= ~FB_SYNC_VERT_HIGH_ACT;
246 } else {
247 base->sync |= FB_SYNC_VERT_HIGH_ACT;
248 }
249 } else if ((p = strstr(buf, "hsync "))) {
250 p += 6;
251
252 if (strstr(buf, "low")) {
253 base->sync &= ~FB_SYNC_HOR_HIGH_ACT;
254 } else {
255 base->sync |= FB_SYNC_HOR_HIGH_ACT;
256 }
257 } else if ((p = strstr(buf, "csync "))) {
258 p += 6;
259
260 if (strstr(buf, "low")) {
261 base->sync &= ~FB_SYNC_COMP_HIGH_ACT;
262 } else {
263 base->sync |= FB_SYNC_COMP_HIGH_ACT;
264 }
265 } else if ((p = strstr(buf, "extsync "))) {
266 p += 8;
267
268 if (strstr(buf, "false")) {
269 base->sync &= ~FB_SYNC_EXT;
270 } else {
271 base->sync |= FB_SYNC_EXT;
272 }
273 }
274
275 if (strstr(buf, "endmode"))
276 return 1;
277 }
278 }
279 }
280 }
281#else
282 error_msg( "mode reading not compiled in");
283#endif
284 return 0;
285}
286
287static void setmode(struct fb_var_screeninfo *base,
288 struct fb_var_screeninfo *set)
289{
290 if ((int) set->xres > 0)
291 base->xres = set->xres;
292 if ((int) set->yres > 0)
293 base->yres = set->yres;
294 if ((int) set->xres_virtual > 0)
295 base->xres_virtual = set->xres_virtual;
296 if ((int) set->yres_virtual > 0)
297 base->yres_virtual = set->yres_virtual;
298 if ((int) set->bits_per_pixel > 0)
299 base->bits_per_pixel = set->bits_per_pixel;
300}
301
302static void showmode(struct fb_var_screeninfo *v)
303{
304 double drate = 0, hrate = 0, vrate = 0;
305
306 if (v->pixclock) {
307 drate = 1e12 / v->pixclock;
308 hrate =
309 drate / (v->left_margin + v->xres + v->right_margin +
310 v->hsync_len);
311 vrate =
312 hrate / (v->upper_margin + v->yres + v->lower_margin +
313 v->vsync_len);
314 }
315 printf("\nmode \"%ux%u-%u\"\n", v->xres, v->yres, (int) (vrate + 0.5));
316#ifdef BB_FEATURE_FBSET_FANCY
317 printf("\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n", drate / 1e6,
318 hrate / 1e3, vrate);
319#endif
320 printf("\tgeometry %u %u %u %u %u\n", v->xres, v->yres,
321 v->xres_virtual, v->yres_virtual, v->bits_per_pixel);
322 printf("\ttimings %u %u %u %u %u %u %u\n", v->pixclock, v->left_margin,
323 v->right_margin, v->upper_margin, v->lower_margin, v->hsync_len,
324 v->vsync_len);
325 printf("\taccel %s\n", (v->accel_flags > 0 ? "true" : "false"));
326 printf("\trgba %u/%u,%u/%u,%u/%u,%u/%u\n", v->red.length,
327 v->red.offset, v->green.length, v->green.offset, v->blue.length,
328 v->blue.offset, v->transp.length, v->transp.offset);
329 printf("endmode\n\n");
330}
331
332#ifdef STANDALONE
333int main(int argc, char **argv)
334#else
335extern int fbset_main(int argc, char **argv)
336#endif
337{
338 struct fb_var_screeninfo var, varset;
339 int fh, i;
340 char *fbdev = DEFAULTFBDEV;
341 char *modefile = DEFAULTFBMODE;
342 char *thisarg, *mode = NULL;
343
344 memset(&varset, 0xFF, sizeof(varset));
345
346 /* parse cmd args.... why do they have to make things so difficult? */
347 argv++;
348 argc--;
349 for (; argc > 0 && (thisarg = *argv); argc--, argv++) {
350 for (i = 0; g_cmdoptions[i].name; i++) {
351 if (!strcmp(thisarg, g_cmdoptions[i].name)) {
352 if (argc - 1 < g_cmdoptions[i].param_count)
353 show_usage();
354 switch (g_cmdoptions[i].code) {
355 case CMD_FB:
356 fbdev = argv[1];
357 break;
358 case CMD_DB:
359 modefile = argv[1];
360 break;
361 case CMD_GEOMETRY:
362 varset.xres = strtoul(argv[1], 0, 0);
363 varset.yres = strtoul(argv[2], 0, 0);
364 varset.xres_virtual = strtoul(argv[3], 0, 0);
365 varset.yres_virtual = strtoul(argv[4], 0, 0);
366 varset.bits_per_pixel = strtoul(argv[5], 0, 0);
367 break;
368 case CMD_TIMING:
369 varset.pixclock = strtoul(argv[1], 0, 0);
370 varset.left_margin = strtoul(argv[2], 0, 0);
371 varset.right_margin = strtoul(argv[3], 0, 0);
372 varset.upper_margin = strtoul(argv[4], 0, 0);
373 varset.lower_margin = strtoul(argv[5], 0, 0);
374 varset.hsync_len = strtoul(argv[6], 0, 0);
375 varset.vsync_len = strtoul(argv[7], 0, 0);
376 break;
377 case CMD_CHANGE:
378 g_options |= OPT_CHANGE;
379 break;
380#ifdef BB_FEATURE_FBSET_FANCY
381 case CMD_XRES:
382 varset.xres = strtoul(argv[1], 0, 0);
383 break;
384 case CMD_YRES:
385 varset.yres = strtoul(argv[1], 0, 0);
386 break;
387#endif
388 }
389 argc -= g_cmdoptions[i].param_count;
390 argv += g_cmdoptions[i].param_count;
391 break;
392 }
393 }
394 if (!g_cmdoptions[i].name) {
395 if (argc == 1) {
396 mode = *argv;
397 g_options |= OPT_READMODE;
398 } else {
399 show_usage();
400 }
401 }
402 }
403
404 if ((fh = open(fbdev, O_RDONLY)) < 0)
405 perror_msg_and_die("fbset(open)");
406 if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
407 perror_msg_and_die("fbset(ioctl)");
408 if (g_options & OPT_READMODE) {
409 if (!readmode(&var, modefile, mode)) {
410 error_msg("Unknown video mode `%s'", mode);
411 return EXIT_FAILURE;
412 }
413 }
414
415 setmode(&var, &varset);
416 if (g_options & OPT_CHANGE)
417 if (ioctl(fh, FBIOPUT_VSCREENINFO, &var))
418 perror_msg_and_die("fbset(ioctl)");
419 showmode(&var);
420 /* Don't close the file, as exiting will take care of that */
421 /* close(fh); */
422
423 return EXIT_SUCCESS;
424}
diff --git a/fdflush.c b/fdflush.c
deleted file mode 100644
index 28f5cb68a..000000000
--- a/fdflush.c
+++ /dev/null
@@ -1,47 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini fdflush implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <stdio.h>
25#include <sys/ioctl.h>
26#include <fcntl.h>
27#include <stdlib.h>
28#include "busybox.h"
29
30/* From <linux/fd.h> */
31#define FDFLUSH _IO(2,0x4b)
32
33extern int fdflush_main(int argc, char **argv)
34{
35 int fd;
36
37 if (argc <= 1 || **(++argv) == '-')
38 show_usage();
39
40 if ((fd = open(*argv, 0)) < 0)
41 perror_msg_and_die("%s", *argv);
42
43 if (ioctl(fd, FDFLUSH, 0))
44 perror_msg_and_die("%s", *argv);
45
46 return EXIT_SUCCESS;
47}
diff --git a/find.c b/find.c
deleted file mode 100644
index e814c97b9..000000000
--- a/find.c
+++ /dev/null
@@ -1,200 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini find implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * Reworked by David Douthitt <n9ubh@callsign.net> and
9 * Matt Kraai <kraai@alumni.carnegiemellon.edu>.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27#include <stdio.h>
28#include <unistd.h>
29#include <dirent.h>
30#include <string.h>
31#include <stdlib.h>
32#include <fnmatch.h>
33#include <time.h>
34#include <ctype.h>
35#include "busybox.h"
36
37
38static char *pattern;
39
40#ifdef BB_FEATURE_FIND_TYPE
41static int type_mask = 0;
42#endif
43
44#ifdef BB_FEATURE_FIND_PERM
45static char perm_char = 0;
46static int perm_mask = 0;
47#endif
48
49#ifdef BB_FEATURE_FIND_MTIME
50static char mtime_char;
51static int mtime_days;
52#endif
53
54static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
55{
56 if (pattern != NULL) {
57 const char *tmp = strrchr(fileName, '/');
58
59 if (tmp == NULL)
60 tmp = fileName;
61 else
62 tmp++;
63 if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0))
64 goto no_match;
65 }
66#ifdef BB_FEATURE_FIND_TYPE
67 if (type_mask != 0) {
68 if (!((statbuf->st_mode & S_IFMT) == type_mask))
69 goto no_match;
70 }
71#endif
72#ifdef BB_FEATURE_FIND_PERM
73 if (perm_mask != 0) {
74 if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) ||
75 (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) ||
76 (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0)))
77 goto no_match;
78 }
79#endif
80#ifdef BB_FEATURE_FIND_MTIME
81 if (mtime_days != 0) {
82 time_t file_age = time(NULL) - statbuf->st_mtime;
83 time_t mtime_secs = mtime_days * 24 * 60 * 60;
84 if (!((isdigit(mtime_char) && mtime_secs >= file_age &&
85 mtime_secs < file_age + 24 * 60 * 60) ||
86 (mtime_char == '+' && mtime_secs >= file_age) ||
87 (mtime_char == '-' && mtime_secs < file_age)))
88 goto no_match;
89 }
90#endif
91 puts(fileName);
92no_match:
93 return (TRUE);
94}
95
96#ifdef BB_FEATURE_FIND_TYPE
97static int find_type(char *type)
98{
99 int mask = 0;
100
101 switch (type[0]) {
102 case 'b':
103 mask = S_IFBLK;
104 break;
105 case 'c':
106 mask = S_IFCHR;
107 break;
108 case 'd':
109 mask = S_IFDIR;
110 break;
111 case 'p':
112 mask = S_IFIFO;
113 break;
114 case 'f':
115 mask = S_IFREG;
116 break;
117 case 'l':
118 mask = S_IFLNK;
119 break;
120 case 's':
121 mask = S_IFSOCK;
122 break;
123 }
124
125 if (mask == 0 || type[1] != '\0')
126 error_msg_and_die("invalid argument `%s' to `-type'", type);
127
128 return mask;
129}
130#endif
131
132int find_main(int argc, char **argv)
133{
134 int dereference = FALSE;
135 int i, firstopt, status = EXIT_SUCCESS;
136
137 for (firstopt = 1; firstopt < argc; firstopt++) {
138 if (argv[firstopt][0] == '-')
139 break;
140 }
141
142 /* Parse any options */
143 for (i = firstopt; i < argc; i++) {
144 if (strcmp(argv[i], "-follow") == 0)
145 dereference = TRUE;
146 else if (strcmp(argv[i], "-print") == 0) {
147 ;
148 }
149 else if (strcmp(argv[i], "-name") == 0) {
150 if (++i == argc)
151 error_msg_and_die("option `-name' requires an argument");
152 pattern = argv[i];
153#ifdef BB_FEATURE_FIND_TYPE
154 } else if (strcmp(argv[i], "-type") == 0) {
155 if (++i == argc)
156 error_msg_and_die("option `-type' requires an argument");
157 type_mask = find_type(argv[i]);
158#endif
159#ifdef BB_FEATURE_FIND_PERM
160 } else if (strcmp(argv[i], "-perm") == 0) {
161 char *end;
162 if (++i == argc)
163 error_msg_and_die("option `-perm' requires an argument");
164 perm_mask = strtol(argv[i], &end, 8);
165 if (end[0] != '\0')
166 error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]);
167 if (perm_mask > 07777)
168 error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]);
169 if ((perm_char = argv[i][0]) == '-')
170 perm_mask = -perm_mask;
171#endif
172#ifdef BB_FEATURE_FIND_MTIME
173 } else if (strcmp(argv[i], "-mtime") == 0) {
174 char *end;
175 if (++i == argc)
176 error_msg_and_die("option `-mtime' requires an argument");
177 mtime_days = strtol(argv[i], &end, 10);
178 if (end[0] != '\0')
179 error_msg_and_die("invalid argument `%s' to `-mtime'", argv[i]);
180 if ((mtime_char = argv[i][0]) == '-')
181 mtime_days = -mtime_days;
182#endif
183 } else
184 show_usage();
185 }
186
187 if (firstopt == 1) {
188 if (recursive_action(".", TRUE, dereference, FALSE, fileAction,
189 fileAction, NULL) == FALSE)
190 status = EXIT_FAILURE;
191 } else {
192 for (i = 1; i < firstopt; i++) {
193 if (recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
194 fileAction, NULL) == FALSE)
195 status = EXIT_FAILURE;
196 }
197 }
198
199 return status;
200}
diff --git a/findutils/Makefile b/findutils/Makefile
new file mode 100644
index 000000000..ac590ccf4
--- /dev/null
+++ b/findutils/Makefile
@@ -0,0 +1,39 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := findutils.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27
28obj-$(CONFIG_FIND) += find.o
29obj-$(CONFIG_GREP) += grep.o
30obj-$(CONFIG_WHICH) += which.o
31obj-$(CONFIG_XARGS) += xargs.o
32
33
34# Hand off to toplevel Rules.mak
35include $(TOPDIR)/Rules.mak
36
37clean:
38 rm -f $(L_TARGET) *.o core
39
diff --git a/findutils/config.in b/findutils/config.in
new file mode 100644
index 000000000..8e41bd50c
--- /dev/null
+++ b/findutils/config.in
@@ -0,0 +1,14 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Finding Utilities'
8
9bool 'find' CONFIG_FIND
10bool 'grep' CONFIG_GREP
11bool 'which' CONFIG_WHICH
12bool 'xargs' CONFIG_XARGS
13endmenu
14
diff --git a/findutils/find.c b/findutils/find.c
index e814c97b9..262213e8b 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -2,9 +2,9 @@
2/* 2/*
3 * Mini find implementation for busybox 3 * Mini find implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
5 * 7 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * Reworked by David Douthitt <n9ubh@callsign.net> and 8 * Reworked by David Douthitt <n9ubh@callsign.net> and
9 * Matt Kraai <kraai@alumni.carnegiemellon.edu>. 9 * Matt Kraai <kraai@alumni.carnegiemellon.edu>.
10 * 10 *
@@ -37,16 +37,16 @@
37 37
38static char *pattern; 38static char *pattern;
39 39
40#ifdef BB_FEATURE_FIND_TYPE 40#ifdef CONFIG_FEATURE_FIND_TYPE
41static int type_mask = 0; 41static int type_mask = 0;
42#endif 42#endif
43 43
44#ifdef BB_FEATURE_FIND_PERM 44#ifdef CONFIG_FEATURE_FIND_PERM
45static char perm_char = 0; 45static char perm_char = 0;
46static int perm_mask = 0; 46static int perm_mask = 0;
47#endif 47#endif
48 48
49#ifdef BB_FEATURE_FIND_MTIME 49#ifdef CONFIG_FEATURE_FIND_MTIME
50static char mtime_char; 50static char mtime_char;
51static int mtime_days; 51static int mtime_days;
52#endif 52#endif
@@ -63,13 +63,13 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
63 if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0)) 63 if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0))
64 goto no_match; 64 goto no_match;
65 } 65 }
66#ifdef BB_FEATURE_FIND_TYPE 66#ifdef CONFIG_FEATURE_FIND_TYPE
67 if (type_mask != 0) { 67 if (type_mask != 0) {
68 if (!((statbuf->st_mode & S_IFMT) == type_mask)) 68 if (!((statbuf->st_mode & S_IFMT) == type_mask))
69 goto no_match; 69 goto no_match;
70 } 70 }
71#endif 71#endif
72#ifdef BB_FEATURE_FIND_PERM 72#ifdef CONFIG_FEATURE_FIND_PERM
73 if (perm_mask != 0) { 73 if (perm_mask != 0) {
74 if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) || 74 if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) ||
75 (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) || 75 (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) ||
@@ -77,7 +77,7 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
77 goto no_match; 77 goto no_match;
78 } 78 }
79#endif 79#endif
80#ifdef BB_FEATURE_FIND_MTIME 80#ifdef CONFIG_FEATURE_FIND_MTIME
81 if (mtime_days != 0) { 81 if (mtime_days != 0) {
82 time_t file_age = time(NULL) - statbuf->st_mtime; 82 time_t file_age = time(NULL) - statbuf->st_mtime;
83 time_t mtime_secs = mtime_days * 24 * 60 * 60; 83 time_t mtime_secs = mtime_days * 24 * 60 * 60;
@@ -93,7 +93,7 @@ no_match:
93 return (TRUE); 93 return (TRUE);
94} 94}
95 95
96#ifdef BB_FEATURE_FIND_TYPE 96#ifdef CONFIG_FEATURE_FIND_TYPE
97static int find_type(char *type) 97static int find_type(char *type)
98{ 98{
99 int mask = 0; 99 int mask = 0;
@@ -150,13 +150,13 @@ int find_main(int argc, char **argv)
150 if (++i == argc) 150 if (++i == argc)
151 error_msg_and_die("option `-name' requires an argument"); 151 error_msg_and_die("option `-name' requires an argument");
152 pattern = argv[i]; 152 pattern = argv[i];
153#ifdef BB_FEATURE_FIND_TYPE 153#ifdef CONFIG_FEATURE_FIND_TYPE
154 } else if (strcmp(argv[i], "-type") == 0) { 154 } else if (strcmp(argv[i], "-type") == 0) {
155 if (++i == argc) 155 if (++i == argc)
156 error_msg_and_die("option `-type' requires an argument"); 156 error_msg_and_die("option `-type' requires an argument");
157 type_mask = find_type(argv[i]); 157 type_mask = find_type(argv[i]);
158#endif 158#endif
159#ifdef BB_FEATURE_FIND_PERM 159#ifdef CONFIG_FEATURE_FIND_PERM
160 } else if (strcmp(argv[i], "-perm") == 0) { 160 } else if (strcmp(argv[i], "-perm") == 0) {
161 char *end; 161 char *end;
162 if (++i == argc) 162 if (++i == argc)
@@ -169,7 +169,7 @@ int find_main(int argc, char **argv)
169 if ((perm_char = argv[i][0]) == '-') 169 if ((perm_char = argv[i][0]) == '-')
170 perm_mask = -perm_mask; 170 perm_mask = -perm_mask;
171#endif 171#endif
172#ifdef BB_FEATURE_FIND_MTIME 172#ifdef CONFIG_FEATURE_FIND_MTIME
173 } else if (strcmp(argv[i], "-mtime") == 0) { 173 } else if (strcmp(argv[i], "-mtime") == 0) {
174 char *end; 174 char *end;
175 if (++i == argc) 175 if (++i == argc)
diff --git a/findutils/grep.c b/findutils/grep.c
index eff7c3ff5..a97a8bbb7 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -1,8 +1,8 @@
1/* 1/*
2 * Mini grep implementation for busybox using libc regex. 2 * Mini grep implementation for busybox using libc regex.
3 * 3 *
4 * Copyright (C) 1999,2000,2001 by Lineo, inc. 4 * Copyright (C) 1999,2000,2001 by Lineo, inc. and Mark Whitley
5 * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org> 5 * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -42,13 +42,13 @@ static int invert_search = 0;
42static int suppress_err_msgs = 0; 42static int suppress_err_msgs = 0;
43static int print_files_with_matches = 0; 43static int print_files_with_matches = 0;
44 44
45#ifdef BB_FEATURE_GREP_CONTEXT 45#ifdef CONFIG_FEATURE_GREP_CONTEXT
46extern char *optarg; /* in getopt.h */ 46extern char *optarg; /* in getopt.h */
47static int lines_before = 0; 47static int lines_before = 0;
48static int lines_after = 0; 48static int lines_after = 0;
49static char **before_buf = NULL; 49static char **before_buf = NULL;
50static int last_line_printed = 0; 50static int last_line_printed = 0;
51#endif /* BB_FEATURE_GREP_CONTEXT */ 51#endif /* CONFIG_FEATURE_GREP_CONTEXT */
52 52
53/* globals used internally */ 53/* globals used internally */
54static regex_t *regexes = NULL; /* growable array of compiled regular expressions */ 54static regex_t *regexes = NULL; /* growable array of compiled regular expressions */
@@ -59,7 +59,7 @@ static char *cur_file = NULL; /* the current file we are reading */
59 59
60static void print_line(const char *line, int linenum, char decoration) 60static void print_line(const char *line, int linenum, char decoration)
61{ 61{
62#ifdef BB_FEATURE_GREP_CONTEXT 62#ifdef CONFIG_FEATURE_GREP_CONTEXT
63 /* possibly print the little '--' seperator */ 63 /* possibly print the little '--' seperator */
64 if ((lines_before || lines_after) && last_line_printed && 64 if ((lines_before || lines_after) && last_line_printed &&
65 last_line_printed < linenum - 1) { 65 last_line_printed < linenum - 1) {
@@ -82,11 +82,11 @@ static void grep_file(FILE *file)
82 int linenum = 0; 82 int linenum = 0;
83 int nmatches = 0; 83 int nmatches = 0;
84 int i; 84 int i;
85#ifdef BB_FEATURE_GREP_CONTEXT 85#ifdef CONFIG_FEATURE_GREP_CONTEXT
86 int print_n_lines_after = 0; 86 int print_n_lines_after = 0;
87 int curpos = 0; /* track where we are in the circular 'before' buffer */ 87 int curpos = 0; /* track where we are in the circular 'before' buffer */
88 int idx = 0; /* used for iteration through the circular buffer */ 88 int idx = 0; /* used for iteration through the circular buffer */
89#endif /* BB_FEATURE_GREP_CONTEXT */ 89#endif /* CONFIG_FEATURE_GREP_CONTEXT */
90 90
91 while ((line = get_line_from_file(file)) != NULL) { 91 while ((line = get_line_from_file(file)) != NULL) {
92 chomp(line); 92 chomp(line);
@@ -116,7 +116,7 @@ static void grep_file(FILE *file)
116 116
117 /* print the matched line */ 117 /* print the matched line */
118 if (print_match_counts == 0) { 118 if (print_match_counts == 0) {
119#ifdef BB_FEATURE_GREP_CONTEXT 119#ifdef CONFIG_FEATURE_GREP_CONTEXT
120 int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1; 120 int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1;
121 121
122 /* if we were told to print 'before' lines and there is at least 122 /* if we were told to print 'before' lines and there is at least
@@ -145,11 +145,11 @@ static void grep_file(FILE *file)
145 145
146 /* make a note that we need to print 'after' lines */ 146 /* make a note that we need to print 'after' lines */
147 print_n_lines_after = lines_after; 147 print_n_lines_after = lines_after;
148#endif /* BB_FEATURE_GREP_CONTEXT */ 148#endif /* CONFIG_FEATURE_GREP_CONTEXT */
149 print_line(line, linenum, ':'); 149 print_line(line, linenum, ':');
150 } 150 }
151 } 151 }
152#ifdef BB_FEATURE_GREP_CONTEXT 152#ifdef CONFIG_FEATURE_GREP_CONTEXT
153 else { /* no match */ 153 else { /* no match */
154 /* Add the line to the circular 'before' buffer */ 154 /* Add the line to the circular 'before' buffer */
155 if(lines_before) { 155 if(lines_before) {
@@ -165,7 +165,7 @@ static void grep_file(FILE *file)
165 print_line(line, linenum, '-'); 165 print_line(line, linenum, '-');
166 print_n_lines_after--; 166 print_n_lines_after--;
167 } 167 }
168#endif /* BB_FEATURE_GREP_CONTEXT */ 168#endif /* CONFIG_FEATURE_GREP_CONTEXT */
169 } /* for */ 169 } /* for */
170 free(line); 170 free(line);
171 } 171 }
@@ -215,7 +215,7 @@ static void load_regexes_from_file(const char *filename)
215} 215}
216 216
217 217
218#ifdef BB_FEATURE_CLEAN_UP 218#ifdef CONFIG_FEATURE_CLEAN_UP
219static void destroy_regexes() 219static void destroy_regexes()
220{ 220{
221 if (regexes == NULL) 221 if (regexes == NULL)
@@ -233,11 +233,11 @@ static void destroy_regexes()
233extern int grep_main(int argc, char **argv) 233extern int grep_main(int argc, char **argv)
234{ 234{
235 int opt; 235 int opt;
236#ifdef BB_FEATURE_GREP_CONTEXT 236#ifdef CONFIG_FEATURE_GREP_CONTEXT
237 char *junk; 237 char *junk;
238#endif 238#endif
239 239
240#ifdef BB_FEATURE_CLEAN_UP 240#ifdef CONFIG_FEATURE_CLEAN_UP
241 /* destroy command strings on exit */ 241 /* destroy command strings on exit */
242 if (atexit(destroy_regexes) == -1) 242 if (atexit(destroy_regexes) == -1)
243 perror_msg_and_die("atexit"); 243 perror_msg_and_die("atexit");
@@ -245,7 +245,7 @@ extern int grep_main(int argc, char **argv)
245 245
246 /* do normal option parsing */ 246 /* do normal option parsing */
247 while ((opt = getopt(argc, argv, "iHhlnqvsce:f:" 247 while ((opt = getopt(argc, argv, "iHhlnqvsce:f:"
248#ifdef BB_FEATURE_GREP_CONTEXT 248#ifdef CONFIG_FEATURE_GREP_CONTEXT
249"A:B:C:" 249"A:B:C:"
250#endif 250#endif
251)) > 0) { 251)) > 0) {
@@ -283,7 +283,7 @@ extern int grep_main(int argc, char **argv)
283 case 'f': 283 case 'f':
284 load_regexes_from_file(optarg); 284 load_regexes_from_file(optarg);
285 break; 285 break;
286#ifdef BB_FEATURE_GREP_CONTEXT 286#ifdef CONFIG_FEATURE_GREP_CONTEXT
287 case 'A': 287 case 'A':
288 lines_after = strtoul(optarg, &junk, 10); 288 lines_after = strtoul(optarg, &junk, 10);
289 if(*junk != '\0') 289 if(*junk != '\0')
@@ -301,7 +301,7 @@ extern int grep_main(int argc, char **argv)
301 error_msg_and_die("invalid context length argument"); 301 error_msg_and_die("invalid context length argument");
302 before_buf = (char **)calloc(lines_before, sizeof(char *)); 302 before_buf = (char **)calloc(lines_before, sizeof(char *));
303 break; 303 break;
304#endif /* BB_FEATURE_GREP_CONTEXT */ 304#endif /* CONFIG_FEATURE_GREP_CONTEXT */
305 default: 305 default:
306 show_usage(); 306 show_usage();
307 } 307 }
@@ -321,7 +321,7 @@ extern int grep_main(int argc, char **argv)
321 /* sanity checks */ 321 /* sanity checks */
322 if (print_match_counts || be_quiet || print_files_with_matches) { 322 if (print_match_counts || be_quiet || print_files_with_matches) {
323 print_line_num = 0; 323 print_line_num = 0;
324#ifdef BB_FEATURE_GREP_CONTEXT 324#ifdef CONFIG_FEATURE_GREP_CONTEXT
325 lines_before = 0; 325 lines_before = 0;
326 lines_after = 0; 326 lines_after = 0;
327#endif 327#endif
diff --git a/findutils/which.c b/findutils/which.c
index c460ffdd1..eec5fdbfb 100644
--- a/findutils/which.c
+++ b/findutils/which.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Which implementation for busybox 3 * Which implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 48adae90a..5d64d0c9f 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -1,9 +1,9 @@
1/* 1/*
2 * Mini xargs implementation for busybox 2 * Mini xargs implementation for busybox
3 * 3 *
4 * Copyright (C) 1999,2000,2001 by Lineo, inc. 4 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
5 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * Remixed by Mark Whitley <markw@lineo.com>, <markw@codepoet.org> 6 * Remixed by Mark Whitley <markw@codepoet.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -95,7 +95,7 @@ int xargs_main(int argc, char **argv)
95 free(file_to_act_on); 95 free(file_to_act_on);
96 } 96 }
97 97
98#ifdef BB_FEATURE_CLEAN_UP 98#ifdef CONFIG_FEATURE_CLEAN_UP
99 free(cmd_to_be_executed); 99 free(cmd_to_be_executed);
100#endif 100#endif
101 101
diff --git a/free.c b/free.c
deleted file mode 100644
index 2e34a972c..000000000
--- a/free.c
+++ /dev/null
@@ -1,69 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini free implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24/* getopt not needed */
25
26#include <stdio.h>
27#include <errno.h>
28#include <stdlib.h>
29#include "busybox.h"
30
31extern int free_main(int argc, char **argv)
32{
33 struct sysinfo info;
34 sysinfo(&info);
35
36 /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
37 if (info.mem_unit==0) {
38 info.mem_unit=1;
39 }
40 info.mem_unit*=1024;
41
42 /* TODO: Make all this stuff not overflow when mem >= 4 Gib */
43 info.totalram/=info.mem_unit;
44 info.freeram/=info.mem_unit;
45 info.totalswap/=info.mem_unit;
46 info.freeswap/=info.mem_unit;
47 info.sharedram/=info.mem_unit;
48 info.bufferram/=info.mem_unit;
49
50 if (argc > 1 && **(argv + 1) == '-')
51 show_usage();
52
53 printf("%6s%13s%13s%13s%13s%13s\n", "", "total", "used", "free",
54 "shared", "buffers");
55
56 printf("%6s%13ld%13ld%13ld%13ld%13ld\n", "Mem:", info.totalram,
57 info.totalram-info.freeram, info.freeram,
58 info.sharedram, info.bufferram);
59
60 printf("%6s%13ld%13ld%13ld\n", "Swap:", info.totalswap,
61 info.totalswap-info.freeswap, info.freeswap);
62
63 printf("%6s%13ld%13ld%13ld\n", "Total:", info.totalram+info.totalswap,
64 (info.totalram-info.freeram)+(info.totalswap-info.freeswap),
65 info.freeram+info.freeswap);
66 return EXIT_SUCCESS;
67}
68
69
diff --git a/freeramdisk.c b/freeramdisk.c
deleted file mode 100644
index aabb5f988..000000000
--- a/freeramdisk.c
+++ /dev/null
@@ -1,64 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * freeramdisk implementation for busybox
4 *
5 * Copyright (C) 2000 and written by Emanuele Caratti <wiz@iol.it>
6 * Adjusted a bit by Erik Andersen <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <stdio.h>
25#include <string.h>
26#include <sys/types.h>
27#include <fcntl.h>
28#include <sys/ioctl.h>
29#include <errno.h>
30#include <stdlib.h>
31#include "busybox.h"
32
33
34/* From linux/fs.h */
35#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
36
37extern int
38freeramdisk_main(int argc, char **argv)
39{
40 FILE *f;
41
42 if (argc != 2 || *argv[1] == '-') {
43 show_usage();
44 }
45
46 f = xfopen(argv[1], "r+");
47
48 if (ioctl(fileno(f), BLKFLSBUF) < 0) {
49 perror_msg_and_die("failed ioctl on %s", argv[1]);
50 }
51 /* Don't bother closing. Exit does
52 * that, so we can save a few bytes */
53 /* close(f); */
54 return EXIT_SUCCESS;
55}
56
57/*
58Local Variables:
59c-file-style: "linux"
60c-basic-offset: 4
61tab-width: 4
62End:
63*/
64
diff --git a/fsck_minix.c b/fsck_minix.c
deleted file mode 100644
index 952968d85..000000000
--- a/fsck_minix.c
+++ /dev/null
@@ -1,1478 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fsck.c - a file system consistency checker for Linux.
4 *
5 * (C) 1991, 1992 Linus Torvalds. This file may be redistributed
6 * as per the GNU copyleft.
7 */
8
9/*
10 * 09.11.91 - made the first rudimetary functions
11 *
12 * 10.11.91 - updated, does checking, no repairs yet.
13 * Sent out to the mailing-list for testing.
14 *
15 * 14.11.91 - Testing seems to have gone well. Added some
16 * correction-code, and changed some functions.
17 *
18 * 15.11.91 - More correction code. Hopefully it notices most
19 * cases now, and tries to do something about them.
20 *
21 * 16.11.91 - More corrections (thanks to Mika Jalava). Most
22 * things seem to work now. Yeah, sure.
23 *
24 *
25 * 19.04.92 - Had to start over again from this old version, as a
26 * kernel bug ate my enhanced fsck in february.
27 *
28 * 28.02.93 - added support for different directory entry sizes..
29 *
30 * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with
31 * super-block information
32 *
33 * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
34 * to that required by fsutil
35 *
36 * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu)
37 * Added support for file system valid flag. Also
38 * added program_version variable and output of
39 * program name and version number when program
40 * is executed.
41 *
42 * 30.10.94 - added support for v2 filesystem
43 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
44 *
45 * 10.12.94 - added test to prevent checking of mounted fs adapted
46 * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck
47 * program. (Daniel Quinlan, quinlan@yggdrasil.com)
48 *
49 * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such
50 * for modern libcs (janl@math.uio.no, Nicolai Langfeldt)
51 *
52 * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk
53 * (Russell King). He made them for ARM. It would seem
54 * that the ARM is powerful enough to do this in C whereas
55 * i386 and m64k must use assembly to get it fast >:-)
56 * This should make minix fsck systemindependent.
57 * (janl@math.uio.no, Nicolai Langfeldt)
58 *
59 * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler
60 * warnings. Added mc68k bitops from
61 * Joerg Dorchain <dorchain@mpi-sb.mpg.de>.
62 *
63 * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by
64 * Andreas Schwab.
65 *
66 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
67 * - added Native Language Support
68 *
69 *
70 * I've had no time to add comments - hopefully the function names
71 * are comments enough. As with all file system checkers, this assumes
72 * the file system is quiescent - don't use it on a mounted device
73 * unless you can be sure nobody is writing to it (and remember that the
74 * kernel can write to it when it searches for files).
75 *
76 * Usuage: fsck [-larvsm] device
77 * -l for a listing of all the filenames
78 * -a for automatic repairs (not implemented)
79 * -r for repairs (interactive) (not implemented)
80 * -v for verbose (tells how many files)
81 * -s for super-block info
82 * -m for minix-like "mode not cleared" warnings
83 * -f force filesystem check even if filesystem marked as valid
84 *
85 * The device may be a block device or a image of one, but this isn't
86 * enforced (but it's not much fun on a character device :-).
87 */
88
89#include <stdio.h>
90#include <errno.h>
91#include <unistd.h>
92#include <string.h>
93#include <fcntl.h>
94#include <ctype.h>
95#include <stdlib.h>
96#include <termios.h>
97#include <mntent.h>
98#include <sys/param.h>
99#include "busybox.h"
100
101static const int MINIX_ROOT_INO = 1;
102static const int MINIX_LINK_MAX = 250;
103static const int MINIX2_LINK_MAX = 65530;
104
105static const int MINIX_I_MAP_SLOTS = 8;
106static const int MINIX_Z_MAP_SLOTS = 64;
107static const int MINIX_SUPER_MAGIC = 0x137F; /* original minix fs */
108static const int MINIX_SUPER_MAGIC2 = 0x138F; /* minix fs, 30 char names */
109static const int MINIX2_SUPER_MAGIC = 0x2468; /* minix V2 fs */
110static const int MINIX2_SUPER_MAGIC2 = 0x2478; /* minix V2 fs, 30 char names */
111static const int MINIX_VALID_FS = 0x0001; /* Clean fs. */
112static const int MINIX_ERROR_FS = 0x0002; /* fs has errors. */
113
114#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
115#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
116
117static const int MINIX_V1 = 0x0001; /* original minix fs */
118static const int MINIX_V2 = 0x0002; /* minix V2 fs */
119
120#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
121
122/*
123 * This is the original minix inode layout on disk.
124 * Note the 8-bit gid and atime and ctime.
125 */
126struct minix_inode {
127 u_int16_t i_mode;
128 u_int16_t i_uid;
129 u_int32_t i_size;
130 u_int32_t i_time;
131 u_int8_t i_gid;
132 u_int8_t i_nlinks;
133 u_int16_t i_zone[9];
134};
135
136/*
137 * The new minix inode has all the time entries, as well as
138 * long block numbers and a third indirect block (7+1+1+1
139 * instead of 7+1+1). Also, some previously 8-bit values are
140 * now 16-bit. The inode is now 64 bytes instead of 32.
141 */
142struct minix2_inode {
143 u_int16_t i_mode;
144 u_int16_t i_nlinks;
145 u_int16_t i_uid;
146 u_int16_t i_gid;
147 u_int32_t i_size;
148 u_int32_t i_atime;
149 u_int32_t i_mtime;
150 u_int32_t i_ctime;
151 u_int32_t i_zone[10];
152};
153
154/*
155 * minix super-block data on disk
156 */
157struct minix_super_block {
158 u_int16_t s_ninodes;
159 u_int16_t s_nzones;
160 u_int16_t s_imap_blocks;
161 u_int16_t s_zmap_blocks;
162 u_int16_t s_firstdatazone;
163 u_int16_t s_log_zone_size;
164 u_int32_t s_max_size;
165 u_int16_t s_magic;
166 u_int16_t s_state;
167 u_int32_t s_zones;
168};
169
170struct minix_dir_entry {
171 u_int16_t inode;
172 char name[0];
173};
174
175#define BLOCK_SIZE_BITS 10
176#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
177
178#define NAME_MAX 255 /* # chars in a file name */
179
180#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
181
182#ifndef BLKGETSIZE
183#define BLKGETSIZE _IO(0x12,96) /* return device size */
184#endif
185
186#ifndef __linux__
187#define volatile
188#endif
189
190static const int ROOT_INO = 1;
191
192#define UPPER(size,n) ((size+((n)-1))/(n))
193#define INODE_SIZE (sizeof(struct minix_inode))
194#ifdef BB_FEATURE_MINIX2
195#define INODE_SIZE2 (sizeof(struct minix2_inode))
196#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
197 : MINIX_INODES_PER_BLOCK))
198#else
199#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
200#endif
201#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
202
203#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
204
205static char *program_version = "1.2 - 11/11/96";
206static char *device_name = NULL;
207static int IN;
208static int repair = 0, automatic = 0, verbose = 0, list = 0, show =
209 0, warn_mode = 0, force = 0;
210static int directory = 0, regular = 0, blockdev = 0, chardev = 0, links =
211 0, symlinks = 0, total = 0;
212
213static int changed = 0; /* flags if the filesystem has been changed */
214static int errors_uncorrected = 0; /* flag if some error was not corrected */
215static int dirsize = 16;
216static int namelen = 14;
217static int version2 = 0;
218static struct termios termios;
219static int termios_set = 0;
220
221/* File-name data */
222static const int MAX_DEPTH = 32;
223static int name_depth = 0;
224// static char name_list[MAX_DEPTH][BUFSIZ + 1];
225static char **name_list = NULL;
226
227static char *inode_buffer = NULL;
228
229#define Inode (((struct minix_inode *) inode_buffer)-1)
230#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
231static char super_block_buffer[BLOCK_SIZE];
232
233#define Super (*(struct minix_super_block *)super_block_buffer)
234#define INODES ((unsigned long)Super.s_ninodes)
235#ifdef BB_FEATURE_MINIX2
236#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
237#else
238#define ZONES ((unsigned long)(Super.s_nzones))
239#endif
240#define IMAPS ((unsigned long)Super.s_imap_blocks)
241#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
242#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
243#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
244#define MAXSIZE ((unsigned long)Super.s_max_size)
245#define MAGIC (Super.s_magic)
246#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
247
248static char *inode_map;
249static char *zone_map;
250
251static unsigned char *inode_count = NULL;
252static unsigned char *zone_count = NULL;
253
254static void recursive_check(unsigned int ino);
255#ifdef BB_FEATURE_MINIX2
256static void recursive_check2(unsigned int ino);
257#endif
258
259static inline int bit(char * a,unsigned int i)
260{
261 return (a[i >> 3] & (1<<(i & 7))) != 0;
262}
263#define inode_in_use(x) (bit(inode_map,(x)))
264#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
265
266#define mark_inode(x) (setbit(inode_map,(x)),changed=1)
267#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1)
268
269#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1)
270#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1)
271
272static void leave(int) __attribute__ ((noreturn));
273static void leave(int status)
274{
275 if (termios_set)
276 tcsetattr(0, TCSANOW, &termios);
277 exit(status);
278}
279
280static void die(const char *str)
281{
282 error_msg("%s", str);
283 leave(8);
284}
285
286/*
287 * This simply goes through the file-name data and prints out the
288 * current file.
289 */
290static void print_current_name(void)
291{
292 int i = 0;
293
294 while (i < name_depth)
295 printf("/%.*s", namelen, name_list[i++]);
296 if (i == 0)
297 printf("/");
298}
299
300static int ask(const char *string, int def)
301{
302 int c;
303
304 if (!repair) {
305 printf("\n");
306 errors_uncorrected = 1;
307 return 0;
308 }
309 if (automatic) {
310 printf("\n");
311 if (!def)
312 errors_uncorrected = 1;
313 return def;
314 }
315 printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
316 for (;;) {
317 fflush(stdout);
318 if ((c = getchar()) == EOF) {
319 if (!def)
320 errors_uncorrected = 1;
321 return def;
322 }
323 c = toupper(c);
324 if (c == 'Y') {
325 def = 1;
326 break;
327 } else if (c == 'N') {
328 def = 0;
329 break;
330 } else if (c == ' ' || c == '\n')
331 break;
332 }
333 if (def)
334 printf("y\n");
335 else {
336 printf("n\n");
337 errors_uncorrected = 1;
338 }
339 return def;
340}
341
342/*
343 * Make certain that we aren't checking a filesystem that is on a
344 * mounted partition. Code adapted from e2fsck, Copyright (C) 1993,
345 * 1994 Theodore Ts'o. Also licensed under GPL.
346 */
347static void check_mount(void)
348{
349 FILE *f;
350 struct mntent *mnt;
351 int cont;
352 int fd;
353
354 if ((f = setmntent(MOUNTED, "r")) == NULL)
355 return;
356 while ((mnt = getmntent(f)) != NULL)
357 if (strcmp(device_name, mnt->mnt_fsname) == 0)
358 break;
359 endmntent(f);
360 if (!mnt)
361 return;
362
363 /*
364 * If the root is mounted read-only, then /etc/mtab is
365 * probably not correct; so we won't issue a warning based on
366 * it.
367 */
368 fd = open(MOUNTED, O_RDWR);
369 if (fd < 0 && errno == EROFS)
370 return;
371 else
372 close(fd);
373
374 printf("%s is mounted. ", device_name);
375 if (isatty(0) && isatty(1))
376 cont = ask("Do you really want to continue", 0);
377 else
378 cont = 0;
379 if (!cont) {
380 printf("check aborted.\n");
381 exit(0);
382 }
383 return;
384}
385
386/*
387 * check_zone_nr checks to see that *nr is a valid zone nr. If it
388 * isn't, it will possibly be repaired. Check_zone_nr sets *corrected
389 * if an error was corrected, and returns the zone (0 for no zone
390 * or a bad zone-number).
391 */
392static int check_zone_nr(unsigned short *nr, int *corrected)
393{
394 if (!*nr)
395 return 0;
396 if (*nr < FIRSTZONE)
397 printf("Zone nr < FIRSTZONE in file `");
398 else if (*nr >= ZONES)
399 printf("Zone nr >= ZONES in file `");
400 else
401 return *nr;
402 print_current_name();
403 printf("'.");
404 if (ask("Remove block", 1)) {
405 *nr = 0;
406 *corrected = 1;
407 }
408 return 0;
409}
410
411#ifdef BB_FEATURE_MINIX2
412static int check_zone_nr2(unsigned int *nr, int *corrected)
413{
414 if (!*nr)
415 return 0;
416 if (*nr < FIRSTZONE)
417 printf("Zone nr < FIRSTZONE in file `");
418 else if (*nr >= ZONES)
419 printf("Zone nr >= ZONES in file `");
420 else
421 return *nr;
422 print_current_name();
423 printf("'.");
424 if (ask("Remove block", 1)) {
425 *nr = 0;
426 *corrected = 1;
427 }
428 return 0;
429}
430#endif
431
432/*
433 * read-block reads block nr into the buffer at addr.
434 */
435static void read_block(unsigned int nr, char *addr)
436{
437 if (!nr) {
438 memset(addr, 0, BLOCK_SIZE);
439 return;
440 }
441 if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) {
442 printf("Read error: unable to seek to block in file '");
443 print_current_name();
444 printf("'\n");
445 memset(addr, 0, BLOCK_SIZE);
446 errors_uncorrected = 1;
447 } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) {
448 printf("Read error: bad block in file '");
449 print_current_name();
450 printf("'\n");
451 memset(addr, 0, BLOCK_SIZE);
452 errors_uncorrected = 1;
453 }
454}
455
456/*
457 * write_block writes block nr to disk.
458 */
459static void write_block(unsigned int nr, char *addr)
460{
461 if (!nr)
462 return;
463 if (nr < FIRSTZONE || nr >= ZONES) {
464 printf("Internal error: trying to write bad block\n"
465 "Write request ignored\n");
466 errors_uncorrected = 1;
467 return;
468 }
469 if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET))
470 die("seek failed in write_block");
471 if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) {
472 printf("Write error: bad block in file '");
473 print_current_name();
474 printf("'\n");
475 errors_uncorrected = 1;
476 }
477}
478
479/*
480 * map-block calculates the absolute block nr of a block in a file.
481 * It sets 'changed' if the inode has needed changing, and re-writes
482 * any indirect blocks with errors.
483 */
484static int map_block(struct minix_inode *inode, unsigned int blknr)
485{
486 unsigned short ind[BLOCK_SIZE >> 1];
487 unsigned short dind[BLOCK_SIZE >> 1];
488 int blk_chg, block, result;
489
490 if (blknr < 7)
491 return check_zone_nr(inode->i_zone + blknr, &changed);
492 blknr -= 7;
493 if (blknr < 512) {
494 block = check_zone_nr(inode->i_zone + 7, &changed);
495 read_block(block, (char *) ind);
496 blk_chg = 0;
497 result = check_zone_nr(blknr + ind, &blk_chg);
498 if (blk_chg)
499 write_block(block, (char *) ind);
500 return result;
501 }
502 blknr -= 512;
503 block = check_zone_nr(inode->i_zone + 8, &changed);
504 read_block(block, (char *) dind);
505 blk_chg = 0;
506 result = check_zone_nr(dind + (blknr / 512), &blk_chg);
507 if (blk_chg)
508 write_block(block, (char *) dind);
509 block = result;
510 read_block(block, (char *) ind);
511 blk_chg = 0;
512 result = check_zone_nr(ind + (blknr % 512), &blk_chg);
513 if (blk_chg)
514 write_block(block, (char *) ind);
515 return result;
516}
517
518#ifdef BB_FEATURE_MINIX2
519static int map_block2(struct minix2_inode *inode, unsigned int blknr)
520{
521 unsigned int ind[BLOCK_SIZE >> 2];
522 unsigned int dind[BLOCK_SIZE >> 2];
523 unsigned int tind[BLOCK_SIZE >> 2];
524 int blk_chg, block, result;
525
526 if (blknr < 7)
527 return check_zone_nr2(inode->i_zone + blknr, &changed);
528 blknr -= 7;
529 if (blknr < 256) {
530 block = check_zone_nr2(inode->i_zone + 7, &changed);
531 read_block(block, (char *) ind);
532 blk_chg = 0;
533 result = check_zone_nr2(blknr + ind, &blk_chg);
534 if (blk_chg)
535 write_block(block, (char *) ind);
536 return result;
537 }
538 blknr -= 256;
539 if (blknr >= 256 * 256) {
540 block = check_zone_nr2(inode->i_zone + 8, &changed);
541 read_block(block, (char *) dind);
542 blk_chg = 0;
543 result = check_zone_nr2(dind + blknr / 256, &blk_chg);
544 if (blk_chg)
545 write_block(block, (char *) dind);
546 block = result;
547 read_block(block, (char *) ind);
548 blk_chg = 0;
549 result = check_zone_nr2(ind + blknr % 256, &blk_chg);
550 if (blk_chg)
551 write_block(block, (char *) ind);
552 return result;
553 }
554 blknr -= 256 * 256;
555 block = check_zone_nr2(inode->i_zone + 9, &changed);
556 read_block(block, (char *) tind);
557 blk_chg = 0;
558 result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg);
559 if (blk_chg)
560 write_block(block, (char *) tind);
561 block = result;
562 read_block(block, (char *) dind);
563 blk_chg = 0;
564 result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg);
565 if (blk_chg)
566 write_block(block, (char *) dind);
567 block = result;
568 read_block(block, (char *) ind);
569 blk_chg = 0;
570 result = check_zone_nr2(ind + blknr % 256, &blk_chg);
571 if (blk_chg)
572 write_block(block, (char *) ind);
573 return result;
574}
575#endif
576
577static void write_super_block(void)
578{
579 /*
580 * Set the state of the filesystem based on whether or not there
581 * are uncorrected errors. The filesystem valid flag is
582 * unconditionally set if we get this far.
583 */
584 Super.s_state |= MINIX_VALID_FS;
585 if (errors_uncorrected)
586 Super.s_state |= MINIX_ERROR_FS;
587 else
588 Super.s_state &= ~MINIX_ERROR_FS;
589
590 if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
591 die("seek failed in write_super_block");
592 if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE))
593 die("unable to write super-block");
594
595 return;
596}
597
598static void write_tables(void)
599{
600 write_super_block();
601
602 if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE))
603 die("Unable to write inode map");
604 if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE))
605 die("Unable to write zone map");
606 if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE))
607 die("Unable to write inodes");
608}
609
610static void get_dirsize(void)
611{
612 int block;
613 char blk[BLOCK_SIZE];
614 int size;
615
616#ifdef BB_FEATURE_MINIX2
617 if (version2)
618 block = Inode2[ROOT_INO].i_zone[0];
619 else
620#endif
621 block = Inode[ROOT_INO].i_zone[0];
622 read_block(block, blk);
623 for (size = 16; size < BLOCK_SIZE; size <<= 1) {
624 if (strcmp(blk + size + 2, "..") == 0) {
625 dirsize = size;
626 namelen = size - 2;
627 return;
628 }
629 }
630 /* use defaults */
631}
632
633static void read_superblock(void)
634{
635 if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
636 die("seek failed");
637 if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE))
638 die("unable to read super block");
639 if (MAGIC == MINIX_SUPER_MAGIC) {
640 namelen = 14;
641 dirsize = 16;
642 version2 = 0;
643 } else if (MAGIC == MINIX_SUPER_MAGIC2) {
644 namelen = 30;
645 dirsize = 32;
646 version2 = 0;
647#ifdef BB_FEATURE_MINIX2
648 } else if (MAGIC == MINIX2_SUPER_MAGIC) {
649 namelen = 14;
650 dirsize = 16;
651 version2 = 1;
652 } else if (MAGIC == MINIX2_SUPER_MAGIC2) {
653 namelen = 30;
654 dirsize = 32;
655 version2 = 1;
656#endif
657 } else
658 die("bad magic number in super-block");
659 if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
660 die("Only 1k blocks/zones supported");
661 if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
662 die("bad s_imap_blocks field in super-block");
663 if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
664 die("bad s_zmap_blocks field in super-block");
665}
666
667static void read_tables(void)
668{
669 inode_map = xmalloc(IMAPS * BLOCK_SIZE);
670 zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
671 memset(inode_map, 0, sizeof(inode_map));
672 memset(zone_map, 0, sizeof(zone_map));
673 inode_buffer = xmalloc(INODE_BUFFER_SIZE);
674 inode_count = xmalloc(INODES + 1);
675 zone_count = xmalloc(ZONES);
676 if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE))
677 die("Unable to read inode map");
678 if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE))
679 die("Unable to read zone map");
680 if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE))
681 die("Unable to read inodes");
682 if (NORM_FIRSTZONE != FIRSTZONE) {
683 printf("Warning: Firstzone != Norm_firstzone\n");
684 errors_uncorrected = 1;
685 }
686 get_dirsize();
687 if (show) {
688 printf("%ld inodes\n", INODES);
689 printf("%ld blocks\n", ZONES);
690 printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
691 printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
692 printf("Maxsize=%ld\n", MAXSIZE);
693 printf("Filesystem state=%d\n", Super.s_state);
694 printf("namelen=%d\n\n", namelen);
695 }
696}
697
698static struct minix_inode *get_inode(unsigned int nr)
699{
700 struct minix_inode *inode;
701
702 if (!nr || nr > INODES)
703 return NULL;
704 total++;
705 inode = Inode + nr;
706 if (!inode_count[nr]) {
707 if (!inode_in_use(nr)) {
708 printf("Inode %d marked not used, but used for file '", nr);
709 print_current_name();
710 printf("'\n");
711 if (repair) {
712 if (ask("Mark in use", 1))
713 mark_inode(nr);
714 } else {
715 errors_uncorrected = 1;
716 }
717 }
718 if (S_ISDIR(inode->i_mode))
719 directory++;
720 else if (S_ISREG(inode->i_mode))
721 regular++;
722 else if (S_ISCHR(inode->i_mode))
723 chardev++;
724 else if (S_ISBLK(inode->i_mode))
725 blockdev++;
726 else if (S_ISLNK(inode->i_mode))
727 symlinks++;
728 else if (S_ISSOCK(inode->i_mode));
729 else if (S_ISFIFO(inode->i_mode));
730 else {
731 print_current_name();
732 printf(" has mode %05o\n", inode->i_mode);
733 }
734
735 } else
736 links++;
737 if (!++inode_count[nr]) {
738 printf("Warning: inode count too big.\n");
739 inode_count[nr]--;
740 errors_uncorrected = 1;
741 }
742 return inode;
743}
744
745#ifdef BB_FEATURE_MINIX2
746static struct minix2_inode *get_inode2(unsigned int nr)
747{
748 struct minix2_inode *inode;
749
750 if (!nr || nr > INODES)
751 return NULL;
752 total++;
753 inode = Inode2 + nr;
754 if (!inode_count[nr]) {
755 if (!inode_in_use(nr)) {
756 printf("Inode %d marked not used, but used for file '", nr);
757 print_current_name();
758 printf("'\n");
759 if (repair) {
760 if (ask("Mark in use", 1))
761 mark_inode(nr);
762 else
763 errors_uncorrected = 1;
764 }
765 }
766 if (S_ISDIR(inode->i_mode))
767 directory++;
768 else if (S_ISREG(inode->i_mode))
769 regular++;
770 else if (S_ISCHR(inode->i_mode))
771 chardev++;
772 else if (S_ISBLK(inode->i_mode))
773 blockdev++;
774 else if (S_ISLNK(inode->i_mode))
775 symlinks++;
776 else if (S_ISSOCK(inode->i_mode));
777 else if (S_ISFIFO(inode->i_mode));
778 else {
779 print_current_name();
780 printf(" has mode %05o\n", inode->i_mode);
781 }
782 } else
783 links++;
784 if (!++inode_count[nr]) {
785 printf("Warning: inode count too big.\n");
786 inode_count[nr]--;
787 errors_uncorrected = 1;
788 }
789 return inode;
790}
791#endif
792
793static void check_root(void)
794{
795 struct minix_inode *inode = Inode + ROOT_INO;
796
797 if (!inode || !S_ISDIR(inode->i_mode))
798 die("root inode isn't a directory");
799}
800
801#ifdef BB_FEATURE_MINIX2
802static void check_root2(void)
803{
804 struct minix2_inode *inode = Inode2 + ROOT_INO;
805
806 if (!inode || !S_ISDIR(inode->i_mode))
807 die("root inode isn't a directory");
808}
809#endif
810
811static int add_zone(unsigned short *znr, int *corrected)
812{
813 int result;
814 int block;
815
816 result = 0;
817 block = check_zone_nr(znr, corrected);
818 if (!block)
819 return 0;
820 if (zone_count[block]) {
821 printf("Block has been used before. Now in file `");
822 print_current_name();
823 printf("'.");
824 if (ask("Clear", 1)) {
825 *znr = 0;
826 block = 0;
827 *corrected = 1;
828 }
829 }
830 if (!block)
831 return 0;
832 if (!zone_in_use(block)) {
833 printf("Block %d in file `", block);
834 print_current_name();
835 printf("' is marked not in use.");
836 if (ask("Correct", 1))
837 mark_zone(block);
838 }
839 if (!++zone_count[block])
840 zone_count[block]--;
841 return block;
842}
843
844#ifdef BB_FEATURE_MINIX2
845static int add_zone2(unsigned int *znr, int *corrected)
846{
847 int result;
848 int block;
849
850 result = 0;
851 block = check_zone_nr2(znr, corrected);
852 if (!block)
853 return 0;
854 if (zone_count[block]) {
855 printf("Block has been used before. Now in file `");
856 print_current_name();
857 printf("'.");
858 if (ask("Clear", 1)) {
859 *znr = 0;
860 block = 0;
861 *corrected = 1;
862 }
863 }
864 if (!block)
865 return 0;
866 if (!zone_in_use(block)) {
867 printf("Block %d in file `", block);
868 print_current_name();
869 printf("' is marked not in use.");
870 if (ask("Correct", 1))
871 mark_zone(block);
872 }
873 if (!++zone_count[block])
874 zone_count[block]--;
875 return block;
876}
877#endif
878
879static void add_zone_ind(unsigned short *znr, int *corrected)
880{
881 static char blk[BLOCK_SIZE];
882 int i, chg_blk = 0;
883 int block;
884
885 block = add_zone(znr, corrected);
886 if (!block)
887 return;
888 read_block(block, blk);
889 for (i = 0; i < (BLOCK_SIZE >> 1); i++)
890 add_zone(i + (unsigned short *) blk, &chg_blk);
891 if (chg_blk)
892 write_block(block, blk);
893}
894
895#ifdef BB_FEATURE_MINIX2
896static void add_zone_ind2(unsigned int *znr, int *corrected)
897{
898 static char blk[BLOCK_SIZE];
899 int i, chg_blk = 0;
900 int block;
901
902 block = add_zone2(znr, corrected);
903 if (!block)
904 return;
905 read_block(block, blk);
906 for (i = 0; i < BLOCK_SIZE >> 2; i++)
907 add_zone2(i + (unsigned int *) blk, &chg_blk);
908 if (chg_blk)
909 write_block(block, blk);
910}
911#endif
912
913static void add_zone_dind(unsigned short *znr, int *corrected)
914{
915 static char blk[BLOCK_SIZE];
916 int i, blk_chg = 0;
917 int block;
918
919 block = add_zone(znr, corrected);
920 if (!block)
921 return;
922 read_block(block, blk);
923 for (i = 0; i < (BLOCK_SIZE >> 1); i++)
924 add_zone_ind(i + (unsigned short *) blk, &blk_chg);
925 if (blk_chg)
926 write_block(block, blk);
927}
928
929#ifdef BB_FEATURE_MINIX2
930static void add_zone_dind2(unsigned int *znr, int *corrected)
931{
932 static char blk[BLOCK_SIZE];
933 int i, blk_chg = 0;
934 int block;
935
936 block = add_zone2(znr, corrected);
937 if (!block)
938 return;
939 read_block(block, blk);
940 for (i = 0; i < BLOCK_SIZE >> 2; i++)
941 add_zone_ind2(i + (unsigned int *) blk, &blk_chg);
942 if (blk_chg)
943 write_block(block, blk);
944}
945
946static void add_zone_tind2(unsigned int *znr, int *corrected)
947{
948 static char blk[BLOCK_SIZE];
949 int i, blk_chg = 0;
950 int block;
951
952 block = add_zone2(znr, corrected);
953 if (!block)
954 return;
955 read_block(block, blk);
956 for (i = 0; i < BLOCK_SIZE >> 2; i++)
957 add_zone_dind2(i + (unsigned int *) blk, &blk_chg);
958 if (blk_chg)
959 write_block(block, blk);
960}
961#endif
962
963static void check_zones(unsigned int i)
964{
965 struct minix_inode *inode;
966
967 if (!i || i > INODES)
968 return;
969 if (inode_count[i] > 1) /* have we counted this file already? */
970 return;
971 inode = Inode + i;
972 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
973 !S_ISLNK(inode->i_mode)) return;
974 for (i = 0; i < 7; i++)
975 add_zone(i + inode->i_zone, &changed);
976 add_zone_ind(7 + inode->i_zone, &changed);
977 add_zone_dind(8 + inode->i_zone, &changed);
978}
979
980#ifdef BB_FEATURE_MINIX2
981static void check_zones2(unsigned int i)
982{
983 struct minix2_inode *inode;
984
985 if (!i || i > INODES)
986 return;
987 if (inode_count[i] > 1) /* have we counted this file already? */
988 return;
989 inode = Inode2 + i;
990 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode)
991 && !S_ISLNK(inode->i_mode))
992 return;
993 for (i = 0; i < 7; i++)
994 add_zone2(i + inode->i_zone, &changed);
995 add_zone_ind2(7 + inode->i_zone, &changed);
996 add_zone_dind2(8 + inode->i_zone, &changed);
997 add_zone_tind2(9 + inode->i_zone, &changed);
998}
999#endif
1000
1001static void check_file(struct minix_inode *dir, unsigned int offset)
1002{
1003 static char blk[BLOCK_SIZE];
1004 struct minix_inode *inode;
1005 int ino;
1006 char *name;
1007 int block;
1008
1009 block = map_block(dir, offset / BLOCK_SIZE);
1010 read_block(block, blk);
1011 name = blk + (offset % BLOCK_SIZE) + 2;
1012 ino = *(unsigned short *) (name - 2);
1013 if (ino > INODES) {
1014 print_current_name();
1015 printf(" contains a bad inode number for file '");
1016 printf("%.*s'.", namelen, name);
1017 if (ask(" Remove", 1)) {
1018 *(unsigned short *) (name - 2) = 0;
1019 write_block(block, blk);
1020 }
1021 ino = 0;
1022 }
1023 if (name_depth < MAX_DEPTH)
1024 strncpy(name_list[name_depth], name, namelen);
1025 name_depth++;
1026 inode = get_inode(ino);
1027 name_depth--;
1028 if (!offset) {
1029 if (!inode || strcmp(".", name)) {
1030 print_current_name();
1031 printf(": bad directory: '.' isn't first\n");
1032 errors_uncorrected = 1;
1033 } else
1034 return;
1035 }
1036 if (offset == dirsize) {
1037 if (!inode || strcmp("..", name)) {
1038 print_current_name();
1039 printf(": bad directory: '..' isn't second\n");
1040 errors_uncorrected = 1;
1041 } else
1042 return;
1043 }
1044 if (!inode)
1045 return;
1046 if (name_depth < MAX_DEPTH)
1047 strncpy(name_list[name_depth], name, namelen);
1048 name_depth++;
1049 if (list) {
1050 if (verbose)
1051 printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
1052 print_current_name();
1053 if (S_ISDIR(inode->i_mode))
1054 printf(":\n");
1055 else
1056 printf("\n");
1057 }
1058 check_zones(ino);
1059 if (inode && S_ISDIR(inode->i_mode))
1060 recursive_check(ino);
1061 name_depth--;
1062 return;
1063}
1064
1065#ifdef BB_FEATURE_MINIX2
1066static void check_file2(struct minix2_inode *dir, unsigned int offset)
1067{
1068 static char blk[BLOCK_SIZE];
1069 struct minix2_inode *inode;
1070 int ino;
1071 char *name;
1072 int block;
1073
1074 block = map_block2(dir, offset / BLOCK_SIZE);
1075 read_block(block, blk);
1076 name = blk + (offset % BLOCK_SIZE) + 2;
1077 ino = *(unsigned short *) (name - 2);
1078 if (ino > INODES) {
1079 print_current_name();
1080 printf(" contains a bad inode number for file '");
1081 printf("%.*s'.", namelen, name);
1082 if (ask(" Remove", 1)) {
1083 *(unsigned short *) (name - 2) = 0;
1084 write_block(block, blk);
1085 }
1086 ino = 0;
1087 }
1088 if (name_depth < MAX_DEPTH)
1089 strncpy(name_list[name_depth], name, namelen);
1090 name_depth++;
1091 inode = get_inode2(ino);
1092 name_depth--;
1093 if (!offset) {
1094 if (!inode || strcmp(".", name)) {
1095 print_current_name();
1096 printf(": bad directory: '.' isn't first\n");
1097 errors_uncorrected = 1;
1098 } else
1099 return;
1100 }
1101 if (offset == dirsize) {
1102 if (!inode || strcmp("..", name)) {
1103 print_current_name();
1104 printf(": bad directory: '..' isn't second\n");
1105 errors_uncorrected = 1;
1106 } else
1107 return;
1108 }
1109 if (!inode)
1110 return;
1111 name_depth++;
1112 if (list) {
1113 if (verbose)
1114 printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
1115 print_current_name();
1116 if (S_ISDIR(inode->i_mode))
1117 printf(":\n");
1118 else
1119 printf("\n");
1120 }
1121 check_zones2(ino);
1122 if (inode && S_ISDIR(inode->i_mode))
1123 recursive_check2(ino);
1124 name_depth--;
1125 return;
1126}
1127#endif
1128
1129static void recursive_check(unsigned int ino)
1130{
1131 struct minix_inode *dir;
1132 unsigned int offset;
1133
1134 dir = Inode + ino;
1135 if (!S_ISDIR(dir->i_mode))
1136 die("internal error");
1137 if (dir->i_size < 2 * dirsize) {
1138 print_current_name();
1139 printf(": bad directory: size<32");
1140 errors_uncorrected = 1;
1141 }
1142 for (offset = 0; offset < dir->i_size; offset += dirsize)
1143 check_file(dir, offset);
1144}
1145
1146#ifdef BB_FEATURE_MINIX2
1147static void recursive_check2(unsigned int ino)
1148{
1149 struct minix2_inode *dir;
1150 unsigned int offset;
1151
1152 dir = Inode2 + ino;
1153 if (!S_ISDIR(dir->i_mode))
1154 die("internal error");
1155 if (dir->i_size < 2 * dirsize) {
1156 print_current_name();
1157 printf(": bad directory: size < 32");
1158 errors_uncorrected = 1;
1159 }
1160 for (offset = 0; offset < dir->i_size; offset += dirsize)
1161 check_file2(dir, offset);
1162}
1163#endif
1164
1165static int bad_zone(int i)
1166{
1167 char buffer[1024];
1168
1169 if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET))
1170 die("seek failed in bad_zone");
1171 return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE));
1172}
1173
1174static void check_counts(void)
1175{
1176 int i;
1177
1178 for (i = 1; i <= INODES; i++) {
1179 if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) {
1180 printf("Inode %d mode not cleared.", i);
1181 if (ask("Clear", 1)) {
1182 Inode[i].i_mode = 0;
1183 changed = 1;
1184 }
1185 }
1186 if (!inode_count[i]) {
1187 if (!inode_in_use(i))
1188 continue;
1189 printf("Inode %d not used, marked used in the bitmap.", i);
1190 if (ask("Clear", 1))
1191 unmark_inode(i);
1192 continue;
1193 }
1194 if (!inode_in_use(i)) {
1195 printf("Inode %d used, marked unused in the bitmap.", i);
1196 if (ask("Set", 1))
1197 mark_inode(i);
1198 }
1199 if (Inode[i].i_nlinks != inode_count[i]) {
1200 printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.",
1201 i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[i]);
1202 if (ask("Set i_nlinks to count", 1)) {
1203 Inode[i].i_nlinks = inode_count[i];
1204 changed = 1;
1205 }
1206 }
1207 }
1208 for (i = FIRSTZONE; i < ZONES; i++) {
1209 if (zone_in_use(i) == zone_count[i])
1210 continue;
1211 if (!zone_count[i]) {
1212 if (bad_zone(i))
1213 continue;
1214 printf("Zone %d: marked in use, no file uses it.", i);
1215 if (ask("Unmark", 1))
1216 unmark_zone(i);
1217 continue;
1218 }
1219 printf("Zone %d: %sin use, counted=%d\n",
1220 i, zone_in_use(i) ? "" : "not ", zone_count[i]);
1221 }
1222}
1223
1224#ifdef BB_FEATURE_MINIX2
1225static void check_counts2(void)
1226{
1227 int i;
1228
1229 for (i = 1; i <= INODES; i++) {
1230 if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) {
1231 printf("Inode %d mode not cleared.", i);
1232 if (ask("Clear", 1)) {
1233 Inode2[i].i_mode = 0;
1234 changed = 1;
1235 }
1236 }
1237 if (!inode_count[i]) {
1238 if (!inode_in_use(i))
1239 continue;
1240 printf("Inode %d not used, marked used in the bitmap.", i);
1241 if (ask("Clear", 1))
1242 unmark_inode(i);
1243 continue;
1244 }
1245 if (!inode_in_use(i)) {
1246 printf("Inode %d used, marked unused in the bitmap.", i);
1247 if (ask("Set", 1))
1248 mark_inode(i);
1249 }
1250 if (Inode2[i].i_nlinks != inode_count[i]) {
1251 printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.",
1252 i, Inode2[i].i_mode, Inode2[i].i_nlinks,
1253 inode_count[i]);
1254 if (ask("Set i_nlinks to count", 1)) {
1255 Inode2[i].i_nlinks = inode_count[i];
1256 changed = 1;
1257 }
1258 }
1259 }
1260 for (i = FIRSTZONE; i < ZONES; i++) {
1261 if (zone_in_use(i) == zone_count[i])
1262 continue;
1263 if (!zone_count[i]) {
1264 if (bad_zone(i))
1265 continue;
1266 printf("Zone %d: marked in use, no file uses it.", i);
1267 if (ask("Unmark", 1))
1268 unmark_zone(i);
1269 continue;
1270 }
1271 printf("Zone %d: %sin use, counted=%d\n",
1272 i, zone_in_use(i) ? "" : "not ", zone_count[i]);
1273 }
1274}
1275#endif
1276
1277static void check(void)
1278{
1279 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
1280 memset(zone_count, 0, ZONES * sizeof(*zone_count));
1281 check_zones(ROOT_INO);
1282 recursive_check(ROOT_INO);
1283 check_counts();
1284}
1285
1286#ifdef BB_FEATURE_MINIX2
1287static void check2(void)
1288{
1289 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
1290 memset(zone_count, 0, ZONES * sizeof(*zone_count));
1291 check_zones2(ROOT_INO);
1292 recursive_check2(ROOT_INO);
1293 check_counts2();
1294}
1295#endif
1296
1297/* Wed Feb 9 15:17:06 MST 2000 */
1298/* dynamically allocate name_list (instead of making it static) */
1299static void alloc_name_list(void)
1300{
1301 int i;
1302
1303 name_list = xmalloc(sizeof(char *) * MAX_DEPTH);
1304 for (i = 0; i < MAX_DEPTH; i++)
1305 name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1);
1306}
1307
1308#ifdef BB_FEATURE_CLEAN_UP
1309/* execute this atexit() to deallocate name_list[] */
1310/* piptigger was here */
1311static void free_name_list(void)
1312{
1313 int i;
1314
1315 if (name_list) {
1316 for (i = 0; i < MAX_DEPTH; i++) {
1317 if (name_list[i]) {
1318 free(name_list[i]);
1319 }
1320 }
1321 free(name_list);
1322 }
1323}
1324#endif
1325
1326extern int fsck_minix_main(int argc, char **argv)
1327{
1328 struct termios tmp;
1329 int count;
1330 int retcode = 0;
1331
1332 alloc_name_list();
1333#ifdef BB_FEATURE_CLEAN_UP
1334 /* Don't bother to free memory. Exit does
1335 * that automagically, so we can save a few bytes */
1336 atexit(free_name_list);
1337#endif
1338
1339 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
1340 die("bad inode size");
1341#ifdef BB_FEATURE_MINIX2
1342 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
1343 die("bad v2 inode size");
1344#endif
1345 while (argc-- > 1) {
1346 argv++;
1347 if (argv[0][0] != '-') {
1348 if (device_name)
1349 show_usage();
1350 else
1351 device_name = argv[0];
1352 } else
1353 while (*++argv[0])
1354 switch (argv[0][0]) {
1355 case 'l':
1356 list = 1;
1357 break;
1358 case 'a':
1359 automatic = 1;
1360 repair = 1;
1361 break;
1362 case 'r':
1363 automatic = 0;
1364 repair = 1;
1365 break;
1366 case 'v':
1367 verbose = 1;
1368 break;
1369 case 's':
1370 show = 1;
1371 break;
1372 case 'm':
1373 warn_mode = 1;
1374 break;
1375 case 'f':
1376 force = 1;
1377 break;
1378 default:
1379 show_usage();
1380 }
1381 }
1382 if (!device_name)
1383 show_usage();
1384 check_mount(); /* trying to check a mounted filesystem? */
1385 if (repair && !automatic) {
1386 if (!isatty(0) || !isatty(1))
1387 die("need terminal for interactive repairs");
1388 }
1389 IN = open(device_name, repair ? O_RDWR : O_RDONLY);
1390 if (IN < 0){
1391 fprintf(stderr,"unable to open device '%s'.\n",device_name);
1392 leave(8);
1393 }
1394 for (count = 0; count < 3; count++)
1395 sync();
1396 read_superblock();
1397
1398 /*
1399 * Determine whether or not we should continue with the checking.
1400 * This is based on the status of the filesystem valid and error
1401 * flags and whether or not the -f switch was specified on the
1402 * command line.
1403 */
1404 printf("%s, %s\n", applet_name, program_version);
1405 if (!(Super.s_state & MINIX_ERROR_FS) &&
1406 (Super.s_state & MINIX_VALID_FS) && !force) {
1407 if (repair)
1408 printf("%s is clean, no check.\n", device_name);
1409 return retcode;
1410 } else if (force)
1411 printf("Forcing filesystem check on %s.\n", device_name);
1412 else if (repair)
1413 printf("Filesystem on %s is dirty, needs checking.\n",
1414 device_name);
1415
1416 read_tables();
1417
1418 if (repair && !automatic) {
1419 tcgetattr(0, &termios);
1420 tmp = termios;
1421 tmp.c_lflag &= ~(ICANON | ECHO);
1422 tcsetattr(0, TCSANOW, &tmp);
1423 termios_set = 1;
1424 }
1425#ifdef BB_FEATURE_MINIX2
1426 if (version2) {
1427 check_root2();
1428 check2();
1429 } else
1430#endif
1431 {
1432 check_root();
1433 check();
1434 }
1435 if (verbose) {
1436 int i, free_cnt;
1437
1438 for (i = 1, free_cnt = 0; i <= INODES; i++)
1439 if (!inode_in_use(i))
1440 free_cnt++;
1441 printf("\n%6ld inodes used (%ld%%)\n", (INODES - free_cnt),
1442 100 * (INODES - free_cnt) / INODES);
1443 for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++)
1444 if (!zone_in_use(i))
1445 free_cnt++;
1446 printf("%6ld zones used (%ld%%)\n", (ZONES - free_cnt),
1447 100 * (ZONES - free_cnt) / ZONES);
1448 printf("\n%6d regular files\n"
1449 "%6d directories\n"
1450 "%6d character device files\n"
1451 "%6d block device files\n"
1452 "%6d links\n"
1453 "%6d symbolic links\n"
1454 "------\n"
1455 "%6d files\n",
1456 regular, directory, chardev, blockdev,
1457 links - 2 * directory + 1, symlinks,
1458 total - 2 * directory + 1);
1459 }
1460 if (changed) {
1461 write_tables();
1462 printf("----------------------------\n"
1463 "FILE SYSTEM HAS BEEN CHANGED\n"
1464 "----------------------------\n");
1465 for (count = 0; count < 3; count++)
1466 sync();
1467 } else if (repair)
1468 write_super_block();
1469
1470 if (repair && !automatic)
1471 tcsetattr(0, TCSANOW, &termios);
1472
1473 if (changed)
1474 retcode += 3;
1475 if (errors_uncorrected)
1476 retcode += 4;
1477 return retcode;
1478}
diff --git a/getopt.c b/getopt.c
deleted file mode 100644
index 95ecba6e6..000000000
--- a/getopt.c
+++ /dev/null
@@ -1,402 +0,0 @@
1/*
2 * getopt.c - Enhanced implementation of BSD getopt(1)
3 * Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20/*
21 * Version 1.0-b4: Tue Sep 23 1997. First public release.
22 * Version 1.0: Wed Nov 19 1997.
23 * Bumped up the version number to 1.0
24 * Fixed minor typo (CSH instead of TCSH)
25 * Version 1.0.1: Tue Jun 3 1998
26 * Fixed sizeof instead of strlen bug
27 * Bumped up the version number to 1.0.1
28 * Version 1.0.2: Thu Jun 11 1998 (not present)
29 * Fixed gcc-2.8.1 warnings
30 * Fixed --version/-V option (not present)
31 * Version 1.0.5: Tue Jun 22 1999
32 * Make -u option work (not present)
33 * Version 1.0.6: Tue Jun 27 2000
34 * No important changes
35 * Version 1.1.0: Tue Jun 30 2000
36 * Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
37 * <misiek@misiek.eu.org>)
38 * Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
39 * Removed --version/-V and --help/-h in
40 * Removed prase_error(), using error_msg() from Busybox instead
41 * Replaced our_malloc with xmalloc and our_realloc with xrealloc
42 *
43 */
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49#include <ctype.h>
50#include <getopt.h>
51
52#include "busybox.h"
53
54/* NON_OPT is the code that is returned when a non-option is found in '+'
55 mode */
56static const int NON_OPT = 1;
57/* LONG_OPT is the code that is returned when a long option is found. */
58static const int LONG_OPT = 2;
59
60/* The shells recognized. */
61typedef enum {BASH,TCSH} shell_t;
62
63
64/* Some global variables that tells us how to parse. */
65static shell_t shell=BASH; /* The shell we generate output for. */
66static int quiet_errors=0; /* 0 is not quiet. */
67static int quiet_output=0; /* 0 is not quiet. */
68static int quote=1; /* 1 is do quote. */
69static int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */
70
71/* Function prototypes */
72static const char *normalize(const char *arg);
73static int generate_output(char * argv[],int argc,const char *optstr,
74 const struct option *longopts);
75static void add_long_options(char *options);
76static void add_longopt(const char *name,int has_arg);
77static void set_shell(const char *new_shell);
78
79
80/*
81 * This function 'normalizes' a single argument: it puts single quotes around
82 * it and escapes other special characters. If quote is false, it just
83 * returns its argument.
84 * Bash only needs special treatment for single quotes; tcsh also recognizes
85 * exclamation marks within single quotes, and nukes whitespace.
86 * This function returns a pointer to a buffer that is overwritten by
87 * each call.
88 */
89const char *normalize(const char *arg)
90{
91 static char *BUFFER=NULL;
92 const char *argptr=arg;
93 char *bufptr;
94
95 if (BUFFER != NULL)
96 free(BUFFER);
97
98 if (!quote) { /* Just copy arg */
99 BUFFER=xmalloc(strlen(arg)+1);
100
101 strcpy(BUFFER,arg);
102 return BUFFER;
103 }
104
105 /* Each character in arg may take upto four characters in the result:
106 For a quote we need a closing quote, a backslash, a quote and an
107 opening quote! We need also the global opening and closing quote,
108 and one extra character for '\0'. */
109 BUFFER=xmalloc(strlen(arg)*4+3);
110
111 bufptr=BUFFER;
112 *bufptr++='\'';
113
114 while (*argptr) {
115 if (*argptr == '\'') {
116 /* Quote: replace it with: '\'' */
117 *bufptr++='\'';
118 *bufptr++='\\';
119 *bufptr++='\'';
120 *bufptr++='\'';
121 } else if (shell==TCSH && *argptr=='!') {
122 /* Exclamation mark: replace it with: \! */
123 *bufptr++='\'';
124 *bufptr++='\\';
125 *bufptr++='!';
126 *bufptr++='\'';
127 } else if (shell==TCSH && *argptr=='\n') {
128 /* Newline: replace it with: \n */
129 *bufptr++='\\';
130 *bufptr++='n';
131 } else if (shell==TCSH && isspace(*argptr)) {
132 /* Non-newline whitespace: replace it with \<ws> */
133 *bufptr++='\'';
134 *bufptr++='\\';
135 *bufptr++=*argptr;
136 *bufptr++='\'';
137 } else
138 /* Just copy */
139 *bufptr++=*argptr;
140 argptr++;
141 }
142 *bufptr++='\'';
143 *bufptr++='\0';
144 return BUFFER;
145}
146
147/*
148 * Generate the output. argv[0] is the program name (used for reporting errors).
149 * argv[1..] contains the options to be parsed. argc must be the number of
150 * elements in argv (ie. 1 if there are no options, only the program name),
151 * optstr must contain the short options, and longopts the long options.
152 * Other settings are found in global variables.
153 */
154int generate_output(char * argv[],int argc,const char *optstr,
155 const struct option *longopts)
156{
157 int exit_code = 0; /* We assume everything will be OK */
158 int opt;
159 int longindex;
160 const char *charptr;
161
162 if (quiet_errors) /* No error reporting from getopt(3) */
163 opterr=0;
164 optind=0; /* Reset getopt(3) */
165
166 while ((opt = (alternative?
167 getopt_long_only(argc,argv,optstr,longopts,&longindex):
168 getopt_long(argc,argv,optstr,longopts,&longindex)))
169 != EOF)
170 if (opt == '?' || opt == ':' )
171 exit_code = 1;
172 else if (!quiet_output) {
173 if (opt == LONG_OPT) {
174 printf(" --%s",longopts[longindex].name);
175 if (longopts[longindex].has_arg)
176 printf(" %s",
177 normalize(optarg?optarg:""));
178 } else if (opt == NON_OPT)
179 printf(" %s",normalize(optarg));
180 else {
181 printf(" -%c",opt);
182 charptr = strchr(optstr,opt);
183 if (charptr != NULL && *++charptr == ':')
184 printf(" %s",
185 normalize(optarg?optarg:""));
186 }
187 }
188
189 if (! quiet_output) {
190 printf(" --");
191 while (optind < argc)
192 printf(" %s",normalize(argv[optind++]));
193 printf("\n");
194 }
195 return exit_code;
196}
197
198static struct option *long_options=NULL;
199static int long_options_length=0; /* Length of array */
200static int long_options_nr=0; /* Nr of used elements in array */
201static const int LONG_OPTIONS_INCR = 10;
202#define init_longopt() add_longopt(NULL,0)
203
204/* Register a long option. The contents of name is copied. */
205void add_longopt(const char *name,int has_arg)
206{
207 char *tmp;
208 if (!name) { /* init */
209 free(long_options);
210 long_options=NULL;
211 long_options_length=0;
212 long_options_nr=0;
213 }
214
215 if (long_options_nr == long_options_length) {
216 long_options_length += LONG_OPTIONS_INCR;
217 long_options=xrealloc(long_options,
218 sizeof(struct option) *
219 long_options_length);
220 }
221
222 long_options[long_options_nr].name=NULL;
223 long_options[long_options_nr].has_arg=0;
224 long_options[long_options_nr].flag=NULL;
225 long_options[long_options_nr].val=0;
226
227 if (long_options_nr) { /* Not for init! */
228 long_options[long_options_nr-1].has_arg=has_arg;
229 long_options[long_options_nr-1].flag=NULL;
230 long_options[long_options_nr-1].val=LONG_OPT;
231 tmp = xmalloc(strlen(name)+1);
232 strcpy(tmp,name);
233 long_options[long_options_nr-1].name=tmp;
234 }
235 long_options_nr++;
236}
237
238
239/*
240 * Register several long options. options is a string of long options,
241 * separated by commas or whitespace.
242 * This nukes options!
243 */
244void add_long_options(char *options)
245{
246 int arg_opt, tlen;
247 char *tokptr=strtok(options,", \t\n");
248 while (tokptr) {
249 arg_opt=no_argument;
250 tlen=strlen(tokptr);
251 if (tlen > 0) {
252 if (tokptr[tlen-1] == ':') {
253 if (tlen > 1 && tokptr[tlen-2] == ':') {
254 tokptr[tlen-2]='\0';
255 tlen -= 2;
256 arg_opt=optional_argument;
257 } else {
258 tokptr[tlen-1]='\0';
259 tlen -= 1;
260 arg_opt=required_argument;
261 }
262 if (tlen == 0)
263 error_msg("empty long option after -l or --long argument");
264 }
265 add_longopt(tokptr,arg_opt);
266 }
267 tokptr=strtok(NULL,", \t\n");
268 }
269}
270
271void set_shell(const char *new_shell)
272{
273 if (!strcmp(new_shell,"bash"))
274 shell=BASH;
275 else if (!strcmp(new_shell,"tcsh"))
276 shell=TCSH;
277 else if (!strcmp(new_shell,"sh"))
278 shell=BASH;
279 else if (!strcmp(new_shell,"csh"))
280 shell=TCSH;
281 else
282 error_msg("unknown shell after -s or --shell argument");
283}
284
285
286/* Exit codes:
287 * 0) No errors, succesful operation.
288 * 1) getopt(3) returned an error.
289 * 2) A problem with parameter parsing for getopt(1).
290 * 3) Internal error, out of memory
291 * 4) Returned for -T
292 */
293
294static struct option longopts[]=
295{
296 {"options",required_argument,NULL,'o'},
297 {"longoptions",required_argument,NULL,'l'},
298 {"quiet",no_argument,NULL,'q'},
299 {"quiet-output",no_argument,NULL,'Q'},
300 {"shell",required_argument,NULL,'s'},
301 {"test",no_argument,NULL,'T'},
302 {"unquoted",no_argument,NULL,'u'},
303 {"alternative",no_argument,NULL,'a'},
304 {"name",required_argument,NULL,'n'},
305 {NULL,0,NULL,0}
306};
307
308/* Stop scanning as soon as a non-option argument is found! */
309static const char *shortopts="+ao:l:n:qQs:Tu";
310
311
312int getopt_main(int argc, char *argv[])
313{
314 char *optstr=NULL;
315 char *name=NULL;
316 int opt;
317 int compatible=0;
318
319 init_longopt();
320
321 if (getenv("GETOPT_COMPATIBLE"))
322 compatible=1;
323
324 if (argc == 1) {
325 if (compatible) {
326 /* For some reason, the original getopt gave no error
327 when there were no arguments. */
328 printf(" --\n");
329 exit(0);
330 } else
331 error_msg_and_die("missing optstring argument");
332 }
333
334 if (argv[1][0] != '-' || compatible) {
335 quote=0;
336 optstr=xmalloc(strlen(argv[1])+1);
337 strcpy(optstr,argv[1]+strspn(argv[1],"-+"));
338 argv[1]=argv[0];
339 exit(generate_output(argv+1,argc-1,optstr,long_options));
340 }
341
342 while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
343 switch (opt) {
344 case 'a':
345 alternative=1;
346 break;
347 case 'o':
348 if (optstr)
349 free(optstr);
350 optstr=xmalloc(strlen(optarg)+1);
351 strcpy(optstr,optarg);
352 break;
353 case 'l':
354 add_long_options(optarg);
355 break;
356 case 'n':
357 if (name)
358 free(name);
359 name=xmalloc(strlen(optarg)+1);
360 strcpy(name,optarg);
361 break;
362 case 'q':
363 quiet_errors=1;
364 break;
365 case 'Q':
366 quiet_output=1;
367 break;
368 case 's':
369 set_shell(optarg);
370 break;
371 case 'T':
372 exit(4);
373 case 'u':
374 quote=0;
375 break;
376 default:
377 show_usage();
378 }
379
380 if (!optstr) {
381 if (optind >= argc)
382 error_msg_and_die("missing optstring argument");
383 else {
384 optstr=xmalloc(strlen(argv[optind])+1);
385 strcpy(optstr,argv[optind]);
386 optind++;
387 }
388 }
389 if (name)
390 argv[optind-1]=name;
391 else
392 argv[optind-1]=argv[0];
393 exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options));
394}
395
396/*
397 Local Variables:
398 c-file-style: "linux"
399 c-basic-offset: 4
400 tab-width: 4
401 End:
402*/
diff --git a/getty.c b/getty.c
deleted file mode 100644
index c6d0eb710..000000000
--- a/getty.c
+++ /dev/null
@@ -1,1232 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/* agetty.c - another getty program for Linux. By W. Z. Venema 1989
3 Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
4 This program is freely distributable. The entire man-page used to
5 be here. Now read the real man-page agetty.8 instead.
6
7 -f option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
8
9 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
10 - added Native Language Support
11
12 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net>
13 - enable hardware flow control before displaying /etc/issue
14
15*/
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <string.h>
21#include <sys/ioctl.h>
22#include <errno.h>
23#include <sys/stat.h>
24#include <sys/signal.h>
25#include <fcntl.h>
26#include <stdarg.h>
27#include <ctype.h>
28#include <utmp.h>
29#include <getopt.h>
30#include <termios.h>
31#include "busybox.h"
32
33#define _PATH_LOGIN "/bin/login"
34
35#ifdef linux
36#include <sys/param.h>
37#define USE_SYSLOG
38#endif
39
40extern void updwtmp(const char *filename, const struct utmp *ut);
41
42 /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
43#ifdef USE_SYSLOG
44#include <syslog.h>
45#endif
46
47
48 /*
49 * Some heuristics to find out what environment we are in: if it is not
50 * System V, assume it is SunOS 4.
51 */
52
53#ifdef LOGIN_PROCESS /* defined in System V utmp.h */
54#define SYSV_STYLE /* select System V style getty */
55#endif
56
57 /*
58 * Things you may want to modify.
59 *
60 * If ISSUE is not defined, agetty will never display the contents of the
61 * /etc/issue file. You will not want to spit out large "issue" files at the
62 * wrong baud rate. Relevant for System V only.
63 *
64 * You may disagree with the default line-editing etc. characters defined
65 * below. Note, however, that DEL cannot be used for interrupt generation
66 * and for line editing at the same time.
67 */
68
69#ifdef SYSV_STYLE
70#define ISSUE "/etc/issue" /* displayed before the login prompt */
71#include <sys/utsname.h>
72#include <time.h>
73#endif
74
75#define LOGIN " login: " /* login prompt */
76
77/* Some shorthands for control characters. */
78
79#define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */
80#define CR CTL('M') /* carriage return */
81#define NL CTL('J') /* line feed */
82#define BS CTL('H') /* back space */
83#define DEL CTL('?') /* delete */
84
85/* Defaults for line-editing etc. characters; you may want to change this. */
86
87#define DEF_ERASE DEL /* default erase character */
88#define DEF_INTR CTL('C') /* default interrupt character */
89#define DEF_QUIT CTL('\\') /* default quit char */
90#define DEF_KILL CTL('U') /* default kill char */
91#define DEF_EOF CTL('D') /* default EOF char */
92#define DEF_EOL 0
93#define DEF_SWITCH 0 /* default switch char */
94
95 /*
96 * SunOS 4.1.1 termio is broken. We must use the termios stuff instead,
97 * because the termio -> termios translation does not clear the termios
98 * CIBAUD bits. Therefore, the tty driver would sometimes report that input
99 * baud rate != output baud rate. I did not notice that problem with SunOS
100 * 4.1. We will use termios where available, and termio otherwise.
101 */
102
103/* linux 0.12 termio is broken too, if we use it c_cc[VERASE] isn't set
104 properly, but all is well if we use termios?! */
105
106#ifdef TCGETS
107#undef TCGETA
108#undef TCSETA
109#undef TCSETAW
110#define termio termios
111#define TCGETA TCGETS
112#define TCSETA TCSETS
113#define TCSETAW TCSETSW
114#endif
115
116 /*
117 * This program tries to not use the standard-i/o library. This keeps the
118 * executable small on systems that do not have shared libraries (System V
119 * Release <3).
120 */
121#ifndef BUFSIZ
122#define BUFSIZ 1024
123#endif
124
125 /*
126 * When multiple baud rates are specified on the command line, the first one
127 * we will try is the first one specified.
128 */
129
130#define FIRST_SPEED 0
131
132/* Storage for command-line options. */
133
134#define MAX_SPEED 10 /* max. nr. of baud rates */
135
136struct options {
137 int flags; /* toggle switches, see below */
138 int timeout; /* time-out period */
139 char *login; /* login program */
140 char *tty; /* name of tty */
141 char *initstring; /* modem init string */
142 char *issue; /* alternative issue file */
143 int numspeed; /* number of baud rates to try */
144 int speeds[MAX_SPEED]; /* baud rates to be tried */
145};
146
147#define F_PARSE (1<<0) /* process modem status messages */
148#define F_ISSUE (1<<1) /* display /etc/issue */
149#define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */
150#define F_LOCAL (1<<3) /* force local */
151#define F_INITSTRING (1<<4) /* initstring is set */
152#define F_WAITCRLF (1<<5) /* wait for CR or LF */
153#define F_CUSTISSUE (1<<6) /* give alternative issue file */
154#define F_NOPROMPT (1<<7) /* don't ask for login name! */
155
156/* Storage for things detected while the login name was read. */
157
158struct chardata {
159 int erase; /* erase character */
160 int kill; /* kill character */
161 int eol; /* end-of-line character */
162 int parity; /* what parity did we see */
163 int capslock; /* upper case without lower case */
164};
165
166/* Initial values for the above. */
167
168struct chardata init_chardata = {
169 DEF_ERASE, /* default erase character */
170 DEF_KILL, /* default kill character */
171 13, /* default eol char */
172 0, /* space parity */
173 0, /* no capslock */
174};
175
176struct Speedtab {
177 long speed;
178 int code;
179};
180
181static struct Speedtab speedtab[] = {
182 {50, B50},
183 {75, B75},
184 {110, B110},
185 {134, B134},
186 {150, B150},
187 {200, B200},
188 {300, B300},
189 {600, B600},
190 {1200, B1200},
191 {1800, B1800},
192 {2400, B2400},
193 {4800, B4800},
194 {9600, B9600},
195#ifdef B19200
196 {19200, B19200},
197#endif
198#ifdef B38400
199 {38400, B38400},
200#endif
201#ifdef EXTA
202 {19200, EXTA},
203#endif
204#ifdef EXTB
205 {38400, EXTB},
206#endif
207#ifdef B57600
208 {57600, B57600},
209#endif
210#ifdef B115200
211 {115200, B115200},
212#endif
213#ifdef B230400
214 {230400, B230400},
215#endif
216 {0, 0},
217};
218
219void parse_args(int argc, char **argv, struct options *op);
220void parse_speeds(struct options *op, char *arg);
221void update_utmp(char *line);
222void open_tty(char *tty, struct termio *tp, int local);
223void termio_init(struct termio *tp, int speed, struct options *op);
224void auto_baud(struct termio *tp);
225void do_prompt(struct options *op, struct termio *tp);
226void next_speed(struct termio *tp, struct options *op);
227char *get_logname(struct options *op, struct chardata *cp,
228
229 struct termio *tp);
230void termio_final(struct options *op, struct termio *tp,
231
232 struct chardata *cp);
233int caps_lock(char *s);
234int bcode(char *s);
235static void error(const char *fmt, ...);
236
237/* The following is used for understandable diagnostics. */
238
239char *progname;
240
241/* Fake hostname for ut_host specified on command line. */
242char *fakehost = NULL;
243
244/* ... */
245#ifdef DEBUGGING
246#define debug(s) fprintf(dbf,s); fflush(dbf)
247#define DEBUGTERM "/dev/ttyp0"
248FILE *dbf;
249#else
250#define debug(s) /* nothing */
251#endif
252
253int getty_main(int argc, char **argv)
254{
255 char *logname = NULL; /* login name, given to /bin/login */
256 struct chardata chardata; /* set by get_logname() */
257 struct termio termio; /* terminal mode bits */
258 static struct options options = {
259 F_ISSUE, /* show /etc/issue (SYSV_STYLE) */
260 0, /* no timeout */
261 _PATH_LOGIN, /* default login program */
262 "tty1", /* default tty line */
263 "", /* modem init string */
264 ISSUE, /* default issue file */
265 0, /* no baud rates known yet */
266 };
267
268 /* The BSD-style init command passes us a useless process name. */
269
270#ifdef SYSV_STYLE
271 progname = argv[0];
272#else
273 progname = "getty";
274#endif
275
276#ifdef DEBUGGING
277 dbf = xfopen(DEBUGTERM, "w");
278
279 {
280 int i;
281
282 for (i = 1; i < argc; i++) {
283 debug(argv[i]);
284 debug("\n");
285 }
286 }
287#endif
288
289 /* Parse command-line arguments. */
290
291 parse_args(argc, argv, &options);
292
293#ifdef __linux__
294 setsid();
295#endif
296
297 /* Update the utmp file. */
298
299#ifdef SYSV_STYLE
300 update_utmp(options.tty);
301#endif
302
303 debug("calling open_tty\n");
304 /* Open the tty as standard { input, output, error }. */
305 open_tty(options.tty, &termio, options.flags & F_LOCAL);
306
307#ifdef __linux__
308 {
309 int iv;
310
311 iv = getpid();
312 if (ioctl(0, TIOCSPGRP, &iv) < 0)
313 perror_msg("ioctl() TIOCSPGRP call failed");
314 }
315#endif
316 /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */
317 debug("calling termio_init\n");
318 termio_init(&termio, options.speeds[FIRST_SPEED], &options);
319
320 /* write the modem init string and DON'T flush the buffers */
321 if (options.flags & F_INITSTRING) {
322 debug("writing init string\n");
323 write(1, options.initstring, strlen(options.initstring));
324 }
325
326 if (!(options.flags & F_LOCAL)) {
327 /* go to blocking write mode unless -L is specified */
328 fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK);
329 }
330
331 /* Optionally detect the baud rate from the modem status message. */
332 debug("before autobaud\n");
333 if (options.flags & F_PARSE)
334 auto_baud(&termio);
335
336 /* Set the optional timer. */
337 if (options.timeout)
338 (void) alarm((unsigned) options.timeout);
339
340 /* optionally wait for CR or LF before writing /etc/issue */
341 if (options.flags & F_WAITCRLF) {
342 char ch;
343
344 debug("waiting for cr-lf\n");
345 while (read(0, &ch, 1) == 1) {
346 ch &= 0x7f; /* strip "parity bit" */
347#ifdef DEBUGGING
348 fprintf(dbf, "read %c\n", ch);
349#endif
350 if (ch == '\n' || ch == '\r')
351 break;
352 }
353 }
354
355 chardata = init_chardata;
356 if (!(options.flags & F_NOPROMPT)) {
357 /* Read the login name. */
358 debug("reading login name\n");
359 /* while ((logname = get_logname(&options, &chardata, &termio)) == 0) */
360 while ((logname = get_logname(&options, &chardata, &termio)) ==
361 NULL) next_speed(&termio, &options);
362 }
363
364 /* Disable timer. */
365
366 if (options.timeout)
367 (void) alarm(0);
368
369 /* Finalize the termio settings. */
370
371 termio_final(&options, &termio, &chardata);
372
373 /* Now the newline character should be properly written. */
374
375 (void) write(1, "\n", 1);
376
377 /* Let the login program take care of password validation. */
378
379 (void) execl(options.login, options.login, "--", logname, (char *) 0);
380 error("%s: can't exec %s: %m", options.tty, options.login);
381 return (0); /* quiet GCC */
382}
383
384/* parse-args - parse command-line arguments */
385
386void parse_args(argc, argv, op)
387int argc;
388char **argv;
389struct options *op;
390{
391 extern char *optarg; /* getopt */
392 extern int optind; /* getopt */
393 int c;
394
395 while (isascii(c = getopt(argc, argv, "I:LH:f:hil:mt:wn"))) {
396 switch (c) {
397 case 'I':
398 if (!(op->initstring = malloc(strlen(optarg)))) {
399 error("can't malloc initstring");
400 break;
401 }
402 {
403 char ch, *p, *q;
404 int i;
405
406 /* copy optarg into op->initstring decoding \ddd
407 octal codes into chars */
408 q = op->initstring;
409 p = optarg;
410 while (*p) {
411 if (*p == '\\') { /* know \\ means \ */
412 p++;
413 if (*p == '\\') {
414 ch = '\\';
415 p++;
416 } else { /* handle \000 - \177 */
417 ch = 0;
418 for (i = 1; i <= 3; i++) {
419 if (*p >= '0' && *p <= '7') {
420 ch <<= 3;
421 ch += *p - '0';
422 p++;
423 } else
424 break;
425 }
426 }
427 *q++ = ch;
428 } else {
429 *q++ = *p++;
430 }
431 }
432 *q = '\0';
433 }
434 op->flags |= F_INITSTRING;
435 break;
436
437 case 'L': /* force local */
438 op->flags |= F_LOCAL;
439 break;
440 case 'H': /* fake login host */
441 fakehost = optarg;
442 break;
443 case 'f': /* custom issue file */
444 op->flags |= F_CUSTISSUE;
445 op->issue = optarg;
446 break;
447 case 'h': /* enable h/w flow control */
448 op->flags |= F_RTSCTS;
449 break;
450 case 'i': /* do not show /etc/issue */
451 op->flags &= ~F_ISSUE;
452 break;
453 case 'l':
454 op->login = optarg; /* non-default login program */
455 break;
456 case 'm': /* parse modem status message */
457 op->flags |= F_PARSE;
458 break;
459 case 'n':
460 op->flags |= F_NOPROMPT;
461 break;
462 case 't': /* time out */
463 if ((op->timeout = atoi(optarg)) <= 0)
464 error("bad timeout value: %s", optarg);
465 break;
466 case 'w':
467 op->flags |= F_WAITCRLF;
468 break;
469 default:
470 show_usage();
471 }
472 }
473 debug("after getopt loop\n");
474 if (argc < optind + 2) /* check parameter count */
475 show_usage();
476
477 /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
478 if ('0' <= argv[optind][0] && argv[optind][0] <= '9') {
479 /* a number first, assume it's a speed (BSD style) */
480 parse_speeds(op, argv[optind++]); /* baud rate(s) */
481 op->tty = argv[optind]; /* tty name */
482 } else {
483 op->tty = argv[optind++]; /* tty name */
484 parse_speeds(op, argv[optind]); /* baud rate(s) */
485 }
486
487 optind++;
488 if (argc > optind && argv[optind])
489 setenv("TERM", argv[optind], 1);
490
491 debug("exiting parseargs\n");
492}
493
494/* parse_speeds - parse alternate baud rates */
495
496void parse_speeds(op, arg)
497struct options *op;
498char *arg;
499{
500 char *strtok();
501 char *cp;
502
503 debug("entered parse_speeds\n");
504 for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) {
505 if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0)
506 error("bad speed: %s", cp);
507 if (op->numspeed > MAX_SPEED)
508 error("too many alternate speeds");
509 }
510 debug("exiting parsespeeds\n");
511}
512
513#ifdef SYSV_STYLE
514
515/* update_utmp - update our utmp entry */
516void update_utmp(line)
517char *line;
518{
519 struct utmp ut;
520 int mypid = getpid();
521 long time();
522 long lseek();
523#ifndef __UCLIBC__
524 time_t t;
525 struct utmp *utp;
526#endif
527
528#if ! (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1))
529 struct flock lock;
530#endif
531
532 /*
533 * The utmp file holds miscellaneous information about things started by
534 * /sbin/init and other system-related events. Our purpose is to update
535 * the utmp entry for the current process, in particular the process type
536 * and the tty line we are listening to. Return successfully only if the
537 * utmp file can be opened for update, and if we are able to find our
538 * entry in the utmp file.
539 */
540
541#ifndef __UCLIBC__
542 utmpname(_PATH_UTMP);
543 setutent();
544 while ((utp = getutent())
545 && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) /* nothing */
546 ;
547
548 if (utp) {
549 memcpy(&ut, utp, sizeof(ut));
550 } else {
551 /* some inits don't initialize utmp... */
552 memset(&ut, 0, sizeof(ut));
553 strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
554 }
555 /*endutent(); */
556
557 strncpy(ut.ut_user, "LOGIN", sizeof(ut.ut_user));
558 strncpy(ut.ut_line, line, sizeof(ut.ut_line));
559 if (fakehost)
560 strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host));
561 time(&t);
562 ut.ut_time = t;
563 ut.ut_type = LOGIN_PROCESS;
564 ut.ut_pid = mypid;
565
566 pututline(&ut);
567 endutent();
568
569 {
570 updwtmp(_PATH_WTMP, &ut);
571 }
572#else /* not __linux__ */
573 {
574 int ut_fd;
575
576 if ((ut_fd = open(_PATH_WTMP, 2)) < 0) {
577 error("%s: open for update: %m"), _PATH_WTMP;
578 } else {
579 long ut_size = sizeof(ut); /* avoid nonsense */
580
581 while (read(ut_fd, (char *) &ut, sizeof(ut)) == sizeof(ut)) {
582 if (ut.ut_type == INIT_PROCESS && ut.ut_pid == mypid) {
583 ut.ut_type = LOGIN_PROCESS;
584 ut.ut_time = time((long *) 0);
585 (void) strncpy(ut.ut_name, "LOGIN", sizeof(ut.ut_name));
586 (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line));
587 if (fakehost)
588 (void) strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host));
589 (void) lseek(ut_fd, -ut_size, 1);
590 (void) write(ut_fd, (char *) &ut, sizeof(ut));
591 (void) close(ut_fd);
592 return;
593 }
594 }
595 error("%s: no utmp entry", line);
596 }
597 }
598#endif /* __linux__ */
599}
600
601#endif
602
603/* open_tty - set up tty as standard { input, output, error } */
604void open_tty(tty, tp, local)
605char *tty;
606struct termio *tp;
607int local;
608{
609 /* Get rid of the present standard { output, error} if any. */
610
611 (void) close(1);
612 (void) close(2);
613 errno = 0; /* ignore above errors */
614
615 /* Set up new standard input, unless we are given an already opened port. */
616
617 if (strcmp(tty, "-")) {
618 struct stat st;
619
620 /* Sanity checks... */
621
622 if (chdir("/dev"))
623 error("/dev: chdir() failed: %m");
624 if (stat(tty, &st) < 0)
625 error("/dev/%s: %m", tty);
626 if ((st.st_mode & S_IFMT) != S_IFCHR)
627 error("/dev/%s: not a character device", tty);
628
629 /* Open the tty as standard input. */
630
631 (void) close(0);
632 errno = 0; /* ignore close(2) errors */
633
634 debug("open(2)\n");
635 if (open(tty, O_RDWR | O_NONBLOCK, 0) != 0)
636 error("/dev/%s: cannot open as standard input: %m", tty);
637
638 } else {
639
640 /*
641 * Standard input should already be connected to an open port. Make
642 * sure it is open for read/write.
643 */
644
645 if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR)
646 error("%s: not open for read/write", tty);
647 }
648
649 /* Set up standard output and standard error file descriptors. */
650 debug("duping\n");
651 if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */
652 error("%s: dup problem: %m", tty); /* we have a problem */
653
654 /*
655 * The following ioctl will fail if stdin is not a tty, but also when
656 * there is noise on the modem control lines. In the latter case, the
657 * common course of action is (1) fix your cables (2) give the modem more
658 * time to properly reset after hanging up. SunOS users can achieve (2)
659 * by patching the SunOS kernel variable "zsadtrlow" to a larger value;
660 * 5 seconds seems to be a good value.
661 */
662
663 if (ioctl(0, TCGETA, tp) < 0)
664 error("%s: ioctl: %m", tty);
665
666 /*
667 * It seems to be a terminal. Set proper protections and ownership. Mode
668 * 0622 is suitable for SYSV <4 because /bin/login does not change
669 * protections. SunOS 4 login will change the protections to 0620 (write
670 * access for group tty) after the login has succeeded.
671 */
672
673#ifdef DEBIAN
674 {
675 /* tty to root.dialout 660 */
676 struct group *gr;
677 int id;
678
679 id = (gr = getgrnam("dialout")) ? gr->gr_gid : 0;
680 chown(tty, 0, id);
681 chmod(tty, 0660);
682
683 /* vcs,vcsa to root.sys 600 */
684 if (!strncmp(tty, "tty", 3) && isdigit(tty[3])) {
685 char *vcs, *vcsa;
686
687 if (!(vcs = malloc(strlen(tty))))
688 error("Can't malloc for vcs");
689 if (!(vcsa = malloc(strlen(tty) + 1)))
690 error("Can't malloc for vcsa");
691 strcpy(vcs, "vcs");
692 strcpy(vcs + 3, tty + 3);
693 strcpy(vcsa, "vcsa");
694 strcpy(vcsa + 4, tty + 3);
695
696 id = (gr = getgrnam("sys")) ? gr->gr_gid : 0;
697 chown(vcs, 0, id);
698 chmod(vcs, 0600);
699 chown(vcsa, 0, id);
700 chmod(vcs, 0600);
701
702 free(vcs);
703 free(vcsa);
704 }
705 }
706#else
707 (void) chown(tty, 0, 0); /* root, sys */
708 (void) chmod(tty, 0622); /* crw--w--w- */
709 errno = 0; /* ignore above errors */
710#endif
711}
712
713/* termio_init - initialize termio settings */
714
715char gbuf[1024];
716char area[1024];
717
718void termio_init(tp, speed, op)
719struct termio *tp;
720int speed;
721struct options *op;
722{
723
724 /*
725 * Initial termio settings: 8-bit characters, raw-mode, blocking i/o.
726 * Special characters are set after we have read the login name; all
727 * reads will be done in raw mode anyway. Errors will be dealt with
728 * lateron.
729 */
730#ifdef __linux__
731 /* flush input and output queues, important for modems! */
732 (void) ioctl(0, TCFLSH, TCIOFLUSH);
733#endif
734
735 tp->c_cflag = CS8 | HUPCL | CREAD | speed;
736 if (op->flags & F_LOCAL) {
737 tp->c_cflag |= CLOCAL;
738 }
739
740 tp->c_iflag = tp->c_lflag = tp->c_oflag = tp->c_line = 0;
741 tp->c_cc[VMIN] = 1;
742 tp->c_cc[VTIME] = 0;
743
744 /* Optionally enable hardware flow control */
745
746#ifdef CRTSCTS
747 if (op->flags & F_RTSCTS)
748 tp->c_cflag |= CRTSCTS;
749#endif
750
751 (void) ioctl(0, TCSETA, tp);
752
753 /* go to blocking input even in local mode */
754 fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK);
755
756 debug("term_io 2\n");
757}
758
759/* auto_baud - extract baud rate from modem status message */
760void auto_baud(tp)
761struct termio *tp;
762{
763 int speed;
764 int vmin;
765 unsigned iflag;
766 char buf[BUFSIZ];
767 char *bp;
768 int nread;
769
770 /*
771 * This works only if the modem produces its status code AFTER raising
772 * the DCD line, and if the computer is fast enough to set the proper
773 * baud rate before the message has gone by. We expect a message of the
774 * following format:
775 *
776 * <junk><number><junk>
777 *
778 * The number is interpreted as the baud rate of the incoming call. If the
779 * modem does not tell us the baud rate within one second, we will keep
780 * using the current baud rate. It is advisable to enable BREAK
781 * processing (comma-separated list of baud rates) if the processing of
782 * modem status messages is enabled.
783 */
784
785 /*
786 * Use 7-bit characters, don't block if input queue is empty. Errors will
787 * be dealt with lateron.
788 */
789
790 iflag = tp->c_iflag;
791 tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */
792 vmin = tp->c_cc[VMIN];
793 tp->c_cc[VMIN] = 0; /* don't block if queue empty */
794 (void) ioctl(0, TCSETA, tp);
795
796 /*
797 * Wait for a while, then read everything the modem has said so far and
798 * try to extract the speed of the dial-in call.
799 */
800
801 (void) sleep(1);
802 if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) {
803 buf[nread] = '\0';
804 for (bp = buf; bp < buf + nread; bp++) {
805 if (isascii(*bp) && isdigit(*bp)) {
806 if ((speed = bcode(bp))) {
807 tp->c_cflag &= ~CBAUD;
808 tp->c_cflag |= speed;
809 }
810 break;
811 }
812 }
813 }
814 /* Restore terminal settings. Errors will be dealt with lateron. */
815
816 tp->c_iflag = iflag;
817 tp->c_cc[VMIN] = vmin;
818 (void) ioctl(0, TCSETA, tp);
819}
820
821/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
822void do_prompt(op, tp)
823struct options *op;
824struct termio *tp;
825{
826#ifdef ISSUE
827 FILE *fd;
828 int oflag;
829 int c;
830 struct utsname uts;
831
832 (void) uname(&uts);
833#endif
834
835 (void) write(1, "\r\n", 2); /* start a new line */
836#ifdef ISSUE /* optional: show /etc/issue */
837 if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) {
838 oflag = tp->c_oflag; /* save current setting */
839 tp->c_oflag |= (ONLCR | OPOST); /* map NL in output to CR-NL */
840 (void) ioctl(0, TCSETAW, tp);
841
842
843 while ((c = getc(fd)) != EOF) {
844 if (c == '\\') {
845 c = getc(fd);
846
847 switch (c) {
848 case 's':
849 (void) printf("%s", uts.sysname);
850 break;
851
852 case 'n':
853 (void) printf("%s", uts.nodename);
854 break;
855
856 case 'r':
857 (void) printf("%s", uts.release);
858 break;
859
860 case 'v':
861 (void) printf("%s", uts.version);
862 break;
863
864 case 'm':
865 (void) printf("%s", uts.machine);
866 break;
867
868 case 'o':
869 {
870 char domainname[256];
871
872 getdomainname(domainname, sizeof(domainname));
873 domainname[sizeof(domainname) - 1] = '\0';
874 printf("%s", domainname);
875 }
876 break;
877
878 case 'd':
879 case 't':
880 {
881 char *weekday[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
882 "Fri", "Sat"
883 };
884 char *month[] = { "Jan", "Feb", "Mar", "Apr", "May",
885 "Jun", "Jul", "Aug", "Sep", "Oct",
886 "Nov", "Dec"
887 };
888 time_t now;
889 struct tm *tm;
890
891 (void) time(&now);
892 tm = localtime(&now);
893
894 if (c == 'd')
895 (void) printf("%s %s %d %d",
896 weekday[tm->tm_wday],
897 month[tm->tm_mon], tm->tm_mday,
898 tm->tm_year <
899 70 ? tm->tm_year +
900 2000 : tm->tm_year + 1900);
901 else
902 (void) printf("%02d:%02d:%02d", tm->tm_hour,
903 tm->tm_min, tm->tm_sec);
904
905 break;
906 }
907
908 case 'l':
909 (void) printf("%s", op->tty);
910 break;
911
912 case 'b':
913 {
914 int i;
915
916 for (i = 0; speedtab[i].speed; i++) {
917 if (speedtab[i].code == (tp->c_cflag & CBAUD)) {
918 printf("%ld", speedtab[i].speed);
919 break;
920 }
921 }
922 break;
923 }
924 case 'u':
925 case 'U':
926 {
927 int users = 0;
928 struct utmp *ut;
929
930 setutent();
931 while ((ut = getutent()))
932 if (ut->ut_type == USER_PROCESS)
933 users++;
934 endutent();
935 printf("%d ", users);
936 if (c == 'U')
937 printf((users == 1) ? "user" : "users");
938 break;
939 }
940 default:
941 (void) putchar(c);
942 }
943 } else
944 (void) putchar(c);
945 }
946 fflush(stdout);
947
948 tp->c_oflag = oflag; /* restore settings */
949 (void) ioctl(0, TCSETAW, tp); /* wait till output is gone */
950 (void) fclose(fd);
951 }
952#endif
953#ifdef __linux__
954 {
955 char hn[MAXHOSTNAMELEN + 1];
956
957 (void) gethostname(hn, MAXHOSTNAMELEN);
958 write(1, hn, strlen(hn));
959 }
960#endif
961 (void) write(1, LOGIN, sizeof(LOGIN) - 1); /* always show login prompt */
962}
963
964/* next_speed - select next baud rate */
965void next_speed(tp, op)
966struct termio *tp;
967struct options *op;
968{
969 static int baud_index = FIRST_SPEED; /* current speed index */
970
971 baud_index = (baud_index + 1) % op->numspeed;
972 tp->c_cflag &= ~CBAUD;
973 tp->c_cflag |= op->speeds[baud_index];
974 (void) ioctl(0, TCSETA, tp);
975}
976
977/* get_logname - get user name, establish parity, speed, erase, kill, eol */
978/* return NULL on failure, logname on success */
979char *get_logname(op, cp, tp)
980struct options *op;
981struct chardata *cp;
982struct termio *tp;
983{
984 static char logname[BUFSIZ];
985 char *bp;
986 char c; /* input character, full eight bits */
987 char ascval; /* low 7 bits of input character */
988 int bits; /* # of "1" bits per character */
989 int mask; /* mask with 1 bit up */
990 static char *erase[] = { /* backspace-space-backspace */
991 "\010\040\010", /* space parity */
992 "\010\040\010", /* odd parity */
993 "\210\240\210", /* even parity */
994 "\210\240\210", /* no parity */
995 };
996
997 /* Initialize kill, erase, parity etc. (also after switching speeds). */
998
999 *cp = init_chardata;
1000
1001 /* Flush pending input (esp. after parsing or switching the baud rate). */
1002
1003 (void) sleep(1);
1004 (void) ioctl(0, TCFLSH, TCIFLUSH);
1005
1006 /* Prompt for and read a login name. */
1007
1008 for (*logname = 0; *logname == 0; /* void */ ) {
1009
1010 /* Write issue file and prompt, with "parity" bit == 0. */
1011
1012 do_prompt(op, tp);
1013
1014 /* Read name, watch for break, parity, erase, kill, end-of-line. */
1015
1016 for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) {
1017
1018 /* Do not report trivial EINTR/EIO errors. */
1019
1020 if (read(0, &c, 1) < 1) {
1021 if (errno == EINTR || errno == EIO)
1022 exit(0);
1023 error("%s: read: %m", op->tty);
1024 }
1025 /* Do BREAK handling elsewhere. */
1026
1027 if ((c == 0) && op->numspeed > 1)
1028 /* return (0); */
1029 return NULL;
1030
1031 /* Do parity bit handling. */
1032
1033 if (c != (ascval = (c & 0177))) { /* "parity" bit on ? */
1034 for (bits = 1, mask = 1; mask & 0177; mask <<= 1)
1035 if (mask & ascval)
1036 bits++; /* count "1" bits */
1037 cp->parity |= ((bits & 1) ? 1 : 2);
1038 }
1039 /* Do erase, kill and end-of-line processing. */
1040
1041 switch (ascval) {
1042 case CR:
1043 case NL:
1044 *bp = 0; /* terminate logname */
1045 cp->eol = ascval; /* set end-of-line char */
1046 break;
1047 case BS:
1048 case DEL:
1049 case '#':
1050 cp->erase = ascval; /* set erase character */
1051 if (bp > logname) {
1052 (void) write(1, erase[cp->parity], 3);
1053 bp--;
1054 }
1055 break;
1056 case CTL('U'):
1057 case '@':
1058 cp->kill = ascval; /* set kill character */
1059 while (bp > logname) {
1060 (void) write(1, erase[cp->parity], 3);
1061 bp--;
1062 }
1063 break;
1064 case CTL('D'):
1065 exit(0);
1066 default:
1067 if (!isascii(ascval) || !isprint(ascval)) {
1068 /* ignore garbage characters */ ;
1069 } else if (bp - logname >= sizeof(logname) - 1) {
1070 error("%s: input overrun", op->tty);
1071 } else {
1072 (void) write(1, &c, 1); /* echo the character */
1073 *bp++ = ascval; /* and store it */
1074 }
1075 break;
1076 }
1077 }
1078 }
1079 /* Handle names with upper case and no lower case. */
1080
1081 if ((cp->capslock = caps_lock(logname))) {
1082 for (bp = logname; *bp; bp++)
1083 if (isupper(*bp))
1084 *bp = tolower(*bp); /* map name to lower case */
1085 }
1086 return (logname);
1087}
1088
1089/* termio_final - set the final tty mode bits */
1090void termio_final(op, tp, cp)
1091struct options *op;
1092struct termio *tp;
1093struct chardata *cp;
1094{
1095 /* General terminal-independent stuff. */
1096
1097 tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */
1098 tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE;
1099 /* no longer| ECHOCTL | ECHOPRT */
1100 tp->c_oflag |= OPOST;
1101 /* tp->c_cflag = 0; */
1102 tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */
1103 tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */
1104 tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */
1105 tp->c_cc[VEOL] = DEF_EOL;
1106#ifdef __linux__
1107 tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */
1108#else
1109 tp->c_cc[VSWTCH] = DEF_SWITCH; /* default switch character */
1110#endif
1111
1112 /* Account for special characters seen in input. */
1113
1114 if (cp->eol == CR) {
1115 tp->c_iflag |= ICRNL; /* map CR in input to NL */
1116 tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */
1117 }
1118 tp->c_cc[VERASE] = cp->erase; /* set erase character */
1119 tp->c_cc[VKILL] = cp->kill; /* set kill character */
1120
1121 /* Account for the presence or absence of parity bits in input. */
1122
1123 switch (cp->parity) {
1124 case 0: /* space (always 0) parity */
1125 break;
1126 case 1: /* odd parity */
1127 tp->c_cflag |= PARODD;
1128 /* FALLTHROUGH */
1129 case 2: /* even parity */
1130 tp->c_cflag |= PARENB;
1131 tp->c_iflag |= INPCK | ISTRIP;
1132 /* FALLTHROUGH */
1133 case (1 | 2): /* no parity bit */
1134 tp->c_cflag &= ~CSIZE;
1135 tp->c_cflag |= CS7;
1136 break;
1137 }
1138 /* Account for upper case without lower case. */
1139
1140 if (cp->capslock) {
1141 tp->c_iflag |= IUCLC;
1142 tp->c_lflag |= XCASE;
1143 tp->c_oflag |= OLCUC;
1144 }
1145 /* Optionally enable hardware flow control */
1146
1147#ifdef CRTSCTS
1148 if (op->flags & F_RTSCTS)
1149 tp->c_cflag |= CRTSCTS;
1150#endif
1151
1152 /* Finally, make the new settings effective */
1153
1154 if (ioctl(0, TCSETA, tp) < 0)
1155 error("%s: ioctl: TCSETA: %m", op->tty);
1156}
1157
1158/* caps_lock - string contains upper case without lower case */
1159/* returns 1 if true, 0 if false */
1160int caps_lock(s)
1161char *s;
1162{
1163 int capslock;
1164
1165 for (capslock = 0; *s; s++) {
1166 if (islower(*s))
1167 return (0);
1168 if (capslock == 0)
1169 capslock = isupper(*s);
1170 }
1171 return (capslock);
1172}
1173
1174/* bcode - convert speed string to speed code; return 0 on failure */
1175int bcode(s)
1176char *s;
1177{
1178 struct Speedtab *sp;
1179 long speed = atol(s);
1180
1181 for (sp = speedtab; sp->speed; sp++)
1182 if (sp->speed == speed)
1183 return (sp->code);
1184 return (0);
1185}
1186
1187/* error - report errors to console or syslog; only understands %s and %m */
1188
1189#define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)
1190
1191/*
1192 * output error messages
1193 */
1194static void error(const char *fmt, ...)
1195{
1196 va_list va_alist;
1197 char buf[256], *bp;
1198
1199#ifndef USE_SYSLOG
1200 int fd;
1201#endif
1202
1203#ifdef USE_SYSLOG
1204 buf[0] = '\0';
1205 bp = buf;
1206#else
1207 strncpy(buf, progname, 256);
1208 strncat(buf, ": ", 256);
1209 buf[255] = 0;
1210 bp = buf + strlen(buf);
1211#endif
1212
1213 va_start(va_alist, fmt);
1214 vsnprintf(bp, 256 - strlen(buf), fmt, va_alist);
1215 buf[255] = 0;
1216 va_end(va_alist);
1217
1218#ifdef USE_SYSLOG
1219 openlog(progname, LOG_PID, LOG_AUTH);
1220 syslog(LOG_ERR, buf);
1221 closelog();
1222#else
1223 strncat(bp, "\r\n", 256 - strlen(buf));
1224 buf[255] = 0;
1225 if ((fd = open("/dev/console", 1)) >= 0) {
1226 write(fd, buf, strlen(buf));
1227 close(fd);
1228 }
1229#endif
1230 (void) sleep((unsigned) 10); /* be kind to init(8) */
1231 exit(1);
1232}
diff --git a/grep.c b/grep.c
deleted file mode 100644
index eff7c3ff5..000000000
--- a/grep.c
+++ /dev/null
@@ -1,358 +0,0 @@
1/*
2 * Mini grep implementation for busybox using libc regex.
3 *
4 * Copyright (C) 1999,2000,2001 by Lineo, inc.
5 * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <getopt.h>
26#include <regex.h>
27#include <string.h> /* for strerror() */
28#include <errno.h>
29#include "busybox.h"
30
31
32extern int optind; /* in unistd.h */
33extern void xregcomp(regex_t *preg, const char *regex, int cflags); /* in busybox.h */
34
35/* options */
36static int reflags = REG_NOSUB;
37static int print_filename = 0;
38static int print_line_num = 0;
39static int print_match_counts = 0;
40static int be_quiet = 0;
41static int invert_search = 0;
42static int suppress_err_msgs = 0;
43static int print_files_with_matches = 0;
44
45#ifdef BB_FEATURE_GREP_CONTEXT
46extern char *optarg; /* in getopt.h */
47static int lines_before = 0;
48static int lines_after = 0;
49static char **before_buf = NULL;
50static int last_line_printed = 0;
51#endif /* BB_FEATURE_GREP_CONTEXT */
52
53/* globals used internally */
54static regex_t *regexes = NULL; /* growable array of compiled regular expressions */
55static int nregexes = 0; /* number of elements in above arrary */
56static int matched; /* keeps track of whether we ever matched */
57static char *cur_file = NULL; /* the current file we are reading */
58
59
60static void print_line(const char *line, int linenum, char decoration)
61{
62#ifdef BB_FEATURE_GREP_CONTEXT
63 /* possibly print the little '--' seperator */
64 if ((lines_before || lines_after) && last_line_printed &&
65 last_line_printed < linenum - 1) {
66 puts("--");
67 }
68 last_line_printed = linenum;
69#endif
70 if (print_filename)
71 printf("%s%c", cur_file, decoration);
72 if (print_line_num)
73 printf("%i%c", linenum, decoration);
74 puts(line);
75}
76
77
78static void grep_file(FILE *file)
79{
80 char *line = NULL;
81 int ret;
82 int linenum = 0;
83 int nmatches = 0;
84 int i;
85#ifdef BB_FEATURE_GREP_CONTEXT
86 int print_n_lines_after = 0;
87 int curpos = 0; /* track where we are in the circular 'before' buffer */
88 int idx = 0; /* used for iteration through the circular buffer */
89#endif /* BB_FEATURE_GREP_CONTEXT */
90
91 while ((line = get_line_from_file(file)) != NULL) {
92 chomp(line);
93 linenum++;
94
95 for (i = 0; i < nregexes; i++) {
96 /*
97 * test for a postitive-assertion match (regexec returns success (0)
98 * and the user did not specify invert search), or a negative-assertion
99 * match (regexec returns failure (REG_NOMATCH) and the user specified
100 * invert search)
101 */
102 ret = regexec(&regexes[i], line, 0, NULL, 0);
103 if ((ret == 0 && !invert_search) || (ret == REG_NOMATCH && invert_search)) {
104
105 /* if we found a match but were told to be quiet, stop here and
106 * return success */
107 if (be_quiet)
108 exit(0);
109
110 /* keep track of matches */
111 nmatches++;
112
113 /* if we're just printing filenames, we stop after the first match */
114 if (print_files_with_matches)
115 break;
116
117 /* print the matched line */
118 if (print_match_counts == 0) {
119#ifdef BB_FEATURE_GREP_CONTEXT
120 int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1;
121
122 /* if we were told to print 'before' lines and there is at least
123 * one line in the circular buffer, print them */
124 if (lines_before && before_buf[prevpos] != NULL) {
125 int first_buf_entry_line_num = linenum - lines_before;
126
127 /* advance to the first entry in the circular buffer, and
128 * figure out the line number is of the first line in the
129 * buffer */
130 idx = curpos;
131 while (before_buf[idx] == NULL) {
132 idx = (idx + 1) % lines_before;
133 first_buf_entry_line_num++;
134 }
135
136 /* now print each line in the buffer, clearing them as we go */
137 while (before_buf[idx] != NULL) {
138 print_line(before_buf[idx], first_buf_entry_line_num, '-');
139 free(before_buf[idx]);
140 before_buf[idx] = NULL;
141 idx = (idx + 1) % lines_before;
142 first_buf_entry_line_num++;
143 }
144 }
145
146 /* make a note that we need to print 'after' lines */
147 print_n_lines_after = lines_after;
148#endif /* BB_FEATURE_GREP_CONTEXT */
149 print_line(line, linenum, ':');
150 }
151 }
152#ifdef BB_FEATURE_GREP_CONTEXT
153 else { /* no match */
154 /* Add the line to the circular 'before' buffer */
155 if(lines_before) {
156 if(before_buf[curpos])
157 free(before_buf[curpos]);
158 before_buf[curpos] = strdup(line);
159 curpos = (curpos + 1) % lines_before;
160 }
161 }
162
163 /* if we need to print some context lines after the last match, do so */
164 if (print_n_lines_after && (last_line_printed != linenum)) {
165 print_line(line, linenum, '-');
166 print_n_lines_after--;
167 }
168#endif /* BB_FEATURE_GREP_CONTEXT */
169 } /* for */
170 free(line);
171 }
172
173
174 /* special-case file post-processing for options where we don't print line
175 * matches, just filenames and possibly match counts */
176
177 /* grep -c: print [filename:]count, even if count is zero */
178 if (print_match_counts) {
179 if (print_filename)
180 printf("%s:", cur_file);
181 if (print_files_with_matches && nmatches > 0)
182 printf("1\n");
183 else
184 printf("%d\n", nmatches);
185 }
186
187 /* grep -l: print just the filename, but only if we grepped the line in the file */
188 if (print_files_with_matches && nmatches > 0) {
189 puts(cur_file);
190 }
191
192
193 /* remember if we matched */
194 if (nmatches != 0)
195 matched = 1;
196}
197
198
199static void add_regex(const char *restr)
200{
201 regexes = xrealloc(regexes, sizeof(regex_t) * (++nregexes));
202 xregcomp(&regexes[nregexes-1], restr, reflags);
203}
204
205
206static void load_regexes_from_file(const char *filename)
207{
208 char *line;
209 FILE *f = xfopen(filename, "r");
210 while ((line = get_line_from_file(f)) != NULL) {
211 chomp(line);
212 add_regex(line);
213 free(line);
214 }
215}
216
217
218#ifdef BB_FEATURE_CLEAN_UP
219static void destroy_regexes()
220{
221 if (regexes == NULL)
222 return;
223
224 /* destroy all the elments in the array */
225 while (--nregexes >= 0) {
226 regfree(&regexes[nregexes]);
227 free(&regexes[nregexes]);
228 }
229}
230#endif
231
232
233extern int grep_main(int argc, char **argv)
234{
235 int opt;
236#ifdef BB_FEATURE_GREP_CONTEXT
237 char *junk;
238#endif
239
240#ifdef BB_FEATURE_CLEAN_UP
241 /* destroy command strings on exit */
242 if (atexit(destroy_regexes) == -1)
243 perror_msg_and_die("atexit");
244#endif
245
246 /* do normal option parsing */
247 while ((opt = getopt(argc, argv, "iHhlnqvsce:f:"
248#ifdef BB_FEATURE_GREP_CONTEXT
249"A:B:C:"
250#endif
251)) > 0) {
252 switch (opt) {
253 case 'i':
254 reflags |= REG_ICASE;
255 break;
256 case 'l':
257 print_files_with_matches++;
258 break;
259 case 'H':
260 print_filename++;
261 break;
262 case 'h':
263 print_filename--;
264 break;
265 case 'n':
266 print_line_num++;
267 break;
268 case 'q':
269 be_quiet++;
270 break;
271 case 'v':
272 invert_search++;
273 break;
274 case 's':
275 suppress_err_msgs++;
276 break;
277 case 'c':
278 print_match_counts++;
279 break;
280 case 'e':
281 add_regex(optarg);
282 break;
283 case 'f':
284 load_regexes_from_file(optarg);
285 break;
286#ifdef BB_FEATURE_GREP_CONTEXT
287 case 'A':
288 lines_after = strtoul(optarg, &junk, 10);
289 if(*junk != '\0')
290 error_msg_and_die("invalid context length argument");
291 break;
292 case 'B':
293 lines_before = strtoul(optarg, &junk, 10);
294 if(*junk != '\0')
295 error_msg_and_die("invalid context length argument");
296 before_buf = (char **)calloc(lines_before, sizeof(char *));
297 break;
298 case 'C':
299 lines_after = lines_before = strtoul(optarg, &junk, 10);
300 if(*junk != '\0')
301 error_msg_and_die("invalid context length argument");
302 before_buf = (char **)calloc(lines_before, sizeof(char *));
303 break;
304#endif /* BB_FEATURE_GREP_CONTEXT */
305 default:
306 show_usage();
307 }
308 }
309
310 /* if we didn't get a pattern from a -e and no command file was specified,
311 * argv[optind] should be the pattern. no pattern, no worky */
312 if (nregexes == 0) {
313 if (argv[optind] == NULL)
314 show_usage();
315 else {
316 add_regex(argv[optind]);
317 optind++;
318 }
319 }
320
321 /* sanity checks */
322 if (print_match_counts || be_quiet || print_files_with_matches) {
323 print_line_num = 0;
324#ifdef BB_FEATURE_GREP_CONTEXT
325 lines_before = 0;
326 lines_after = 0;
327#endif
328 }
329
330 /* argv[(optind)..(argc-1)] should be names of file to grep through. If
331 * there is more than one file to grep, we will print the filenames */
332 if ((argc-1) - (optind) > 0)
333 print_filename++;
334
335 /* If no files were specified, or '-' was specified, take input from
336 * stdin. Otherwise, we grep through all the files specified. */
337 if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
338 grep_file(stdin);
339 }
340 else {
341 int i;
342 FILE *file;
343 for (i = optind; i < argc; i++) {
344 cur_file = argv[i];
345 file = fopen(cur_file, "r");
346 if (file == NULL) {
347 if (!suppress_err_msgs)
348 perror_msg("%s", cur_file);
349 }
350 else {
351 grep_file(file);
352 fclose(file);
353 }
354 }
355 }
356
357 return !matched; /* invert return value 0 = success, 1 = failed */
358}
diff --git a/gunzip.c b/gunzip.c
deleted file mode 100644
index 430bc630e..000000000
--- a/gunzip.c
+++ /dev/null
@@ -1,183 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Gzip implementation for busybox
4 *
5 * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
6 *
7 * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
8 * based on gzip sources
9 *
10 * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
11 * to support files as well as stdin/stdout, and to generally behave itself wrt
12 * command line handling.
13 *
14 * General cleanup to better adhere to the style guide and make use of standard
15 * busybox functions by Glenn McGrath <bug1@optushome.com.au>
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 *
31 *
32 * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
33 * Copyright (C) 1992-1993 Jean-loup Gailly
34 * The unzip code was written and put in the public domain by Mark Adler.
35 * Portions of the lzw code are derived from the public domain 'compress'
36 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
37 * Ken Turkowski, Dave Mack and Peter Jannesen.
38 *
39 * See the license_msg below and the file COPYING for the software license.
40 * See the file algorithm.doc for the compression algorithms and file formats.
41 */
42
43#if 0
44static char *license_msg[] = {
45 " Copyright (C) 1992-1993 Jean-loup Gailly",
46 " This program is free software; you can redistribute it and/or modify",
47 " it under the terms of the GNU General Public License as published by",
48 " the Free Software Foundation; either version 2, or (at your option)",
49 " any later version.",
50 "",
51 " This program is distributed in the hope that it will be useful,",
52 " but WITHOUT ANY WARRANTY; without even the implied warranty of",
53 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
54 " GNU General Public License for more details.",
55 "",
56 " You should have received a copy of the GNU General Public License",
57 " along with this program; if not, write to the Free Software",
58 " Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
59 0
60};
61#endif
62
63#include <stdlib.h>
64#include <string.h>
65#include <unistd.h>
66#include <getopt.h>
67#include "busybox.h"
68
69extern int gunzip_main(int argc, char **argv)
70{
71 FILE *in_file = stdin;
72 FILE *out_file = NULL;
73 struct stat stat_buf;
74
75 char *if_name = NULL;
76 char *of_name = NULL;
77 char *delete_file_name = NULL;
78
79 const int gunzip_to_stdout = 1;
80 const int gunzip_force = 2;
81 const int gunzip_test = 4;
82
83 int flags = 0;
84 int opt = 0;
85 int delete_old_file = FALSE;
86
87 /* if called as zcat */
88 if (strcmp(applet_name, "zcat") == 0)
89 flags |= gunzip_to_stdout;
90
91 while ((opt = getopt(argc, argv, "ctfhdq")) != -1) {
92 switch (opt) {
93 case 'c':
94 flags |= gunzip_to_stdout;
95 break;
96 case 'f':
97 flags |= gunzip_force;
98 break;
99 case 't':
100 flags |= gunzip_test;
101 break;
102 case 'd': /* Used to convert gzip to gunzip. */
103 break;
104 case 'q':
105 error_msg("-q option not supported, ignored");
106 break;
107 case 'h':
108 default:
109 show_usage(); /* exit's inside usage */
110 }
111 }
112
113 /* Set input filename and number */
114 if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) {
115 flags |= gunzip_to_stdout;
116 } else {
117 if_name = strdup(argv[optind]);
118 /* Open input file */
119 in_file = xfopen(if_name, "r");
120
121 /* set the buffer size */
122 setvbuf(in_file, NULL, _IOFBF, 0x8000);
123
124 /* Get the time stamp on the input file. */
125 if (stat(if_name, &stat_buf) < 0) {
126 error_msg_and_die("Couldn't stat file %s", if_name);
127 }
128 }
129
130 /* Check that the input is sane. */
131 if (isatty(fileno(in_file)) && (flags & gunzip_force) == 0)
132 error_msg_and_die("compressed data not read from terminal. Use -f to force it.");
133
134 /* Set output filename and number */
135 if (flags & gunzip_test) {
136 out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */
137 } else if (flags & gunzip_to_stdout) {
138 out_file = stdout;
139 } else {
140 char *extension;
141 int length = strlen(if_name);
142
143 delete_old_file = TRUE;
144 extension = strrchr(if_name, '.');
145 if (extension && strcmp(extension, ".gz") == 0) {
146 length -= 3;
147 } else if (extension && strcmp(extension, ".tgz") == 0) {
148 length -= 4;
149 } else {
150 error_msg_and_die("Invalid extension");
151 }
152 of_name = (char *) xcalloc(sizeof(char), length + 1);
153 strncpy(of_name, if_name, length);
154
155 /* Open output file */
156 out_file = xfopen(of_name, "w");
157
158 /* Set permissions on the file */
159 chmod(of_name, stat_buf.st_mode);
160 }
161
162 /* do the decompression, and cleanup */
163 if (unzip(in_file, out_file) == 0) {
164 /* Success, remove .gz file */
165 delete_file_name = if_name;
166 } else {
167 /* remove failed attempt */
168 delete_file_name = of_name;
169 }
170
171 fclose(out_file);
172 fclose(in_file);
173
174 if (delete_old_file == TRUE) {
175 if (unlink(delete_file_name) < 0) {
176 error_msg_and_die("Couldnt remove %s", delete_file_name);
177 }
178 }
179
180 free(of_name);
181
182 return(EXIT_SUCCESS);
183}
diff --git a/gzip.c b/gzip.c
deleted file mode 100644
index 5c86c1070..000000000
--- a/gzip.c
+++ /dev/null
@@ -1,2568 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Gzip implementation for busybox
4 *
5 * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly.
6 *
7 * Originally adjusted for busybox by Charles P. Wright <cpw@unix.asb.com>
8 * "this is a stripped down version of gzip I put into busybox, it does
9 * only standard in to standard out with -9 compression. It also requires
10 * the zcat module for some important functions."
11 *
12 * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
13 * to support files as well as stdin/stdout, and to generally behave itself wrt
14 * command line handling.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 */
31
32/* These defines are very important for BusyBox. Without these,
33 * huge chunks of ram are pre-allocated making the BusyBox bss
34 * size Freaking Huge(tm), which is a bad thing.*/
35#define SMALL_MEM
36#define DYN_ALLOC
37
38#include <stdlib.h>
39#include <stdio.h>
40#include <string.h>
41#include <unistd.h>
42#include <errno.h>
43#include <sys/types.h>
44#include <signal.h>
45#include <utime.h>
46#include <ctype.h>
47#include <sys/types.h>
48#include <unistd.h>
49#include <dirent.h>
50#include <fcntl.h>
51#include <time.h>
52#include "busybox.h"
53
54#define memzero(s, n) memset ((void *)(s), 0, (n))
55
56#ifndef RETSIGTYPE
57# define RETSIGTYPE void
58#endif
59
60typedef unsigned char uch;
61typedef unsigned short ush;
62typedef unsigned long ulg;
63
64/* Return codes from gzip */
65#define OK 0
66#define ERROR 1
67#define WARNING 2
68
69/* Compression methods (see algorithm.doc) */
70/* Only STORED and DEFLATED are supported by this BusyBox module */
71#define STORED 0
72/* methods 4 to 7 reserved */
73#define DEFLATED 8
74static int method; /* compression method */
75
76/* To save memory for 16 bit systems, some arrays are overlaid between
77 * the various modules:
78 * deflate: prev+head window d_buf l_buf outbuf
79 * unlzw: tab_prefix tab_suffix stack inbuf outbuf
80 * For compression, input is done in window[]. For decompression, output
81 * is done in window except for unlzw.
82 */
83
84#ifndef INBUFSIZ
85# ifdef SMALL_MEM
86# define INBUFSIZ 0x2000 /* input buffer size */
87# else
88# define INBUFSIZ 0x8000 /* input buffer size */
89# endif
90#endif
91#define INBUF_EXTRA 64 /* required by unlzw() */
92
93#ifndef OUTBUFSIZ
94# ifdef SMALL_MEM
95# define OUTBUFSIZ 8192 /* output buffer size */
96# else
97# define OUTBUFSIZ 16384 /* output buffer size */
98# endif
99#endif
100#define OUTBUF_EXTRA 2048 /* required by unlzw() */
101
102#ifndef DIST_BUFSIZE
103# ifdef SMALL_MEM
104# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
105# else
106# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
107# endif
108#endif
109
110#ifdef DYN_ALLOC
111# define DECLARE(type, array, size) static type * array
112# define ALLOC(type, array, size) { \
113 array = (type*)xcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
114 }
115# define FREE(array) {if (array != NULL) free(array), array=NULL;}
116#else
117# define DECLARE(type, array, size) static type array[size]
118# define ALLOC(type, array, size)
119# define FREE(array)
120#endif
121
122#define tab_suffix window
123#define tab_prefix prev /* hash link (see deflate.c) */
124#define head (prev+WSIZE) /* hash head (see deflate.c) */
125
126static long bytes_in; /* number of input bytes */
127
128#define isize bytes_in
129/* for compatibility with old zip sources (to be cleaned) */
130
131typedef int file_t; /* Do not use stdio */
132
133#define NO_FILE (-1) /* in memory compression */
134
135
136#define PACK_MAGIC "\037\036" /* Magic header for packed files */
137#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
138#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
139#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files */
140#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */
141
142/* gzip flag byte */
143#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
144#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
145#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
146#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
147#define COMMENT 0x10 /* bit 4 set: file comment present */
148#define RESERVED 0xC0 /* bit 6,7: reserved */
149
150/* internal file attribute */
151#define UNKNOWN 0xffff
152#define BINARY 0
153#define ASCII 1
154
155#ifndef WSIZE
156# define WSIZE 0x8000 /* window size--must be a power of two, and */
157#endif /* at least 32K for zip's deflate method */
158
159#define MIN_MATCH 3
160#define MAX_MATCH 258
161/* The minimum and maximum match lengths */
162
163#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
164/* Minimum amount of lookahead, except at the end of the input file.
165 * See deflate.c for comments about the MIN_MATCH+1.
166 */
167
168#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
169/* In order to simplify the code, particularly on 16 bit machines, match
170 * distances are limited to MAX_DIST instead of WSIZE.
171 */
172
173/* put_byte is used for the compressed output */
174#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
175 flush_outbuf();}
176
177/* Output a 16 bit value, lsb first */
178#define put_short(w) \
179{ if (outcnt < OUTBUFSIZ-2) { \
180 outbuf[outcnt++] = (uch) ((w) & 0xff); \
181 outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
182 } else { \
183 put_short_when_full(w); \
184 } \
185}
186
187/* Output a 32 bit value to the bit stream, lsb first */
188#if 0
189#define put_long(n) { \
190 put_short((n) & 0xffff); \
191 put_short(((ulg)(n)) >> 16); \
192}
193#endif
194
195#define seekable() 0 /* force sequential output */
196#define translate_eol 0 /* no option -a yet */
197
198/* Diagnostic functions */
199#ifdef DEBUG
200# define Assert(cond,msg) {if(!(cond)) error_msg(msg);}
201# define Trace(x) fprintf x
202# define Tracev(x) {if (verbose) fprintf x ;}
203# define Tracevv(x) {if (verbose>1) fprintf x ;}
204# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
205# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
206#else
207# define Assert(cond,msg)
208# define Trace(x)
209# define Tracev(x)
210# define Tracevv(x)
211# define Tracec(c,x)
212# define Tracecv(c,x)
213#endif
214
215#define WARN(msg) {if (!quiet) fprintf msg ; \
216 if (exit_code == OK) exit_code = WARNING;}
217
218#ifndef MAX_PATH_LEN
219# define MAX_PATH_LEN 1024 /* max pathname length */
220#endif
221
222
223 /* from zip.c: */
224static int zip (int in, int out);
225static int file_read (char *buf, unsigned size);
226
227 /* from gzip.c */
228static RETSIGTYPE abort_gzip (void);
229
230 /* from deflate.c */
231static void lm_init (ush * flags);
232static ulg deflate (void);
233
234 /* from trees.c */
235static void ct_init (ush * attr, int *methodp);
236static int ct_tally (int dist, int lc);
237static ulg flush_block (char *buf, ulg stored_len, int eof);
238
239 /* from bits.c */
240static void bi_init (file_t zipfile);
241static void send_bits (int value, int length);
242static unsigned bi_reverse (unsigned value, int length);
243static void bi_windup (void);
244static void copy_block (char *buf, unsigned len, int header);
245static int (*read_buf) (char *buf, unsigned size);
246
247 /* from util.c: */
248static void flush_outbuf (void);
249
250static void put_short_when_full (ush);
251
252
253/* lzw.h -- define the lzw functions.
254 * Copyright (C) 1992-1993 Jean-loup Gailly.
255 * This is free software; you can redistribute it and/or modify it under the
256 * terms of the GNU General Public License, see the file COPYING.
257 */
258
259#if !defined(OF) && defined(lint)
260# include "gzip.h"
261#endif
262
263#ifndef BITS
264# define BITS 16
265#endif
266#define INIT_BITS 9 /* Initial number of bits per code */
267
268#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
269/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
270 * It's a pity that old uncompress does not check bit 0x20. That makes
271 * extension of the format actually undesirable because old compress
272 * would just crash on the new format instead of giving a meaningful
273 * error message. It does check the number of bits, but it's more
274 * helpful to say "unsupported format, get a new version" than
275 * "can only handle 16 bits".
276 */
277
278/* tailor.h -- target dependent definitions
279 * Copyright (C) 1992-1993 Jean-loup Gailly.
280 * This is free software; you can redistribute it and/or modify it under the
281 * terms of the GNU General Public License, see the file COPYING.
282 */
283
284/* The target dependent definitions should be defined here only.
285 * The target dependent functions should be defined in tailor.c.
286 */
287
288
289 /* Common defaults */
290
291#ifndef OS_CODE
292# define OS_CODE 0x03 /* assume Unix */
293#endif
294
295#ifndef PATH_SEP
296# define PATH_SEP '/'
297#endif
298
299#ifndef OPTIONS_VAR
300# define OPTIONS_VAR "GZIP"
301#endif
302
303#ifndef Z_SUFFIX
304# define Z_SUFFIX ".gz"
305#endif
306
307#ifdef MAX_EXT_CHARS
308# define MAX_SUFFIX MAX_EXT_CHARS
309#else
310# define MAX_SUFFIX 30
311#endif
312
313 /* global buffers */
314
315DECLARE(uch, inbuf, INBUFSIZ + INBUF_EXTRA);
316DECLARE(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA);
317DECLARE(ush, d_buf, DIST_BUFSIZE);
318DECLARE(uch, window, 2L * WSIZE);
319DECLARE(ush, tab_prefix, 1L << BITS);
320
321static int crc_table_empty = 1;
322
323static int foreground; /* set if program run in foreground */
324static int method = DEFLATED; /* compression method */
325static int exit_code = OK; /* program exit code */
326static int part_nb; /* number of parts in .gz file */
327static long time_stamp; /* original time stamp (modification time) */
328static long ifile_size; /* input file size, -1 for devices (debug only) */
329static char z_suffix[MAX_SUFFIX + 1]; /* default suffix (can be set with --suffix) */
330static int z_len; /* strlen(z_suffix) */
331
332static char ifname[MAX_PATH_LEN]; /* input file name */
333static char ofname[MAX_PATH_LEN]; /* output file name */
334static int ifd; /* input file descriptor */
335static int ofd; /* output file descriptor */
336static unsigned insize; /* valid bytes in inbuf */
337static unsigned outcnt; /* bytes in output buffer */
338
339/* ========================================================================
340 * Signal and error handler.
341 */
342static void abort_gzip()
343{
344 exit(ERROR);
345}
346
347/* ===========================================================================
348 * Clear input and output buffers
349 */
350static void clear_bufs(void)
351{
352 outcnt = 0;
353 insize = 0;
354 bytes_in = 0L;
355}
356
357static void write_error_msg(void)
358{
359 fprintf(stderr, "\n");
360 perror("");
361 abort_gzip();
362}
363
364/* ===========================================================================
365 * Does the same as write(), but also handles partial pipe writes and checks
366 * for error return.
367 */
368static void write_buf(int fd, void *buf, unsigned cnt)
369{
370 unsigned n;
371
372 while ((n = write(fd, buf, cnt)) != cnt) {
373 if (n == (unsigned) (-1)) {
374 write_error_msg();
375 }
376 cnt -= n;
377 buf = (void *) ((char *) buf + n);
378 }
379}
380
381/* ===========================================================================
382 * Run a set of bytes through the crc shift register. If s is a NULL
383 * pointer, then initialize the crc shift register contents instead.
384 * Return the current crc in either case.
385 */
386static ulg updcrc(uch *s, unsigned n)
387{
388 static ulg crc = (ulg) 0xffffffffL; /* shift register contents */
389 register ulg c; /* temporary variable */
390 static unsigned long crc_32_tab[256];
391 if (crc_table_empty) {
392 unsigned long csr; /* crc shift register */
393 const unsigned long e = 0xedb88320L; /* polynomial exclusive-or pattern */
394 int i; /* counter for all possible eight bit values */
395 int k; /* byte being shifted into crc apparatus */
396
397 /* Compute table of CRC's. */
398 crc_32_tab[0] = 0x00000000L;
399 for (i = 1; i < 256; i++) {
400 csr = i;
401 /* The idea to initialize the register with the byte instead of
402 * zero was stolen from Haruhiko Okumura's ar002
403 */
404 for (k = 8; k; k--)
405 csr = csr & 1 ? (csr >> 1) ^ e : csr >> 1;
406 crc_32_tab[i]=csr;
407 }
408 }
409
410 if (s == NULL) {
411 c = 0xffffffffL;
412 } else {
413 c = crc;
414 if (n)
415 do {
416 c = crc_32_tab[((int) c ^ (*s++)) & 0xff] ^ (c >> 8);
417 } while (--n);
418 }
419 crc = c;
420 return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
421}
422
423/* bits.c -- output variable-length bit strings
424 * Copyright (C) 1992-1993 Jean-loup Gailly
425 * This is free software; you can redistribute it and/or modify it under the
426 * terms of the GNU General Public License, see the file COPYING.
427 */
428
429
430/*
431 * PURPOSE
432 *
433 * Output variable-length bit strings. Compression can be done
434 * to a file or to memory. (The latter is not supported in this version.)
435 *
436 * DISCUSSION
437 *
438 * The PKZIP "deflate" file format interprets compressed file data
439 * as a sequence of bits. Multi-bit strings in the file may cross
440 * byte boundaries without restriction.
441 *
442 * The first bit of each byte is the low-order bit.
443 *
444 * The routines in this file allow a variable-length bit value to
445 * be output right-to-left (useful for literal values). For
446 * left-to-right output (useful for code strings from the tree routines),
447 * the bits must have been reversed first with bi_reverse().
448 *
449 * For in-memory compression, the compressed bit stream goes directly
450 * into the requested output buffer. The input data is read in blocks
451 * by the mem_read() function. The buffer is limited to 64K on 16 bit
452 * machines.
453 *
454 * INTERFACE
455 *
456 * void bi_init (FILE *zipfile)
457 * Initialize the bit string routines.
458 *
459 * void send_bits (int value, int length)
460 * Write out a bit string, taking the source bits right to
461 * left.
462 *
463 * int bi_reverse (int value, int length)
464 * Reverse the bits of a bit string, taking the source bits left to
465 * right and emitting them right to left.
466 *
467 * void bi_windup (void)
468 * Write out any remaining bits in an incomplete byte.
469 *
470 * void copy_block(char *buf, unsigned len, int header)
471 * Copy a stored block to the zip file, storing first the length and
472 * its one's complement if requested.
473 *
474 */
475
476/* ===========================================================================
477 * Local data used by the "bit string" routines.
478 */
479
480static file_t zfile; /* output gzip file */
481
482static unsigned short bi_buf;
483
484/* Output buffer. bits are inserted starting at the bottom (least significant
485 * bits).
486 */
487
488#define Buf_size (8 * 2*sizeof(char))
489/* Number of bits used within bi_buf. (bi_buf might be implemented on
490 * more than 16 bits on some systems.)
491 */
492
493static int bi_valid;
494
495/* Current input function. Set to mem_read for in-memory compression */
496
497#ifdef DEBUG
498ulg bits_sent; /* bit length of the compressed data */
499#endif
500
501/* ===========================================================================
502 * Initialize the bit string routines.
503 */
504static void bi_init(file_t zipfile)
505{
506 zfile = zipfile;
507 bi_buf = 0;
508 bi_valid = 0;
509#ifdef DEBUG
510 bits_sent = 0L;
511#endif
512
513 /* Set the defaults for file compression. They are set by memcompress
514 * for in-memory compression.
515 */
516 if (zfile != NO_FILE) {
517 read_buf = file_read;
518 }
519}
520
521/* ===========================================================================
522 * Send a value on a given number of bits.
523 * IN assertion: length <= 16 and value fits in length bits.
524 */
525static void send_bits(int value, int length)
526{
527#ifdef DEBUG
528 Tracev((stderr, " l %2d v %4x ", length, value));
529 Assert(length > 0 && length <= 15, "invalid length");
530 bits_sent += (ulg) length;
531#endif
532 /* If not enough room in bi_buf, use (valid) bits from bi_buf and
533 * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
534 * unused bits in value.
535 */
536 if (bi_valid > (int) Buf_size - length) {
537 bi_buf |= (value << bi_valid);
538 put_short(bi_buf);
539 bi_buf = (ush) value >> (Buf_size - bi_valid);
540 bi_valid += length - Buf_size;
541 } else {
542 bi_buf |= value << bi_valid;
543 bi_valid += length;
544 }
545}
546
547/* ===========================================================================
548 * Reverse the first len bits of a code, using straightforward code (a faster
549 * method would use a table)
550 * IN assertion: 1 <= len <= 15
551 */
552static unsigned bi_reverse(unsigned code, int len)
553{
554 register unsigned res = 0;
555
556 do {
557 res |= code & 1;
558 code >>= 1, res <<= 1;
559 } while (--len > 0);
560 return res >> 1;
561}
562
563/* ===========================================================================
564 * Write out any remaining bits in an incomplete byte.
565 */
566static void bi_windup()
567{
568 if (bi_valid > 8) {
569 put_short(bi_buf);
570 } else if (bi_valid > 0) {
571 put_byte(bi_buf);
572 }
573 bi_buf = 0;
574 bi_valid = 0;
575#ifdef DEBUG
576 bits_sent = (bits_sent + 7) & ~7;
577#endif
578}
579
580/* ===========================================================================
581 * Copy a stored block to the zip file, storing first the length and its
582 * one's complement if requested.
583 */
584static void copy_block(char *buf, unsigned len, int header)
585{
586 bi_windup(); /* align on byte boundary */
587
588 if (header) {
589 put_short((ush) len);
590 put_short((ush) ~ len);
591#ifdef DEBUG
592 bits_sent += 2 * 16;
593#endif
594 }
595#ifdef DEBUG
596 bits_sent += (ulg) len << 3;
597#endif
598 while (len--) {
599 put_byte(*buf++);
600 }
601}
602
603/* deflate.c -- compress data using the deflation algorithm
604 * Copyright (C) 1992-1993 Jean-loup Gailly
605 * This is free software; you can redistribute it and/or modify it under the
606 * terms of the GNU General Public License, see the file COPYING.
607 */
608
609/*
610 * PURPOSE
611 *
612 * Identify new text as repetitions of old text within a fixed-
613 * length sliding window trailing behind the new text.
614 *
615 * DISCUSSION
616 *
617 * The "deflation" process depends on being able to identify portions
618 * of the input text which are identical to earlier input (within a
619 * sliding window trailing behind the input currently being processed).
620 *
621 * The most straightforward technique turns out to be the fastest for
622 * most input files: try all possible matches and select the longest.
623 * The key feature of this algorithm is that insertions into the string
624 * dictionary are very simple and thus fast, and deletions are avoided
625 * completely. Insertions are performed at each input character, whereas
626 * string matches are performed only when the previous match ends. So it
627 * is preferable to spend more time in matches to allow very fast string
628 * insertions and avoid deletions. The matching algorithm for small
629 * strings is inspired from that of Rabin & Karp. A brute force approach
630 * is used to find longer strings when a small match has been found.
631 * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
632 * (by Leonid Broukhis).
633 * A previous version of this file used a more sophisticated algorithm
634 * (by Fiala and Greene) which is guaranteed to run in linear amortized
635 * time, but has a larger average cost, uses more memory and is patented.
636 * However the F&G algorithm may be faster for some highly redundant
637 * files if the parameter max_chain_length (described below) is too large.
638 *
639 * ACKNOWLEDGEMENTS
640 *
641 * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
642 * I found it in 'freeze' written by Leonid Broukhis.
643 * Thanks to many info-zippers for bug reports and testing.
644 *
645 * REFERENCES
646 *
647 * APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
648 *
649 * A description of the Rabin and Karp algorithm is given in the book
650 * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
651 *
652 * Fiala,E.R., and Greene,D.H.
653 * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
654 *
655 * INTERFACE
656 *
657 * void lm_init (int pack_level, ush *flags)
658 * Initialize the "longest match" routines for a new file
659 *
660 * ulg deflate (void)
661 * Processes a new input file and return its compressed length. Sets
662 * the compressed length, crc, deflate flags and internal file
663 * attributes.
664 */
665
666
667/* ===========================================================================
668 * Configuration parameters
669 */
670
671/* Compile with MEDIUM_MEM to reduce the memory requirements or
672 * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
673 * entire input file can be held in memory (not possible on 16 bit systems).
674 * Warning: defining these symbols affects HASH_BITS (see below) and thus
675 * affects the compression ratio. The compressed output
676 * is still correct, and might even be smaller in some cases.
677 */
678
679#ifdef SMALL_MEM
680# define HASH_BITS 13 /* Number of bits used to hash strings */
681#endif
682#ifdef MEDIUM_MEM
683# define HASH_BITS 14
684#endif
685#ifndef HASH_BITS
686# define HASH_BITS 15
687 /* For portability to 16 bit machines, do not use values above 15. */
688#endif
689
690/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
691 * window with tab_suffix. Check that we can do this:
692 */
693#if (WSIZE<<1) > (1<<BITS)
694# error cannot overlay window with tab_suffix and prev with tab_prefix0
695#endif
696#if HASH_BITS > BITS-1
697# error cannot overlay head with tab_prefix1
698#endif
699#define HASH_SIZE (unsigned)(1<<HASH_BITS)
700#define HASH_MASK (HASH_SIZE-1)
701#define WMASK (WSIZE-1)
702/* HASH_SIZE and WSIZE must be powers of two */
703#define NIL 0
704/* Tail of hash chains */
705#define FAST 4
706#define SLOW 2
707/* speed options for the general purpose bit flag */
708#ifndef TOO_FAR
709# define TOO_FAR 4096
710#endif
711/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
712/* ===========================================================================
713 * Local data used by the "longest match" routines.
714 */
715typedef ush Pos;
716typedef unsigned IPos;
717
718/* A Pos is an index in the character window. We use short instead of int to
719 * save space in the various tables. IPos is used only for parameter passing.
720 */
721
722/* DECLARE(uch, window, 2L*WSIZE); */
723/* Sliding window. Input bytes are read into the second half of the window,
724 * and move to the first half later to keep a dictionary of at least WSIZE
725 * bytes. With this organization, matches are limited to a distance of
726 * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
727 * performed with a length multiple of the block size. Also, it limits
728 * the window size to 64K, which is quite useful on MSDOS.
729 * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
730 * be less efficient).
731 */
732
733/* DECLARE(Pos, prev, WSIZE); */
734/* Link to older string with same hash index. To limit the size of this
735 * array to 64K, this link is maintained only for the last 32K strings.
736 * An index in this array is thus a window index modulo 32K.
737 */
738
739/* DECLARE(Pos, head, 1<<HASH_BITS); */
740/* Heads of the hash chains or NIL. */
741
742static const ulg window_size = (ulg) 2 * WSIZE;
743
744/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
745 * input file length plus MIN_LOOKAHEAD.
746 */
747
748static long block_start;
749
750/* window position at the beginning of the current output block. Gets
751 * negative when the window is moved backwards.
752 */
753
754static unsigned ins_h; /* hash index of string to be inserted */
755
756#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
757/* Number of bits by which ins_h and del_h must be shifted at each
758 * input step. It must be such that after MIN_MATCH steps, the oldest
759 * byte no longer takes part in the hash key, that is:
760 * H_SHIFT * MIN_MATCH >= HASH_BITS
761 */
762
763static unsigned int prev_length;
764
765/* Length of the best match at previous step. Matches not greater than this
766 * are discarded. This is used in the lazy match evaluation.
767 */
768
769static unsigned strstart; /* start of string to insert */
770static unsigned match_start; /* start of matching string */
771static int eofile; /* flag set at end of input file */
772static unsigned lookahead; /* number of valid bytes ahead in window */
773
774static const unsigned max_chain_length=4096;
775
776/* To speed up deflation, hash chains are never searched beyond this length.
777 * A higher limit improves compression ratio but degrades the speed.
778 */
779
780static const unsigned int max_lazy_match=258;
781
782/* Attempt to find a better match only when the current match is strictly
783 * smaller than this value. This mechanism is used only for compression
784 * levels >= 4.
785 */
786#define max_insert_length max_lazy_match
787/* Insert new strings in the hash table only if the match length
788 * is not greater than this length. This saves time but degrades compression.
789 * max_insert_length is used only for compression levels <= 3.
790 */
791
792static const unsigned good_match=32;
793
794/* Use a faster search when the previous match is longer than this */
795
796
797/* Values for max_lazy_match, good_match and max_chain_length, depending on
798 * the desired pack level (0..9). The values given below have been tuned to
799 * exclude worst case performance for pathological files. Better values may be
800 * found for specific files.
801 */
802
803static const int nice_match=258; /* Stop searching when current match exceeds this */
804
805/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
806 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
807 * meaning.
808 */
809
810#define EQUAL 0
811/* result of memcmp for equal strings */
812
813/* ===========================================================================
814 * Prototypes for local functions.
815 */
816static void fill_window (void);
817
818static int longest_match (IPos cur_match);
819
820#ifdef DEBUG
821static void check_match (IPos start, IPos match, int length);
822#endif
823
824/* ===========================================================================
825 * Update a hash value with the given input byte
826 * IN assertion: all calls to to UPDATE_HASH are made with consecutive
827 * input characters, so that a running hash key can be computed from the
828 * previous key instead of complete recalculation each time.
829 */
830#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
831
832/* ===========================================================================
833 * Insert string s in the dictionary and set match_head to the previous head
834 * of the hash chain (the most recent string with same hash key). Return
835 * the previous length of the hash chain.
836 * IN assertion: all calls to to INSERT_STRING are made with consecutive
837 * input characters and the first MIN_MATCH bytes of s are valid
838 * (except for the last MIN_MATCH-1 bytes of the input file).
839 */
840#define INSERT_STRING(s, match_head) \
841 (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
842 prev[(s) & WMASK] = match_head = head[ins_h], \
843 head[ins_h] = (s))
844
845/* ===========================================================================
846 * Initialize the "longest match" routines for a new file
847 */
848static void lm_init(ush *flags)
849{
850 register unsigned j;
851
852 /* Initialize the hash table. */
853 memzero((char *) head, HASH_SIZE * sizeof(*head));
854 /* prev will be initialized on the fly */
855
856 *flags |= SLOW;
857 /* ??? reduce max_chain_length for binary files */
858
859 strstart = 0;
860 block_start = 0L;
861
862 lookahead = read_buf((char *) window,
863 sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE);
864
865 if (lookahead == 0 || lookahead == (unsigned) EOF) {
866 eofile = 1, lookahead = 0;
867 return;
868 }
869 eofile = 0;
870 /* Make sure that we always have enough lookahead. This is important
871 * if input comes from a device such as a tty.
872 */
873 while (lookahead < MIN_LOOKAHEAD && !eofile)
874 fill_window();
875
876 ins_h = 0;
877 for (j = 0; j < MIN_MATCH - 1; j++)
878 UPDATE_HASH(ins_h, window[j]);
879 /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
880 * not important since only literal bytes will be emitted.
881 */
882}
883
884/* ===========================================================================
885 * Set match_start to the longest match starting at the given string and
886 * return its length. Matches shorter or equal to prev_length are discarded,
887 * in which case the result is equal to prev_length and match_start is
888 * garbage.
889 * IN assertions: cur_match is the head of the hash chain for the current
890 * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
891 */
892
893/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
894 * match.s. The code is functionally equivalent, so you can use the C version
895 * if desired.
896 */
897static int longest_match(IPos cur_match)
898{
899 unsigned chain_length = max_chain_length; /* max hash chain length */
900 register uch *scan = window + strstart; /* current string */
901 register uch *match; /* matched string */
902 register int len; /* length of current match */
903 int best_len = prev_length; /* best match length so far */
904 IPos limit =
905
906 strstart > (IPos) MAX_DIST ? strstart - (IPos) MAX_DIST : NIL;
907 /* Stop when cur_match becomes <= limit. To simplify the code,
908 * we prevent matches with the string of window index 0.
909 */
910
911/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
912 * It is easy to get rid of this optimization if necessary.
913 */
914#if HASH_BITS < 8 || MAX_MATCH != 258
915# error Code too clever
916#endif
917 register uch *strend = window + strstart + MAX_MATCH;
918 register uch scan_end1 = scan[best_len - 1];
919 register uch scan_end = scan[best_len];
920
921 /* Do not waste too much time if we already have a good match: */
922 if (prev_length >= good_match) {
923 chain_length >>= 2;
924 }
925 Assert(strstart <= window_size - MIN_LOOKAHEAD,
926 "insufficient lookahead");
927
928 do {
929 Assert(cur_match < strstart, "no future");
930 match = window + cur_match;
931
932 /* Skip to next match if the match length cannot increase
933 * or if the match length is less than 2:
934 */
935 if (match[best_len] != scan_end ||
936 match[best_len - 1] != scan_end1 ||
937 *match != *scan || *++match != scan[1])
938 continue;
939
940 /* The check at best_len-1 can be removed because it will be made
941 * again later. (This heuristic is not always a win.)
942 * It is not necessary to compare scan[2] and match[2] since they
943 * are always equal when the other bytes match, given that
944 * the hash keys are equal and that HASH_BITS >= 8.
945 */
946 scan += 2, match++;
947
948 /* We check for insufficient lookahead only every 8th comparison;
949 * the 256th check will be made at strstart+258.
950 */
951 do {
952 } while (*++scan == *++match && *++scan == *++match &&
953 *++scan == *++match && *++scan == *++match &&
954 *++scan == *++match && *++scan == *++match &&
955 *++scan == *++match && *++scan == *++match &&
956 scan < strend);
957
958 len = MAX_MATCH - (int) (strend - scan);
959 scan = strend - MAX_MATCH;
960
961 if (len > best_len) {
962 match_start = cur_match;
963 best_len = len;
964 if (len >= nice_match)
965 break;
966 scan_end1 = scan[best_len - 1];
967 scan_end = scan[best_len];
968 }
969 } while ((cur_match = prev[cur_match & WMASK]) > limit
970 && --chain_length != 0);
971
972 return best_len;
973}
974
975#ifdef DEBUG
976/* ===========================================================================
977 * Check that the match at match_start is indeed a match.
978 */
979static void check_match(IPos start, IPos match, int length)
980{
981 /* check that the match is indeed a match */
982 if (memcmp((char *) window + match,
983 (char *) window + start, length) != EQUAL) {
984 fprintf(stderr,
985 " start %d, match %d, length %d\n", start, match, length);
986 error_msg("invalid match");
987 }
988 if (verbose > 1) {
989 fprintf(stderr, "\\[%d,%d]", start - match, length);
990 do {
991 putc(window[start++], stderr);
992 } while (--length != 0);
993 }
994}
995#else
996# define check_match(start, match, length)
997#endif
998
999/* ===========================================================================
1000 * Fill the window when the lookahead becomes insufficient.
1001 * Updates strstart and lookahead, and sets eofile if end of input file.
1002 * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
1003 * OUT assertions: at least one byte has been read, or eofile is set;
1004 * file reads are performed for at least two bytes (required for the
1005 * translate_eol option).
1006 */
1007static void fill_window()
1008{
1009 register unsigned n, m;
1010 unsigned more =
1011
1012 (unsigned) (window_size - (ulg) lookahead - (ulg) strstart);
1013 /* Amount of free space at the end of the window. */
1014
1015 /* If the window is almost full and there is insufficient lookahead,
1016 * move the upper half to the lower one to make room in the upper half.
1017 */
1018 if (more == (unsigned) EOF) {
1019 /* Very unlikely, but possible on 16 bit machine if strstart == 0
1020 * and lookahead == 1 (input done one byte at time)
1021 */
1022 more--;
1023 } else if (strstart >= WSIZE + MAX_DIST) {
1024 /* By the IN assertion, the window is not empty so we can't confuse
1025 * more == 0 with more == 64K on a 16 bit machine.
1026 */
1027 Assert(window_size == (ulg) 2 * WSIZE, "no sliding with BIG_MEM");
1028
1029 memcpy((char *) window, (char *) window + WSIZE, (unsigned) WSIZE);
1030 match_start -= WSIZE;
1031 strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
1032
1033 block_start -= (long) WSIZE;
1034
1035 for (n = 0; n < HASH_SIZE; n++) {
1036 m = head[n];
1037 head[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
1038 }
1039 for (n = 0; n < WSIZE; n++) {
1040 m = prev[n];
1041 prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
1042 /* If n is not on any hash chain, prev[n] is garbage but
1043 * its value will never be used.
1044 */
1045 }
1046 more += WSIZE;
1047 }
1048 /* At this point, more >= 2 */
1049 if (!eofile) {
1050 n = read_buf((char *) window + strstart + lookahead, more);
1051 if (n == 0 || n == (unsigned) EOF) {
1052 eofile = 1;
1053 } else {
1054 lookahead += n;
1055 }
1056 }
1057}
1058
1059/* ===========================================================================
1060 * Flush the current block, with given end-of-file flag.
1061 * IN assertion: strstart is set to the end of the current match.
1062 */
1063#define FLUSH_BLOCK(eof) \
1064 flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
1065 (char*)NULL, (long)strstart - block_start, (eof))
1066
1067/* ===========================================================================
1068 * Same as above, but achieves better compression. We use a lazy
1069 * evaluation for matches: a match is finally adopted only if there is
1070 * no better match at the next window position.
1071 */
1072static ulg deflate()
1073{
1074 IPos hash_head; /* head of hash chain */
1075 IPos prev_match; /* previous match */
1076 int flush; /* set if current block must be flushed */
1077 int match_available = 0; /* set if previous match exists */
1078 register unsigned match_length = MIN_MATCH - 1; /* length of best match */
1079
1080 /* Process the input block. */
1081 while (lookahead != 0) {
1082 /* Insert the string window[strstart .. strstart+2] in the
1083 * dictionary, and set hash_head to the head of the hash chain:
1084 */
1085 INSERT_STRING(strstart, hash_head);
1086
1087 /* Find the longest match, discarding those <= prev_length.
1088 */
1089 prev_length = match_length, prev_match = match_start;
1090 match_length = MIN_MATCH - 1;
1091
1092 if (hash_head != NIL && prev_length < max_lazy_match &&
1093 strstart - hash_head <= MAX_DIST) {
1094 /* To simplify the code, we prevent matches with the string
1095 * of window index 0 (in particular we have to avoid a match
1096 * of the string with itself at the start of the input file).
1097 */
1098 match_length = longest_match(hash_head);
1099 /* longest_match() sets match_start */
1100 if (match_length > lookahead)
1101 match_length = lookahead;
1102
1103 /* Ignore a length 3 match if it is too distant: */
1104 if (match_length == MIN_MATCH
1105 && strstart - match_start > TOO_FAR) {
1106 /* If prev_match is also MIN_MATCH, match_start is garbage
1107 * but we will ignore the current match anyway.
1108 */
1109 match_length--;
1110 }
1111 }
1112 /* If there was a match at the previous step and the current
1113 * match is not better, output the previous match:
1114 */
1115 if (prev_length >= MIN_MATCH && match_length <= prev_length) {
1116
1117 check_match(strstart - 1, prev_match, prev_length);
1118
1119 flush =
1120 ct_tally(strstart - 1 - prev_match,
1121 prev_length - MIN_MATCH);
1122
1123 /* Insert in hash table all strings up to the end of the match.
1124 * strstart-1 and strstart are already inserted.
1125 */
1126 lookahead -= prev_length - 1;
1127 prev_length -= 2;
1128 do {
1129 strstart++;
1130 INSERT_STRING(strstart, hash_head);
1131 /* strstart never exceeds WSIZE-MAX_MATCH, so there are
1132 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
1133 * these bytes are garbage, but it does not matter since the
1134 * next lookahead bytes will always be emitted as literals.
1135 */
1136 } while (--prev_length != 0);
1137 match_available = 0;
1138 match_length = MIN_MATCH - 1;
1139 strstart++;
1140 if (flush)
1141 FLUSH_BLOCK(0), block_start = strstart;
1142
1143 } else if (match_available) {
1144 /* If there was no match at the previous position, output a
1145 * single literal. If there was a match but the current match
1146 * is longer, truncate the previous match to a single literal.
1147 */
1148 Tracevv((stderr, "%c", window[strstart - 1]));
1149 if (ct_tally(0, window[strstart - 1])) {
1150 FLUSH_BLOCK(0), block_start = strstart;
1151 }
1152 strstart++;
1153 lookahead--;
1154 } else {
1155 /* There is no previous match to compare with, wait for
1156 * the next step to decide.
1157 */
1158 match_available = 1;
1159 strstart++;
1160 lookahead--;
1161 }
1162 Assert(strstart <= isize && lookahead <= isize, "a bit too far");
1163
1164 /* Make sure that we always have enough lookahead, except
1165 * at the end of the input file. We need MAX_MATCH bytes
1166 * for the next match, plus MIN_MATCH bytes to insert the
1167 * string following the next match.
1168 */
1169 while (lookahead < MIN_LOOKAHEAD && !eofile)
1170 fill_window();
1171 }
1172 if (match_available)
1173 ct_tally(0, window[strstart - 1]);
1174
1175 return FLUSH_BLOCK(1); /* eof */
1176}
1177
1178/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
1179 * Copyright (C) 1992-1993 Jean-loup Gailly
1180 * The unzip code was written and put in the public domain by Mark Adler.
1181 * Portions of the lzw code are derived from the public domain 'compress'
1182 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
1183 * Ken Turkowski, Dave Mack and Peter Jannesen.
1184 *
1185 * See the license_msg below and the file COPYING for the software license.
1186 * See the file algorithm.doc for the compression algorithms and file formats.
1187 */
1188
1189/* Compress files with zip algorithm and 'compress' interface.
1190 * See usage() and help() functions below for all options.
1191 * Outputs:
1192 * file.gz: compressed file with same mode, owner, and utimes
1193 * or stdout with -c option or if stdin used as input.
1194 * If the output file name had to be truncated, the original name is kept
1195 * in the compressed file.
1196 */
1197
1198 /* configuration */
1199
1200typedef struct dirent dir_type;
1201
1202typedef RETSIGTYPE(*sig_type) (int);
1203
1204/* ======================================================================== */
1205// int main (argc, argv)
1206// int argc;
1207// char **argv;
1208int gzip_main(int argc, char **argv)
1209{
1210 int result;
1211 int inFileNum;
1212 int outFileNum;
1213 struct stat statBuf;
1214 char *delFileName;
1215 int tostdout = 0;
1216 int fromstdin = 0;
1217 int force = 0;
1218 int opt;
1219
1220 while ((opt = getopt(argc, argv, "cf123456789dq")) != -1) {
1221 switch (opt) {
1222 case 'c':
1223 tostdout = 1;
1224 break;
1225 case 'f':
1226 force = 1;
1227 break;
1228 /* Ignore 1-9 (compression level) options */
1229 case '1': case '2': case '3': case '4': case '5':
1230 case '6': case '7': case '8': case '9':
1231 break;
1232 case 'q':
1233 break;
1234#ifdef BB_GUNZIP
1235 case 'd':
1236 optind = 1;
1237 return gunzip_main(argc, argv);
1238#endif
1239 default:
1240 show_usage();
1241 }
1242 }
1243 if ((optind == argc) || (strcmp(argv[optind], "-") == 0)) {
1244 fromstdin = 1;
1245 tostdout = 1;
1246 }
1247
1248 if (isatty(fileno(stdout)) && tostdout==1 && force==0)
1249 error_msg_and_die( "compressed data not written to terminal. Use -f to force it.");
1250
1251 foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
1252 if (foreground) {
1253 (void) signal(SIGINT, (sig_type) abort_gzip);
1254 }
1255#ifdef SIGTERM
1256 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
1257 (void) signal(SIGTERM, (sig_type) abort_gzip);
1258 }
1259#endif
1260#ifdef SIGHUP
1261 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
1262 (void) signal(SIGHUP, (sig_type) abort_gzip);
1263 }
1264#endif
1265
1266 strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix) - 1);
1267 z_len = strlen(z_suffix);
1268
1269 /* Allocate all global buffers (for DYN_ALLOC option) */
1270 ALLOC(uch, inbuf, INBUFSIZ + INBUF_EXTRA);
1271 ALLOC(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA);
1272 ALLOC(ush, d_buf, DIST_BUFSIZE);
1273 ALLOC(uch, window, 2L * WSIZE);
1274 ALLOC(ush, tab_prefix, 1L << BITS);
1275
1276 if (fromstdin == 1) {
1277 strcpy(ofname, "stdin");
1278
1279 inFileNum = fileno(stdin);
1280 time_stamp = 0; /* time unknown by default */
1281 ifile_size = -1L; /* convention for unknown size */
1282 } else {
1283 /* Open up the input file */
1284 strncpy(ifname, argv[optind], MAX_PATH_LEN);
1285
1286 /* Open input file */
1287 inFileNum = open(ifname, O_RDONLY);
1288 if (inFileNum < 0 || stat(ifname, &statBuf) < 0)
1289 perror_msg_and_die("%s", ifname);
1290 /* Get the time stamp on the input file. */
1291 time_stamp = statBuf.st_ctime;
1292 ifile_size = statBuf.st_size;
1293 }
1294
1295
1296 if (tostdout == 1) {
1297 /* And get to work */
1298 strcpy(ofname, "stdout");
1299 outFileNum = fileno(stdout);
1300
1301 clear_bufs(); /* clear input and output buffers */
1302 part_nb = 0;
1303
1304 /* Actually do the compression/decompression. */
1305 zip(inFileNum, outFileNum);
1306
1307 } else {
1308
1309 /* And get to work */
1310 strncpy(ofname, ifname, MAX_PATH_LEN - 4);
1311 strcat(ofname, ".gz");
1312
1313
1314 /* Open output fille */
1315#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
1316 outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW);
1317#else
1318 outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL);
1319#endif
1320 if (outFileNum < 0)
1321 perror_msg_and_die("%s", ofname);
1322 /* Set permissions on the file */
1323 fchmod(outFileNum, statBuf.st_mode);
1324
1325 clear_bufs(); /* clear input and output buffers */
1326 part_nb = 0;
1327
1328 /* Actually do the compression/decompression. */
1329 result = zip(inFileNum, outFileNum);
1330 close(outFileNum);
1331 close(inFileNum);
1332 /* Delete the original file */
1333 if (result == OK)
1334 delFileName = ifname;
1335 else
1336 delFileName = ofname;
1337
1338 if (unlink(delFileName) < 0)
1339 perror_msg_and_die("%s", delFileName);
1340 }
1341
1342 return(exit_code);
1343}
1344
1345/* trees.c -- output deflated data using Huffman coding
1346 * Copyright (C) 1992-1993 Jean-loup Gailly
1347 * This is free software; you can redistribute it and/or modify it under the
1348 * terms of the GNU General Public License, see the file COPYING.
1349 */
1350
1351/*
1352 * PURPOSE
1353 *
1354 * Encode various sets of source values using variable-length
1355 * binary code trees.
1356 *
1357 * DISCUSSION
1358 *
1359 * The PKZIP "deflation" process uses several Huffman trees. The more
1360 * common source values are represented by shorter bit sequences.
1361 *
1362 * Each code tree is stored in the ZIP file in a compressed form
1363 * which is itself a Huffman encoding of the lengths of
1364 * all the code strings (in ascending order by source values).
1365 * The actual code strings are reconstructed from the lengths in
1366 * the UNZIP process, as described in the "application note"
1367 * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
1368 *
1369 * REFERENCES
1370 *
1371 * Lynch, Thomas J.
1372 * Data Compression: Techniques and Applications, pp. 53-55.
1373 * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
1374 *
1375 * Storer, James A.
1376 * Data Compression: Methods and Theory, pp. 49-50.
1377 * Computer Science Press, 1988. ISBN 0-7167-8156-5.
1378 *
1379 * Sedgewick, R.
1380 * Algorithms, p290.
1381 * Addison-Wesley, 1983. ISBN 0-201-06672-6.
1382 *
1383 * INTERFACE
1384 *
1385 * void ct_init (ush *attr, int *methodp)
1386 * Allocate the match buffer, initialize the various tables and save
1387 * the location of the internal file attribute (ascii/binary) and
1388 * method (DEFLATE/STORE)
1389 *
1390 * void ct_tally (int dist, int lc);
1391 * Save the match info and tally the frequency counts.
1392 *
1393 * long flush_block (char *buf, ulg stored_len, int eof)
1394 * Determine the best encoding for the current block: dynamic trees,
1395 * static trees or store, and output the encoded block to the zip
1396 * file. Returns the total compressed length for the file so far.
1397 *
1398 */
1399
1400/* ===========================================================================
1401 * Constants
1402 */
1403
1404#define MAX_BITS 15
1405/* All codes must not exceed MAX_BITS bits */
1406
1407#define MAX_BL_BITS 7
1408/* Bit length codes must not exceed MAX_BL_BITS bits */
1409
1410#define LENGTH_CODES 29
1411/* number of length codes, not counting the special END_BLOCK code */
1412
1413#define LITERALS 256
1414/* number of literal bytes 0..255 */
1415
1416#define END_BLOCK 256
1417/* end of block literal code */
1418
1419#define L_CODES (LITERALS+1+LENGTH_CODES)
1420/* number of Literal or Length codes, including the END_BLOCK code */
1421
1422#define D_CODES 30
1423/* number of distance codes */
1424
1425#define BL_CODES 19
1426/* number of codes used to transfer the bit lengths */
1427
1428typedef uch extra_bits_t;
1429
1430/* extra bits for each length code */
1431static const extra_bits_t extra_lbits[LENGTH_CODES]
1432 = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
1433 4, 4, 5, 5, 5, 5, 0 };
1434
1435/* extra bits for each distance code */
1436static const extra_bits_t extra_dbits[D_CODES]
1437 = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
1438 10, 10, 11, 11, 12, 12, 13, 13 };
1439
1440/* extra bits for each bit length code */
1441static const extra_bits_t extra_blbits[BL_CODES]
1442= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 };
1443
1444#define STORED_BLOCK 0
1445#define STATIC_TREES 1
1446#define DYN_TREES 2
1447/* The three kinds of block type */
1448
1449#ifndef LIT_BUFSIZE
1450# ifdef SMALL_MEM
1451# define LIT_BUFSIZE 0x2000
1452# else
1453# ifdef MEDIUM_MEM
1454# define LIT_BUFSIZE 0x4000
1455# else
1456# define LIT_BUFSIZE 0x8000
1457# endif
1458# endif
1459#endif
1460#ifndef DIST_BUFSIZE
1461# define DIST_BUFSIZE LIT_BUFSIZE
1462#endif
1463/* Sizes of match buffers for literals/lengths and distances. There are
1464 * 4 reasons for limiting LIT_BUFSIZE to 64K:
1465 * - frequencies can be kept in 16 bit counters
1466 * - if compression is not successful for the first block, all input data is
1467 * still in the window so we can still emit a stored block even when input
1468 * comes from standard input. (This can also be done for all blocks if
1469 * LIT_BUFSIZE is not greater than 32K.)
1470 * - if compression is not successful for a file smaller than 64K, we can
1471 * even emit a stored file instead of a stored block (saving 5 bytes).
1472 * - creating new Huffman trees less frequently may not provide fast
1473 * adaptation to changes in the input data statistics. (Take for
1474 * example a binary file with poorly compressible code followed by
1475 * a highly compressible string table.) Smaller buffer sizes give
1476 * fast adaptation but have of course the overhead of transmitting trees
1477 * more frequently.
1478 * - I can't count above 4
1479 * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
1480 * memory at the expense of compression). Some optimizations would be possible
1481 * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
1482 */
1483#if LIT_BUFSIZE > INBUFSIZ
1484error cannot overlay l_buf and inbuf
1485#endif
1486#define REP_3_6 16
1487/* repeat previous bit length 3-6 times (2 bits of repeat count) */
1488#define REPZ_3_10 17
1489/* repeat a zero length 3-10 times (3 bits of repeat count) */
1490#define REPZ_11_138 18
1491/* repeat a zero length 11-138 times (7 bits of repeat count) *//* ===========================================================================
1492 * Local data
1493 *//* Data structure describing a single value and its code string. */ typedef struct ct_data {
1494 union {
1495 ush freq; /* frequency count */
1496 ush code; /* bit string */
1497 } fc;
1498 union {
1499 ush dad; /* father node in Huffman tree */
1500 ush len; /* length of bit string */
1501 } dl;
1502} ct_data;
1503
1504#define Freq fc.freq
1505#define Code fc.code
1506#define Dad dl.dad
1507#define Len dl.len
1508
1509#define HEAP_SIZE (2*L_CODES+1)
1510/* maximum heap size */
1511
1512static ct_data dyn_ltree[HEAP_SIZE]; /* literal and length tree */
1513static ct_data dyn_dtree[2 * D_CODES + 1]; /* distance tree */
1514
1515static ct_data static_ltree[L_CODES + 2];
1516
1517/* The static literal tree. Since the bit lengths are imposed, there is no
1518 * need for the L_CODES extra codes used during heap construction. However
1519 * The codes 286 and 287 are needed to build a canonical tree (see ct_init
1520 * below).
1521 */
1522
1523static ct_data static_dtree[D_CODES];
1524
1525/* The static distance tree. (Actually a trivial tree since all codes use
1526 * 5 bits.)
1527 */
1528
1529static ct_data bl_tree[2 * BL_CODES + 1];
1530
1531/* Huffman tree for the bit lengths */
1532
1533typedef struct tree_desc {
1534 ct_data *dyn_tree; /* the dynamic tree */
1535 ct_data *static_tree; /* corresponding static tree or NULL */
1536 const extra_bits_t *extra_bits; /* extra bits for each code or NULL */
1537 int extra_base; /* base index for extra_bits */
1538 int elems; /* max number of elements in the tree */
1539 int max_length; /* max bit length for the codes */
1540 int max_code; /* largest code with non zero frequency */
1541} tree_desc;
1542
1543static tree_desc l_desc =
1544 { dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES,
1545 MAX_BITS, 0 };
1546
1547static tree_desc d_desc =
1548 { dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0 };
1549
1550static tree_desc bl_desc =
1551 { bl_tree, (ct_data *) 0, extra_blbits, 0, BL_CODES, MAX_BL_BITS,
1552 0 };
1553
1554
1555static ush bl_count[MAX_BITS + 1];
1556
1557/* number of codes at each bit length for an optimal tree */
1558
1559static const uch bl_order[BL_CODES]
1560= { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
1561
1562/* The lengths of the bit length codes are sent in order of decreasing
1563 * probability, to avoid transmitting the lengths for unused bit length codes.
1564 */
1565
1566static int heap[2 * L_CODES + 1]; /* heap used to build the Huffman trees */
1567static int heap_len; /* number of elements in the heap */
1568static int heap_max; /* element of largest frequency */
1569
1570/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
1571 * The same heap array is used to build all trees.
1572 */
1573
1574static uch depth[2 * L_CODES + 1];
1575
1576/* Depth of each subtree used as tie breaker for trees of equal frequency */
1577
1578static uch length_code[MAX_MATCH - MIN_MATCH + 1];
1579
1580/* length code for each normalized match length (0 == MIN_MATCH) */
1581
1582static uch dist_code[512];
1583
1584/* distance codes. The first 256 values correspond to the distances
1585 * 3 .. 258, the last 256 values correspond to the top 8 bits of
1586 * the 15 bit distances.
1587 */
1588
1589static int base_length[LENGTH_CODES];
1590
1591/* First normalized length for each code (0 = MIN_MATCH) */
1592
1593static int base_dist[D_CODES];
1594
1595/* First normalized distance for each code (0 = distance of 1) */
1596
1597#define l_buf inbuf
1598/* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */
1599
1600/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
1601
1602static uch flag_buf[(LIT_BUFSIZE / 8)];
1603
1604/* flag_buf is a bit array distinguishing literals from lengths in
1605 * l_buf, thus indicating the presence or absence of a distance.
1606 */
1607
1608static unsigned last_lit; /* running index in l_buf */
1609static unsigned last_dist; /* running index in d_buf */
1610static unsigned last_flags; /* running index in flag_buf */
1611static uch flags; /* current flags not yet saved in flag_buf */
1612static uch flag_bit; /* current bit used in flags */
1613
1614/* bits are filled in flags starting at bit 0 (least significant).
1615 * Note: these flags are overkill in the current code since we don't
1616 * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
1617 */
1618
1619static ulg opt_len; /* bit length of current block with optimal trees */
1620static ulg static_len; /* bit length of current block with static trees */
1621
1622static ulg compressed_len; /* total bit length of compressed file */
1623
1624
1625static ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */
1626static int *file_method; /* pointer to DEFLATE or STORE */
1627
1628/* ===========================================================================
1629 * Local (static) routines in this file.
1630 */
1631
1632static void init_block (void);
1633static void pqdownheap (ct_data * tree, int k);
1634static void gen_bitlen (tree_desc * desc);
1635static void gen_codes (ct_data * tree, int max_code);
1636static void build_tree (tree_desc * desc);
1637static void scan_tree (ct_data * tree, int max_code);
1638static void send_tree (ct_data * tree, int max_code);
1639static int build_bl_tree (void);
1640static void send_all_trees (int lcodes, int dcodes, int blcodes);
1641static void compress_block (ct_data * ltree, ct_data * dtree);
1642static void set_file_type (void);
1643
1644
1645#ifndef DEBUG
1646# define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
1647 /* Send a code of the given tree. c and tree must not have side effects */
1648
1649#else /* DEBUG */
1650# define send_code(c, tree) \
1651 { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
1652 send_bits(tree[c].Code, tree[c].Len); }
1653#endif
1654
1655#define d_code(dist) \
1656 ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
1657/* Mapping from a distance to a distance code. dist is the distance - 1 and
1658 * must not have side effects. dist_code[256] and dist_code[257] are never
1659 * used.
1660 */
1661
1662/* the arguments must not have side effects */
1663
1664/* ===========================================================================
1665 * Allocate the match buffer, initialize the various tables and save the
1666 * location of the internal file attribute (ascii/binary) and method
1667 * (DEFLATE/STORE).
1668 */
1669static void ct_init(ush *attr, int *methodp)
1670{
1671 int n; /* iterates over tree elements */
1672 int bits; /* bit counter */
1673 int length; /* length value */
1674 int code; /* code value */
1675 int dist; /* distance index */
1676
1677 file_type = attr;
1678 file_method = methodp;
1679 compressed_len = 0L;
1680
1681 if (static_dtree[0].Len != 0)
1682 return; /* ct_init already called */
1683
1684 /* Initialize the mapping length (0..255) -> length code (0..28) */
1685 length = 0;
1686 for (code = 0; code < LENGTH_CODES - 1; code++) {
1687 base_length[code] = length;
1688 for (n = 0; n < (1 << extra_lbits[code]); n++) {
1689 length_code[length++] = (uch) code;
1690 }
1691 }
1692 Assert(length == 256, "ct_init: length != 256");
1693 /* Note that the length 255 (match length 258) can be represented
1694 * in two different ways: code 284 + 5 bits or code 285, so we
1695 * overwrite length_code[255] to use the best encoding:
1696 */
1697 length_code[length - 1] = (uch) code;
1698
1699 /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
1700 dist = 0;
1701 for (code = 0; code < 16; code++) {
1702 base_dist[code] = dist;
1703 for (n = 0; n < (1 << extra_dbits[code]); n++) {
1704 dist_code[dist++] = (uch) code;
1705 }
1706 }
1707 Assert(dist == 256, "ct_init: dist != 256");
1708 dist >>= 7; /* from now on, all distances are divided by 128 */
1709 for (; code < D_CODES; code++) {
1710 base_dist[code] = dist << 7;
1711 for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
1712 dist_code[256 + dist++] = (uch) code;
1713 }
1714 }
1715 Assert(dist == 256, "ct_init: 256+dist != 512");
1716
1717 /* Construct the codes of the static literal tree */
1718 for (bits = 0; bits <= MAX_BITS; bits++)
1719 bl_count[bits] = 0;
1720 n = 0;
1721 while (n <= 143)
1722 static_ltree[n++].Len = 8, bl_count[8]++;
1723 while (n <= 255)
1724 static_ltree[n++].Len = 9, bl_count[9]++;
1725 while (n <= 279)
1726 static_ltree[n++].Len = 7, bl_count[7]++;
1727 while (n <= 287)
1728 static_ltree[n++].Len = 8, bl_count[8]++;
1729 /* Codes 286 and 287 do not exist, but we must include them in the
1730 * tree construction to get a canonical Huffman tree (longest code
1731 * all ones)
1732 */
1733 gen_codes((ct_data *) static_ltree, L_CODES + 1);
1734
1735 /* The static distance tree is trivial: */
1736 for (n = 0; n < D_CODES; n++) {
1737 static_dtree[n].Len = 5;
1738 static_dtree[n].Code = bi_reverse(n, 5);
1739 }
1740
1741 /* Initialize the first block of the first file: */
1742 init_block();
1743}
1744
1745/* ===========================================================================
1746 * Initialize a new block.
1747 */
1748static void init_block()
1749{
1750 int n; /* iterates over tree elements */
1751
1752 /* Initialize the trees. */
1753 for (n = 0; n < L_CODES; n++)
1754 dyn_ltree[n].Freq = 0;
1755 for (n = 0; n < D_CODES; n++)
1756 dyn_dtree[n].Freq = 0;
1757 for (n = 0; n < BL_CODES; n++)
1758 bl_tree[n].Freq = 0;
1759
1760 dyn_ltree[END_BLOCK].Freq = 1;
1761 opt_len = static_len = 0L;
1762 last_lit = last_dist = last_flags = 0;
1763 flags = 0;
1764 flag_bit = 1;
1765}
1766
1767#define SMALLEST 1
1768/* Index within the heap array of least frequent node in the Huffman tree */
1769
1770
1771/* ===========================================================================
1772 * Remove the smallest element from the heap and recreate the heap with
1773 * one less element. Updates heap and heap_len.
1774 */
1775#define pqremove(tree, top) \
1776{\
1777 top = heap[SMALLEST]; \
1778 heap[SMALLEST] = heap[heap_len--]; \
1779 pqdownheap(tree, SMALLEST); \
1780}
1781
1782/* ===========================================================================
1783 * Compares to subtrees, using the tree depth as tie breaker when
1784 * the subtrees have equal frequency. This minimizes the worst case length.
1785 */
1786#define smaller(tree, n, m) \
1787 (tree[n].Freq < tree[m].Freq || \
1788 (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
1789
1790/* ===========================================================================
1791 * Restore the heap property by moving down the tree starting at node k,
1792 * exchanging a node with the smallest of its two sons if necessary, stopping
1793 * when the heap property is re-established (each father smaller than its
1794 * two sons).
1795 */
1796static void pqdownheap(ct_data *tree, int k)
1797{
1798 int v = heap[k];
1799 int j = k << 1; /* left son of k */
1800
1801 while (j <= heap_len) {
1802 /* Set j to the smallest of the two sons: */
1803 if (j < heap_len && smaller(tree, heap[j + 1], heap[j]))
1804 j++;
1805
1806 /* Exit if v is smaller than both sons */
1807 if (smaller(tree, v, heap[j]))
1808 break;
1809
1810 /* Exchange v with the smallest son */
1811 heap[k] = heap[j];
1812 k = j;
1813
1814 /* And continue down the tree, setting j to the left son of k */
1815 j <<= 1;
1816 }
1817 heap[k] = v;
1818}
1819
1820/* ===========================================================================
1821 * Compute the optimal bit lengths for a tree and update the total bit length
1822 * for the current block.
1823 * IN assertion: the fields freq and dad are set, heap[heap_max] and
1824 * above are the tree nodes sorted by increasing frequency.
1825 * OUT assertions: the field len is set to the optimal bit length, the
1826 * array bl_count contains the frequencies for each bit length.
1827 * The length opt_len is updated; static_len is also updated if stree is
1828 * not null.
1829 */
1830static void gen_bitlen(tree_desc *desc)
1831{
1832 ct_data *tree = desc->dyn_tree;
1833 const extra_bits_t *extra = desc->extra_bits;
1834 int base = desc->extra_base;
1835 int max_code = desc->max_code;
1836 int max_length = desc->max_length;
1837 ct_data *stree = desc->static_tree;
1838 int h; /* heap index */
1839 int n, m; /* iterate over the tree elements */
1840 int bits; /* bit length */
1841 int xbits; /* extra bits */
1842 ush f; /* frequency */
1843 int overflow = 0; /* number of elements with bit length too large */
1844
1845 for (bits = 0; bits <= MAX_BITS; bits++)
1846 bl_count[bits] = 0;
1847
1848 /* In a first pass, compute the optimal bit lengths (which may
1849 * overflow in the case of the bit length tree).
1850 */
1851 tree[heap[heap_max]].Len = 0; /* root of the heap */
1852
1853 for (h = heap_max + 1; h < HEAP_SIZE; h++) {
1854 n = heap[h];
1855 bits = tree[tree[n].Dad].Len + 1;
1856 if (bits > max_length)
1857 bits = max_length, overflow++;
1858 tree[n].Len = (ush) bits;
1859 /* We overwrite tree[n].Dad which is no longer needed */
1860
1861 if (n > max_code)
1862 continue; /* not a leaf node */
1863
1864 bl_count[bits]++;
1865 xbits = 0;
1866 if (n >= base)
1867 xbits = extra[n - base];
1868 f = tree[n].Freq;
1869 opt_len += (ulg) f *(bits + xbits);
1870
1871 if (stree)
1872 static_len += (ulg) f *(stree[n].Len + xbits);
1873 }
1874 if (overflow == 0)
1875 return;
1876
1877 Trace((stderr, "\nbit length overflow\n"));
1878 /* This happens for example on obj2 and pic of the Calgary corpus */
1879
1880 /* Find the first bit length which could increase: */
1881 do {
1882 bits = max_length - 1;
1883 while (bl_count[bits] == 0)
1884 bits--;
1885 bl_count[bits]--; /* move one leaf down the tree */
1886 bl_count[bits + 1] += 2; /* move one overflow item as its brother */
1887 bl_count[max_length]--;
1888 /* The brother of the overflow item also moves one step up,
1889 * but this does not affect bl_count[max_length]
1890 */
1891 overflow -= 2;
1892 } while (overflow > 0);
1893
1894 /* Now recompute all bit lengths, scanning in increasing frequency.
1895 * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
1896 * lengths instead of fixing only the wrong ones. This idea is taken
1897 * from 'ar' written by Haruhiko Okumura.)
1898 */
1899 for (bits = max_length; bits != 0; bits--) {
1900 n = bl_count[bits];
1901 while (n != 0) {
1902 m = heap[--h];
1903 if (m > max_code)
1904 continue;
1905 if (tree[m].Len != (unsigned) bits) {
1906 Trace(
1907 (stderr, "code %d bits %d->%d\n", m, tree[m].Len,
1908 bits));
1909 opt_len +=
1910 ((long) bits -
1911 (long) tree[m].Len) * (long) tree[m].Freq;
1912 tree[m].Len = (ush) bits;
1913 }
1914 n--;
1915 }
1916 }
1917}
1918
1919/* ===========================================================================
1920 * Generate the codes for a given tree and bit counts (which need not be
1921 * optimal).
1922 * IN assertion: the array bl_count contains the bit length statistics for
1923 * the given tree and the field len is set for all tree elements.
1924 * OUT assertion: the field code is set for all tree elements of non
1925 * zero code length.
1926 */
1927static void gen_codes(ct_data *tree, int max_code)
1928{
1929 ush next_code[MAX_BITS + 1]; /* next code value for each bit length */
1930 ush code = 0; /* running code value */
1931 int bits; /* bit index */
1932 int n; /* code index */
1933
1934 /* The distribution counts are first used to generate the code values
1935 * without bit reversal.
1936 */
1937 for (bits = 1; bits <= MAX_BITS; bits++) {
1938 next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
1939 }
1940 /* Check that the bit counts in bl_count are consistent. The last code
1941 * must be all ones.
1942 */
1943 Assert(code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
1944 "inconsistent bit counts");
1945 Tracev((stderr, "\ngen_codes: max_code %d ", max_code));
1946
1947 for (n = 0; n <= max_code; n++) {
1948 int len = tree[n].Len;
1949
1950 if (len == 0)
1951 continue;
1952 /* Now reverse the bits */
1953 tree[n].Code = bi_reverse(next_code[len]++, len);
1954
1955 Tracec(tree != static_ltree,
1956 (stderr, "\nn %3d %c l %2d c %4x (%x) ", n,
1957 (isgraph(n) ? n : ' '), len, tree[n].Code,
1958 next_code[len] - 1));
1959 }
1960}
1961
1962/* ===========================================================================
1963 * Construct one Huffman tree and assigns the code bit strings and lengths.
1964 * Update the total bit length for the current block.
1965 * IN assertion: the field freq is set for all tree elements.
1966 * OUT assertions: the fields len and code are set to the optimal bit length
1967 * and corresponding code. The length opt_len is updated; static_len is
1968 * also updated if stree is not null. The field max_code is set.
1969 */
1970static void build_tree(tree_desc *desc)
1971{
1972 ct_data *tree = desc->dyn_tree;
1973 ct_data *stree = desc->static_tree;
1974 int elems = desc->elems;
1975 int n, m; /* iterate over heap elements */
1976 int max_code = -1; /* largest code with non zero frequency */
1977 int node = elems; /* next internal node of the tree */
1978
1979 /* Construct the initial heap, with least frequent element in
1980 * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
1981 * heap[0] is not used.
1982 */
1983 heap_len = 0, heap_max = HEAP_SIZE;
1984
1985 for (n = 0; n < elems; n++) {
1986 if (tree[n].Freq != 0) {
1987 heap[++heap_len] = max_code = n;
1988 depth[n] = 0;
1989 } else {
1990 tree[n].Len = 0;
1991 }
1992 }
1993
1994 /* The pkzip format requires that at least one distance code exists,
1995 * and that at least one bit should be sent even if there is only one
1996 * possible code. So to avoid special checks later on we force at least
1997 * two codes of non zero frequency.
1998 */
1999 while (heap_len < 2) {
2000 int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
2001
2002 tree[new].Freq = 1;
2003 depth[new] = 0;
2004 opt_len--;
2005 if (stree)
2006 static_len -= stree[new].Len;
2007 /* new is 0 or 1 so it does not have extra bits */
2008 }
2009 desc->max_code = max_code;
2010
2011 /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
2012 * establish sub-heaps of increasing lengths:
2013 */
2014 for (n = heap_len / 2; n >= 1; n--)
2015 pqdownheap(tree, n);
2016
2017 /* Construct the Huffman tree by repeatedly combining the least two
2018 * frequent nodes.
2019 */
2020 do {
2021 pqremove(tree, n); /* n = node of least frequency */
2022 m = heap[SMALLEST]; /* m = node of next least frequency */
2023
2024 heap[--heap_max] = n; /* keep the nodes sorted by frequency */
2025 heap[--heap_max] = m;
2026
2027 /* Create a new node father of n and m */
2028 tree[node].Freq = tree[n].Freq + tree[m].Freq;
2029 depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
2030 tree[n].Dad = tree[m].Dad = (ush) node;
2031#ifdef DUMP_BL_TREE
2032 if (tree == bl_tree) {
2033 fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)",
2034 node, tree[node].Freq, n, tree[n].Freq, m,
2035 tree[m].Freq);
2036 }
2037#endif
2038 /* and insert the new node in the heap */
2039 heap[SMALLEST] = node++;
2040 pqdownheap(tree, SMALLEST);
2041
2042 } while (heap_len >= 2);
2043
2044 heap[--heap_max] = heap[SMALLEST];
2045
2046 /* At this point, the fields freq and dad are set. We can now
2047 * generate the bit lengths.
2048 */
2049 gen_bitlen((tree_desc *) desc);
2050
2051 /* The field len is now set, we can generate the bit codes */
2052 gen_codes((ct_data *) tree, max_code);
2053}
2054
2055/* ===========================================================================
2056 * Scan a literal or distance tree to determine the frequencies of the codes
2057 * in the bit length tree. Updates opt_len to take into account the repeat
2058 * counts. (The contribution of the bit length codes will be added later
2059 * during the construction of bl_tree.)
2060 */
2061static void scan_tree(ct_data *tree, int max_code)
2062{
2063 int n; /* iterates over all tree elements */
2064 int prevlen = -1; /* last emitted length */
2065 int curlen; /* length of current code */
2066 int nextlen = tree[0].Len; /* length of next code */
2067 int count = 0; /* repeat count of the current code */
2068 int max_count = 7; /* max repeat count */
2069 int min_count = 4; /* min repeat count */
2070
2071 if (nextlen == 0)
2072 max_count = 138, min_count = 3;
2073 tree[max_code + 1].Len = (ush) 0xffff; /* guard */
2074
2075 for (n = 0; n <= max_code; n++) {
2076 curlen = nextlen;
2077 nextlen = tree[n + 1].Len;
2078 if (++count < max_count && curlen == nextlen) {
2079 continue;
2080 } else if (count < min_count) {
2081 bl_tree[curlen].Freq += count;
2082 } else if (curlen != 0) {
2083 if (curlen != prevlen)
2084 bl_tree[curlen].Freq++;
2085 bl_tree[REP_3_6].Freq++;
2086 } else if (count <= 10) {
2087 bl_tree[REPZ_3_10].Freq++;
2088 } else {
2089 bl_tree[REPZ_11_138].Freq++;
2090 }
2091 count = 0;
2092 prevlen = curlen;
2093 if (nextlen == 0) {
2094 max_count = 138, min_count = 3;
2095 } else if (curlen == nextlen) {
2096 max_count = 6, min_count = 3;
2097 } else {
2098 max_count = 7, min_count = 4;
2099 }
2100 }
2101}
2102
2103/* ===========================================================================
2104 * Send a literal or distance tree in compressed form, using the codes in
2105 * bl_tree.
2106 */
2107static void send_tree(ct_data *tree, int max_code)
2108{
2109 int n; /* iterates over all tree elements */
2110 int prevlen = -1; /* last emitted length */
2111 int curlen; /* length of current code */
2112 int nextlen = tree[0].Len; /* length of next code */
2113 int count = 0; /* repeat count of the current code */
2114 int max_count = 7; /* max repeat count */
2115 int min_count = 4; /* min repeat count */
2116
2117/* tree[max_code+1].Len = -1; *//* guard already set */
2118 if (nextlen == 0)
2119 max_count = 138, min_count = 3;
2120
2121 for (n = 0; n <= max_code; n++) {
2122 curlen = nextlen;
2123 nextlen = tree[n + 1].Len;
2124 if (++count < max_count && curlen == nextlen) {
2125 continue;
2126 } else if (count < min_count) {
2127 do {
2128 send_code(curlen, bl_tree);
2129 } while (--count != 0);
2130
2131 } else if (curlen != 0) {
2132 if (curlen != prevlen) {
2133 send_code(curlen, bl_tree);
2134 count--;
2135 }
2136 Assert(count >= 3 && count <= 6, " 3_6?");
2137 send_code(REP_3_6, bl_tree);
2138 send_bits(count - 3, 2);
2139
2140 } else if (count <= 10) {
2141 send_code(REPZ_3_10, bl_tree);
2142 send_bits(count - 3, 3);
2143
2144 } else {
2145 send_code(REPZ_11_138, bl_tree);
2146 send_bits(count - 11, 7);
2147 }
2148 count = 0;
2149 prevlen = curlen;
2150 if (nextlen == 0) {
2151 max_count = 138, min_count = 3;
2152 } else if (curlen == nextlen) {
2153 max_count = 6, min_count = 3;
2154 } else {
2155 max_count = 7, min_count = 4;
2156 }
2157 }
2158}
2159
2160/* ===========================================================================
2161 * Construct the Huffman tree for the bit lengths and return the index in
2162 * bl_order of the last bit length code to send.
2163 */
2164static const int build_bl_tree()
2165{
2166 int max_blindex; /* index of last bit length code of non zero freq */
2167
2168 /* Determine the bit length frequencies for literal and distance trees */
2169 scan_tree((ct_data *) dyn_ltree, l_desc.max_code);
2170 scan_tree((ct_data *) dyn_dtree, d_desc.max_code);
2171
2172 /* Build the bit length tree: */
2173 build_tree((tree_desc *) (&bl_desc));
2174 /* opt_len now includes the length of the tree representations, except
2175 * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
2176 */
2177
2178 /* Determine the number of bit length codes to send. The pkzip format
2179 * requires that at least 4 bit length codes be sent. (appnote.txt says
2180 * 3 but the actual value used is 4.)
2181 */
2182 for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
2183 if (bl_tree[bl_order[max_blindex]].Len != 0)
2184 break;
2185 }
2186 /* Update opt_len to include the bit length tree and counts */
2187 opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
2188 Tracev(
2189 (stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len,
2190 static_len));
2191
2192 return max_blindex;
2193}
2194
2195/* ===========================================================================
2196 * Send the header for a block using dynamic Huffman trees: the counts, the
2197 * lengths of the bit length codes, the literal tree and the distance tree.
2198 * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
2199 */
2200static void send_all_trees(int lcodes, int dcodes, int blcodes)
2201{
2202 int rank; /* index in bl_order */
2203
2204 Assert(lcodes >= 257 && dcodes >= 1
2205 && blcodes >= 4, "not enough codes");
2206 Assert(lcodes <= L_CODES && dcodes <= D_CODES
2207 && blcodes <= BL_CODES, "too many codes");
2208 Tracev((stderr, "\nbl counts: "));
2209 send_bits(lcodes - 257, 5); /* not +255 as stated in appnote.txt */
2210 send_bits(dcodes - 1, 5);
2211 send_bits(blcodes - 4, 4); /* not -3 as stated in appnote.txt */
2212 for (rank = 0; rank < blcodes; rank++) {
2213 Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
2214 send_bits(bl_tree[bl_order[rank]].Len, 3);
2215 }
2216 Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
2217
2218 send_tree((ct_data *) dyn_ltree, lcodes - 1); /* send the literal tree */
2219 Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
2220
2221 send_tree((ct_data *) dyn_dtree, dcodes - 1); /* send the distance tree */
2222 Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
2223}
2224
2225/* ===========================================================================
2226 * Determine the best encoding for the current block: dynamic trees, static
2227 * trees or store, and output the encoded block to the zip file. This function
2228 * returns the total compressed length for the file so far.
2229 */
2230static ulg flush_block(char *buf, ulg stored_len, int eof)
2231{
2232 ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
2233 int max_blindex; /* index of last bit length code of non zero freq */
2234
2235 flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
2236
2237 /* Check if the file is ascii or binary */
2238 if (*file_type == (ush) UNKNOWN)
2239 set_file_type();
2240
2241 /* Construct the literal and distance trees */
2242 build_tree((tree_desc *) (&l_desc));
2243 Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
2244
2245 build_tree((tree_desc *) (&d_desc));
2246 Tracev(
2247 (stderr, "\ndist data: dyn %ld, stat %ld", opt_len,
2248 static_len));
2249 /* At this point, opt_len and static_len are the total bit lengths of
2250 * the compressed block data, excluding the tree representations.
2251 */
2252
2253 /* Build the bit length tree for the above two trees, and get the index
2254 * in bl_order of the last bit length code to send.
2255 */
2256 max_blindex = build_bl_tree();
2257
2258 /* Determine the best encoding. Compute first the block length in bytes */
2259 opt_lenb = (opt_len + 3 + 7) >> 3;
2260 static_lenb = (static_len + 3 + 7) >> 3;
2261
2262 Trace(
2263 (stderr,
2264 "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
2265 opt_lenb, opt_len, static_lenb, static_len, stored_len,
2266 last_lit, last_dist));
2267
2268 if (static_lenb <= opt_lenb)
2269 opt_lenb = static_lenb;
2270
2271 /* If compression failed and this is the first and last block,
2272 * and if the zip file can be seeked (to rewrite the local header),
2273 * the whole file is transformed into a stored file:
2274 */
2275 if (stored_len <= opt_lenb && eof && compressed_len == 0L
2276 && seekable()) {
2277 /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
2278 if (buf == (char *) 0)
2279 error_msg("block vanished");
2280
2281 copy_block(buf, (unsigned) stored_len, 0); /* without header */
2282 compressed_len = stored_len << 3;
2283 *file_method = STORED;
2284
2285 } else if (stored_len + 4 <= opt_lenb && buf != (char *) 0) {
2286 /* 4: two words for the lengths */
2287 /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
2288 * Otherwise we can't have processed more than WSIZE input bytes since
2289 * the last block flush, because compression would have been
2290 * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
2291 * transform a block into a stored block.
2292 */
2293 send_bits((STORED_BLOCK << 1) + eof, 3); /* send block type */
2294 compressed_len = (compressed_len + 3 + 7) & ~7L;
2295 compressed_len += (stored_len + 4) << 3;
2296
2297 copy_block(buf, (unsigned) stored_len, 1); /* with header */
2298
2299 } else if (static_lenb == opt_lenb) {
2300 send_bits((STATIC_TREES << 1) + eof, 3);
2301 compress_block((ct_data *) static_ltree,
2302 (ct_data *) static_dtree);
2303 compressed_len += 3 + static_len;
2304 } else {
2305 send_bits((DYN_TREES << 1) + eof, 3);
2306 send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1,
2307 max_blindex + 1);
2308 compress_block((ct_data *) dyn_ltree,
2309 (ct_data *) dyn_dtree);
2310 compressed_len += 3 + opt_len;
2311 }
2312 Assert(compressed_len == bits_sent, "bad compressed size");
2313 init_block();
2314
2315 if (eof) {
2316 bi_windup();
2317 compressed_len += 7; /* align on byte boundary */
2318 }
2319 Tracev((stderr, "\ncomprlen %lu(%lu) ", compressed_len >> 3,
2320 compressed_len - 7 * eof));
2321
2322 return compressed_len >> 3;
2323}
2324
2325/* ===========================================================================
2326 * Save the match info and tally the frequency counts. Return true if
2327 * the current block must be flushed.
2328 */
2329static int ct_tally(int dist, int lc)
2330{
2331 l_buf[last_lit++] = (uch) lc;
2332 if (dist == 0) {
2333 /* lc is the unmatched char */
2334 dyn_ltree[lc].Freq++;
2335 } else {
2336 /* Here, lc is the match length - MIN_MATCH */
2337 dist--; /* dist = match distance - 1 */
2338 Assert((ush) dist < (ush) MAX_DIST &&
2339 (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH) &&
2340 (ush) d_code(dist) < (ush) D_CODES, "ct_tally: bad match");
2341
2342 dyn_ltree[length_code[lc] + LITERALS + 1].Freq++;
2343 dyn_dtree[d_code(dist)].Freq++;
2344
2345 d_buf[last_dist++] = (ush) dist;
2346 flags |= flag_bit;
2347 }
2348 flag_bit <<= 1;
2349
2350 /* Output the flags if they fill a byte: */
2351 if ((last_lit & 7) == 0) {
2352 flag_buf[last_flags++] = flags;
2353 flags = 0, flag_bit = 1;
2354 }
2355 /* Try to guess if it is profitable to stop the current block here */
2356 if ((last_lit & 0xfff) == 0) {
2357 /* Compute an upper bound for the compressed length */
2358 ulg out_length = (ulg) last_lit * 8L;
2359 ulg in_length = (ulg) strstart - block_start;
2360 int dcode;
2361
2362 for (dcode = 0; dcode < D_CODES; dcode++) {
2363 out_length +=
2364 (ulg) dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]);
2365 }
2366 out_length >>= 3;
2367 Trace(
2368 (stderr,
2369 "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
2370 last_lit, last_dist, in_length, out_length,
2371 100L - out_length * 100L / in_length));
2372 if (last_dist < last_lit / 2 && out_length < in_length / 2)
2373 return 1;
2374 }
2375 return (last_lit == LIT_BUFSIZE - 1 || last_dist == DIST_BUFSIZE);
2376 /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
2377 * on 16 bit machines and because stored blocks are restricted to
2378 * 64K-1 bytes.
2379 */
2380}
2381
2382/* ===========================================================================
2383 * Send the block data compressed using the given Huffman trees
2384 */
2385static void compress_block(ct_data *ltree, ct_data *dtree)
2386{
2387 unsigned dist; /* distance of matched string */
2388 int lc; /* match length or unmatched char (if dist == 0) */
2389 unsigned lx = 0; /* running index in l_buf */
2390 unsigned dx = 0; /* running index in d_buf */
2391 unsigned fx = 0; /* running index in flag_buf */
2392 uch flag = 0; /* current flags */
2393 unsigned code; /* the code to send */
2394 int extra; /* number of extra bits to send */
2395
2396 if (last_lit != 0)
2397 do {
2398 if ((lx & 7) == 0)
2399 flag = flag_buf[fx++];
2400 lc = l_buf[lx++];
2401 if ((flag & 1) == 0) {
2402 send_code(lc, ltree); /* send a literal byte */
2403 Tracecv(isgraph(lc), (stderr, " '%c' ", lc));
2404 } else {
2405 /* Here, lc is the match length - MIN_MATCH */
2406 code = length_code[lc];
2407 send_code(code + LITERALS + 1, ltree); /* send the length code */
2408 extra = extra_lbits[code];
2409 if (extra != 0) {
2410 lc -= base_length[code];
2411 send_bits(lc, extra); /* send the extra length bits */
2412 }
2413 dist = d_buf[dx++];
2414 /* Here, dist is the match distance - 1 */
2415 code = d_code(dist);
2416 Assert(code < D_CODES, "bad d_code");
2417
2418 send_code(code, dtree); /* send the distance code */
2419 extra = extra_dbits[code];
2420 if (extra != 0) {
2421 dist -= base_dist[code];
2422 send_bits(dist, extra); /* send the extra distance bits */
2423 }
2424 } /* literal or match pair ? */
2425 flag >>= 1;
2426 } while (lx < last_lit);
2427
2428 send_code(END_BLOCK, ltree);
2429}
2430
2431/* ===========================================================================
2432 * Set the file type to ASCII or BINARY, using a crude approximation:
2433 * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
2434 * IN assertion: the fields freq of dyn_ltree are set and the total of all
2435 * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
2436 */
2437static void set_file_type()
2438{
2439 int n = 0;
2440 unsigned ascii_freq = 0;
2441 unsigned bin_freq = 0;
2442
2443 while (n < 7)
2444 bin_freq += dyn_ltree[n++].Freq;
2445 while (n < 128)
2446 ascii_freq += dyn_ltree[n++].Freq;
2447 while (n < LITERALS)
2448 bin_freq += dyn_ltree[n++].Freq;
2449 *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
2450 if (*file_type == BINARY && translate_eol) {
2451 error_msg("-l used on binary file");
2452 }
2453}
2454
2455/* zip.c -- compress files to the gzip or pkzip format
2456 * Copyright (C) 1992-1993 Jean-loup Gailly
2457 * This is free software; you can redistribute it and/or modify it under the
2458 * terms of the GNU General Public License, see the file COPYING.
2459 */
2460
2461
2462static ulg crc; /* crc on uncompressed file data */
2463static long header_bytes; /* number of bytes in gzip header */
2464
2465static void put_short_when_full(ush w)
2466{
2467 put_byte((uch)((w) & 0xff));
2468 put_byte((uch)((ush)(w) >> 8));
2469}
2470
2471static void put_short_function(ush n)
2472{
2473 put_short(n);
2474}
2475
2476static void put_long(ulg n)
2477{
2478 put_short_function((n) & 0xffff);
2479 put_short_function(((ulg)(n)) >> 16);
2480}
2481
2482/* put_header_byte is used for the compressed output
2483 * - for the initial 4 bytes that can't overflow the buffer.
2484 */
2485#define put_header_byte(c) {outbuf[outcnt++]=(uch)(c);}
2486
2487/* ===========================================================================
2488 * Deflate in to out.
2489 * IN assertions: the input and output buffers are cleared.
2490 * The variables time_stamp and save_orig_name are initialized.
2491 */
2492static int zip(int in, int out)
2493{
2494 uch my_flags = 0; /* general purpose bit flags */
2495 ush attr = 0; /* ascii/binary flag */
2496 ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
2497
2498 ifd = in;
2499 ofd = out;
2500 outcnt = 0;
2501
2502 /* Write the header to the gzip file. See algorithm.doc for the format */
2503
2504
2505 method = DEFLATED;
2506 put_header_byte(GZIP_MAGIC[0]); /* magic header */
2507 put_header_byte(GZIP_MAGIC[1]);
2508 put_header_byte(DEFLATED); /* compression method */
2509
2510 put_header_byte(my_flags); /* general flags */
2511 put_long(time_stamp);
2512
2513 /* Write deflated file to zip file */
2514 crc = updcrc(0, 0);
2515
2516 bi_init(out);
2517 ct_init(&attr, &method);
2518 lm_init(&deflate_flags);
2519
2520 put_byte((uch) deflate_flags); /* extra flags */
2521 put_byte(OS_CODE); /* OS identifier */
2522
2523 header_bytes = (long) outcnt;
2524
2525 (void) deflate();
2526
2527 /* Write the crc and uncompressed size */
2528 put_long(crc);
2529 put_long(isize);
2530 header_bytes += 2 * sizeof(long);
2531
2532 flush_outbuf();
2533 return OK;
2534}
2535
2536
2537/* ===========================================================================
2538 * Read a new buffer from the current input file, perform end-of-line
2539 * translation, and update the crc and input file size.
2540 * IN assertion: size >= 2 (for end-of-line translation)
2541 */
2542static int file_read(char *buf, unsigned size)
2543{
2544 unsigned len;
2545
2546 Assert(insize == 0, "inbuf not empty");
2547
2548 len = read(ifd, buf, size);
2549 if (len == (unsigned) (-1) || len == 0)
2550 return (int) len;
2551
2552 crc = updcrc((uch *) buf, len);
2553 isize += (ulg) len;
2554 return (int) len;
2555}
2556
2557/* ===========================================================================
2558 * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
2559 * (used for the compressed data only)
2560 */
2561static void flush_outbuf()
2562{
2563 if (outcnt == 0)
2564 return;
2565
2566 write_buf(ofd, (char *) outbuf, outcnt);
2567 outcnt = 0;
2568}
diff --git a/halt.c b/halt.c
deleted file mode 100644
index d66e28d0e..000000000
--- a/halt.c
+++ /dev/null
@@ -1,41 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini halt implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include "busybox.h"
25#include <signal.h>
26
27extern int halt_main(int argc, char **argv)
28{
29#ifdef BB_FEATURE_LINUXRC
30 /* don't assume init's pid == 1 */
31 pid_t *pid = find_pid_by_name("init");
32 if (!pid || *pid<=0) {
33 pid = find_pid_by_name("linuxrc");
34 if (!pid || *pid<=0)
35 error_msg_and_die("no process killed");
36 }
37 return(kill(*pid, SIGUSR1));
38#else
39 return(kill(1, SIGUSR1));
40#endif
41}
diff --git a/head.c b/head.c
deleted file mode 100644
index 688c250b1..000000000
--- a/head.c
+++ /dev/null
@@ -1,97 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini head implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by John Beppu <beppu@lineo.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <getopt.h>
27#include <stdlib.h>
28#include <string.h>
29#include "busybox.h"
30
31static int head(int len, FILE *fp)
32{
33 int i;
34 char *input;
35
36 for (i = 0; i < len; i++) {
37 if ((input = get_line_from_file(fp)) == NULL)
38 break;
39 fputs(input, stdout);
40 free(input);
41 }
42 return 0;
43}
44
45/* BusyBoxed head(1) */
46int head_main(int argc, char **argv)
47{
48 FILE *fp;
49 int need_headers, opt, len = 10, status = EXIT_SUCCESS;
50
51 /* parse argv[] */
52 while ((opt = getopt(argc, argv, "n:")) > 0) {
53 switch (opt) {
54 case 'n':
55 len = atoi(optarg);
56 if (len >= 1)
57 break;
58 /* fallthrough */
59 default:
60 show_usage();
61 }
62 }
63
64 /* get rest of argv[] or stdin if nothing's left */
65 if (argv[optind] == NULL) {
66 head(len, stdin);
67 return status;
68 }
69
70 need_headers = optind != (argc - 1);
71 while (argv[optind]) {
72 if (strcmp(argv[optind], "-") == 0) {
73 fp = stdin;
74 argv[optind] = "standard input";
75 } else {
76 if ((fp = wfopen(argv[optind], "r")) == NULL)
77 status = EXIT_FAILURE;
78 }
79 if (fp) {
80 if (need_headers) {
81 printf("==> %s <==\n", argv[optind]);
82 }
83 head(len, fp);
84 if (ferror(fp)) {
85 perror_msg("%s", argv[optind]);
86 status = EXIT_FAILURE;
87 }
88 if (optind < argc - 1)
89 putchar('\n');
90 if (fp != stdin)
91 fclose(fp);
92 }
93 optind++;
94 }
95
96 return status;
97}
diff --git a/hostid.c b/hostid.c
deleted file mode 100644
index 68a2cc659..000000000
--- a/hostid.c
+++ /dev/null
@@ -1,32 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini hostid implementation for busybox
4 *
5 * Copyright (C) 2000 Edward Betts <edward@debian.org>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include "busybox.h"
27
28extern int hostid_main(int argc, char **argv)
29{
30 printf("%lx\n", gethostid());
31 return EXIT_SUCCESS;
32}
diff --git a/hostname.c b/hostname.c
deleted file mode 100644
index d87851509..000000000
--- a/hostname.c
+++ /dev/null
@@ -1,128 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * $Id: hostname.c,v 1.30 2001/06/26 02:06:08 bug1 Exp $
4 * Mini hostname implementation for busybox
5 *
6 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
7 *
8 * adjusted by Erik Andersen <andersee@debian.org> to remove
9 * use of long options and GNU getopt. Improved the usage info.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#include <errno.h>
27#include <arpa/inet.h>
28#include <netdb.h>
29#include <unistd.h>
30#include <string.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include "busybox.h"
34
35static void do_sethostname(char *s, int isfile)
36{
37 FILE *f;
38 char buf[255];
39
40 if (!s)
41 return;
42 if (!isfile) {
43 if (sethostname(s, strlen(s)) < 0) {
44 if (errno == EPERM)
45 error_msg_and_die("you must be root to change the hostname");
46 else
47 perror_msg_and_die("sethostname");
48 }
49 } else {
50 f = xfopen(s, "r");
51 fgets(buf, 255, f);
52#ifdef BB_FEATURE_CLEAN_UP
53 fclose(f);
54#endif
55 chomp(buf);
56 do_sethostname(buf, 0);
57 }
58}
59
60int hostname_main(int argc, char **argv)
61{
62 int opt_short = 0;
63 int opt_domain = 0;
64 int opt_ip = 0;
65 struct hostent *h;
66 char *filename = NULL;
67 char buf[255];
68 char *s = NULL;
69
70 if (argc < 1)
71 show_usage();
72
73 while (--argc > 0 && **(++argv) == '-') {
74 while (*(++(*argv))) {
75 switch (**argv) {
76 case 's':
77 opt_short = 1;
78 break;
79 case 'i':
80 opt_ip = 1;
81 break;
82 case 'd':
83 opt_domain = 1;
84 break;
85 case 'F':
86 if (--argc == 0) {
87 show_usage();
88 }
89 filename = *(++argv);
90 break;
91 case '-':
92 if (strcmp(++(*argv), "file") || --argc ==0 ) {
93 show_usage();
94 }
95 filename = *(++argv);
96 break;
97 default:
98 show_usage();
99 }
100 if (filename != NULL)
101 break;
102 }
103 }
104
105 if (argc >= 1) {
106 do_sethostname(*argv, 0);
107 } else if (filename != NULL) {
108 do_sethostname(filename, 1);
109 } else {
110 gethostname(buf, 255);
111 if (opt_short) {
112 s = strchr(buf, '.');
113 if (!s)
114 s = buf;
115 *s = 0;
116 puts(buf);
117 } else if (opt_domain) {
118 s = strchr(buf, '.');
119 puts(s ? s + 1 : "");
120 } else if (opt_ip) {
121 h = xgethostbyname(buf);
122 puts(inet_ntoa(*(struct in_addr *) (h->h_addr)));
123 } else {
124 puts(buf);
125 }
126 }
127 return(0);
128}
diff --git a/hush.c b/hush.c
deleted file mode 100644
index cb0e6e980..000000000
--- a/hush.c
+++ /dev/null
@@ -1,2695 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * sh.c -- a prototype Bourne shell grammar parser
4 * Intended to follow the original Thompson and Ritchie
5 * "small and simple is beautiful" philosophy, which
6 * incidentally is a good match to today's BusyBox.
7 *
8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
9 *
10 * Credits:
11 * The parser routines proper are all original material, first
12 * written Dec 2000 and Jan 2001 by Larry Doolittle.
13 * The execution engine, the builtins, and much of the underlying
14 * support has been adapted from busybox-0.49pre's lash,
15 * which is Copyright (C) 2000 by Lineo, Inc., and
16 * written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
17 * That, in turn, is based in part on ladsh.c, by Michael K. Johnson and
18 * Erik W. Troan, which they placed in the public domain. I don't know
19 * how much of the Johnson/Troan code has survived the repeated rewrites.
20 * Other credits:
21 * simple_itoa() was lifted from boa-0.93.15
22 * b_addchr() derived from similar w_addchar function in glibc-2.2
23 * setup_redirect(), redirect_opt_num(), and big chunks of main()
24 * and many builtins derived from contributions by Erik Andersen
25 * miscellaneous bugfixes from Matt Kraai
26 *
27 * There are two big (and related) architecture differences between
28 * this parser and the lash parser. One is that this version is
29 * actually designed from the ground up to understand nearly all
30 * of the Bourne grammar. The second, consequential change is that
31 * the parser and input reader have been turned inside out. Now,
32 * the parser is in control, and asks for input as needed. The old
33 * way had the input reader in control, and it asked for parsing to
34 * take place as needed. The new way makes it much easier to properly
35 * handle the recursion implicit in the various substitutions, especially
36 * across continuation lines.
37 *
38 * Bash grammar not implemented: (how many of these were in original sh?)
39 * $@ (those sure look like weird quoting rules)
40 * $_
41 * ! negation operator for pipes
42 * &> and >& redirection of stdout+stderr
43 * Brace Expansion
44 * Tilde Expansion
45 * fancy forms of Parameter Expansion
46 * aliases
47 * Arithmetic Expansion
48 * <(list) and >(list) Process Substitution
49 * reserved words: case, esac, select, function
50 * Here Documents ( << word )
51 * Functions
52 * Major bugs:
53 * job handling woefully incomplete and buggy
54 * reserved word execution woefully incomplete and buggy
55 * to-do:
56 * port selected bugfixes from post-0.49 busybox lash - done?
57 * finish implementing reserved words: for, while, until, do, done
58 * change { and } from special chars to reserved words
59 * builtins: break, continue, eval, return, set, trap, ulimit
60 * test magic exec
61 * handle children going into background
62 * clean up recognition of null pipes
63 * check setting of global_argc and global_argv
64 * control-C handling, probably with longjmp
65 * follow IFS rules more precisely, including update semantics
66 * figure out what to do with backslash-newline
67 * explain why we use signal instead of sigaction
68 * propagate syntax errors, die on resource errors?
69 * continuation lines, both explicit and implicit - done?
70 * memory leak finding and plugging - done?
71 * more testing, especially quoting rules and redirection
72 * document how quoting rules not precisely followed for variable assignments
73 * maybe change map[] to use 2-bit entries
74 * (eventually) remove all the printf's
75 *
76 * This program is free software; you can redistribute it and/or modify
77 * it under the terms of the GNU General Public License as published by
78 * the Free Software Foundation; either version 2 of the License, or
79 * (at your option) any later version.
80 *
81 * This program is distributed in the hope that it will be useful,
82 * but WITHOUT ANY WARRANTY; without even the implied warranty of
83 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
84 * General Public License for more details.
85 *
86 * You should have received a copy of the GNU General Public License
87 * along with this program; if not, write to the Free Software
88 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
89 */
90#include <ctype.h> /* isalpha, isdigit */
91#include <unistd.h> /* getpid */
92#include <stdlib.h> /* getenv, atoi */
93#include <string.h> /* strchr */
94#include <stdio.h> /* popen etc. */
95#include <glob.h> /* glob, of course */
96#include <stdarg.h> /* va_list */
97#include <errno.h>
98#include <fcntl.h>
99#include <getopt.h> /* should be pretty obvious */
100
101#include <sys/stat.h> /* ulimit */
102#include <sys/types.h>
103#include <sys/wait.h>
104#include <signal.h>
105
106/* #include <dmalloc.h> */
107/* #define DEBUG_SHELL */
108
109#ifdef BB_VER
110#include "busybox.h"
111#include "cmdedit.h"
112#else
113#define applet_name "hush"
114#include "standalone.h"
115#define hush_main main
116#undef BB_FEATURE_SH_FANCY_PROMPT
117#endif
118
119typedef enum {
120 REDIRECT_INPUT = 1,
121 REDIRECT_OVERWRITE = 2,
122 REDIRECT_APPEND = 3,
123 REDIRECT_HEREIS = 4,
124 REDIRECT_IO = 5
125} redir_type;
126
127/* The descrip member of this structure is only used to make debugging
128 * output pretty */
129struct {int mode; int default_fd; char *descrip;} redir_table[] = {
130 { 0, 0, "()" },
131 { O_RDONLY, 0, "<" },
132 { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
133 { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
134 { O_RDONLY, -1, "<<" },
135 { O_RDWR, 1, "<>" }
136};
137
138typedef enum {
139 PIPE_SEQ = 1,
140 PIPE_AND = 2,
141 PIPE_OR = 3,
142 PIPE_BG = 4,
143} pipe_style;
144
145/* might eventually control execution */
146typedef enum {
147 RES_NONE = 0,
148 RES_IF = 1,
149 RES_THEN = 2,
150 RES_ELIF = 3,
151 RES_ELSE = 4,
152 RES_FI = 5,
153 RES_FOR = 6,
154 RES_WHILE = 7,
155 RES_UNTIL = 8,
156 RES_DO = 9,
157 RES_DONE = 10,
158 RES_XXXX = 11,
159 RES_SNTX = 12
160} reserved_style;
161#define FLAG_END (1<<RES_NONE)
162#define FLAG_IF (1<<RES_IF)
163#define FLAG_THEN (1<<RES_THEN)
164#define FLAG_ELIF (1<<RES_ELIF)
165#define FLAG_ELSE (1<<RES_ELSE)
166#define FLAG_FI (1<<RES_FI)
167#define FLAG_FOR (1<<RES_FOR)
168#define FLAG_WHILE (1<<RES_WHILE)
169#define FLAG_UNTIL (1<<RES_UNTIL)
170#define FLAG_DO (1<<RES_DO)
171#define FLAG_DONE (1<<RES_DONE)
172#define FLAG_START (1<<RES_XXXX)
173
174/* This holds pointers to the various results of parsing */
175struct p_context {
176 struct child_prog *child;
177 struct pipe *list_head;
178 struct pipe *pipe;
179 struct redir_struct *pending_redirect;
180 reserved_style w;
181 int old_flag; /* for figuring out valid reserved words */
182 struct p_context *stack;
183 /* How about quoting status? */
184};
185
186struct redir_struct {
187 redir_type type; /* type of redirection */
188 int fd; /* file descriptor being redirected */
189 int dup; /* -1, or file descriptor being duplicated */
190 struct redir_struct *next; /* pointer to the next redirect in the list */
191 glob_t word; /* *word.gl_pathv is the filename */
192};
193
194struct child_prog {
195 pid_t pid; /* 0 if exited */
196 char **argv; /* program name and arguments */
197 struct pipe *group; /* if non-NULL, first in group or subshell */
198 int subshell; /* flag, non-zero if group must be forked */
199 struct redir_struct *redirects; /* I/O redirections */
200 glob_t glob_result; /* result of parameter globbing */
201 int is_stopped; /* is the program currently running? */
202 struct pipe *family; /* pointer back to the child's parent pipe */
203};
204
205struct pipe {
206 int jobid; /* job number */
207 int num_progs; /* total number of programs in job */
208 int running_progs; /* number of programs running */
209 char *text; /* name of job */
210 char *cmdbuf; /* buffer various argv's point into */
211 pid_t pgrp; /* process group ID for the job */
212 struct child_prog *progs; /* array of commands in pipe */
213 struct pipe *next; /* to track background commands */
214 int stopped_progs; /* number of programs alive, but stopped */
215 int job_context; /* bitmask defining current context */
216 pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
217 reserved_style r_mode; /* supports if, for, while, until */
218};
219
220struct close_me {
221 int fd;
222 struct close_me *next;
223};
224
225struct variables {
226 char *name;
227 char *value;
228 int flg_export;
229 int flg_read_only;
230 struct variables *next;
231};
232
233/* globals, connect us to the outside world
234 * the first three support $?, $#, and $1 */
235char **global_argv;
236unsigned int global_argc;
237unsigned int last_return_code;
238extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
239
240/* "globals" within this file */
241static char *ifs;
242static char map[256];
243static int fake_mode;
244static int interactive;
245static struct close_me *close_me_head;
246static const char *cwd;
247static struct pipe *job_list;
248static unsigned int last_bg_pid;
249static unsigned int last_jobid;
250static unsigned int shell_terminal;
251static char *PS1;
252static char *PS2;
253struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
254struct variables *top_vars = &shell_ver;
255
256
257#define B_CHUNK (100)
258#define B_NOSPAC 1
259
260typedef struct {
261 char *data;
262 int length;
263 int maxlen;
264 int quote;
265 int nonnull;
266} o_string;
267#define NULL_O_STRING {NULL,0,0,0,0}
268/* used for initialization:
269 o_string foo = NULL_O_STRING; */
270
271/* I can almost use ordinary FILE *. Is open_memstream() universally
272 * available? Where is it documented? */
273struct in_str {
274 const char *p;
275 char peek_buf[2];
276 int __promptme;
277 int promptmode;
278 FILE *file;
279 int (*get) (struct in_str *);
280 int (*peek) (struct in_str *);
281};
282#define b_getch(input) ((input)->get(input))
283#define b_peek(input) ((input)->peek(input))
284
285#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
286
287struct built_in_command {
288 char *cmd; /* name */
289 char *descr; /* description */
290 int (*function) (struct child_prog *); /* function ptr */
291};
292
293/* belongs in busybox.h */
294static inline int max(int a, int b) {
295 return (a>b)?a:b;
296}
297
298/* This should be in utility.c */
299#ifdef DEBUG_SHELL
300static void debug_printf(const char *format, ...)
301{
302 va_list args;
303 va_start(args, format);
304 vfprintf(stderr, format, args);
305 va_end(args);
306}
307#else
308static inline void debug_printf(const char *format, ...) { }
309#endif
310#define final_printf debug_printf
311
312static void __syntax(char *file, int line) {
313 error_msg("syntax error %s:%d", file, line);
314}
315#define syntax() __syntax(__FILE__, __LINE__)
316
317/* Index of subroutines: */
318/* function prototypes for builtins */
319static int builtin_cd(struct child_prog *child);
320static int builtin_env(struct child_prog *child);
321static int builtin_exec(struct child_prog *child);
322static int builtin_exit(struct child_prog *child);
323static int builtin_export(struct child_prog *child);
324static int builtin_fg_bg(struct child_prog *child);
325static int builtin_help(struct child_prog *child);
326static int builtin_jobs(struct child_prog *child);
327static int builtin_pwd(struct child_prog *child);
328static int builtin_read(struct child_prog *child);
329static int builtin_set(struct child_prog *child);
330static int builtin_shift(struct child_prog *child);
331static int builtin_source(struct child_prog *child);
332static int builtin_umask(struct child_prog *child);
333static int builtin_unset(struct child_prog *child);
334static int builtin_not_written(struct child_prog *child);
335/* o_string manipulation: */
336static int b_check_space(o_string *o, int len);
337static int b_addchr(o_string *o, int ch);
338static void b_reset(o_string *o);
339static int b_addqchr(o_string *o, int ch, int quote);
340static int b_adduint(o_string *o, unsigned int i);
341/* in_str manipulations: */
342static int static_get(struct in_str *i);
343static int static_peek(struct in_str *i);
344static int file_get(struct in_str *i);
345static int file_peek(struct in_str *i);
346static void setup_file_in_str(struct in_str *i, FILE *f);
347static void setup_string_in_str(struct in_str *i, const char *s);
348/* close_me manipulations: */
349static void mark_open(int fd);
350static void mark_closed(int fd);
351static void close_all();
352/* "run" the final data structures: */
353static char *indenter(int i);
354static int free_pipe_list(struct pipe *head, int indent);
355static int free_pipe(struct pipe *pi, int indent);
356/* really run the final data structures: */
357static int setup_redirects(struct child_prog *prog, int squirrel[]);
358static int run_list_real(struct pipe *pi);
359static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn));
360static int run_pipe_real(struct pipe *pi);
361/* extended glob support: */
362static int globhack(const char *src, int flags, glob_t *pglob);
363static int glob_needed(const char *s);
364static int xglob(o_string *dest, int flags, glob_t *pglob);
365/* variable assignment: */
366static int is_assignment(const char *s);
367/* data structure manipulation: */
368static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
369static void initialize_context(struct p_context *ctx);
370static int done_word(o_string *dest, struct p_context *ctx);
371static int done_command(struct p_context *ctx);
372static int done_pipe(struct p_context *ctx, pipe_style type);
373/* primary string parsing: */
374static int redirect_dup_num(struct in_str *input);
375static int redirect_opt_num(o_string *o);
376static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
377static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
378static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src);
379static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
380static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
381static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
382/* setup: */
383static int parse_stream_outer(struct in_str *inp);
384static int parse_string_outer(const char *s);
385static int parse_file_outer(FILE *f);
386/* job management: */
387static int checkjobs(struct pipe* fg_pipe);
388static void insert_bg_job(struct pipe *pi);
389static void remove_bg_job(struct pipe *pi);
390/* local variable support */
391static char *get_local_var(const char *var);
392static void unset_local_var(const char *name);
393static int set_local_var(const char *s, int flg_export);
394
395/* Table of built-in functions. They can be forked or not, depending on
396 * context: within pipes, they fork. As simple commands, they do not.
397 * When used in non-forking context, they can change global variables
398 * in the parent shell process. If forked, of course they can not.
399 * For example, 'unset foo | whatever' will parse and run, but foo will
400 * still be set at the end. */
401static struct built_in_command bltins[] = {
402 {"bg", "Resume a job in the background", builtin_fg_bg},
403 {"break", "Exit for, while or until loop", builtin_not_written},
404 {"cd", "Change working directory", builtin_cd},
405 {"continue", "Continue for, while or until loop", builtin_not_written},
406 {"env", "Print all environment variables", builtin_env},
407 {"eval", "Construct and run shell command", builtin_not_written},
408 {"exec", "Exec command, replacing this shell with the exec'd process",
409 builtin_exec},
410 {"exit", "Exit from shell()", builtin_exit},
411 {"export", "Set environment variable", builtin_export},
412 {"fg", "Bring job into the foreground", builtin_fg_bg},
413 {"jobs", "Lists the active jobs", builtin_jobs},
414 {"pwd", "Print current directory", builtin_pwd},
415 {"read", "Input environment variable", builtin_read},
416 {"return", "Return from a function", builtin_not_written},
417 {"set", "Set/unset shell local variables", builtin_set},
418 {"shift", "Shift positional parameters", builtin_shift},
419 {"trap", "Trap signals", builtin_not_written},
420 {"ulimit","Controls resource limits", builtin_not_written},
421 {"umask","Sets file creation mask", builtin_umask},
422 {"unset", "Unset environment variable", builtin_unset},
423 {".", "Source-in and run commands in a file", builtin_source},
424 {"help", "List shell built-in commands", builtin_help},
425 {NULL, NULL, NULL}
426};
427
428static const char *set_cwd(void)
429{
430 if(cwd==unknown)
431 cwd = NULL; /* xgetcwd(arg) called free(arg) */
432 cwd = xgetcwd((char *)cwd);
433 if (!cwd)
434 cwd = unknown;
435 return cwd;
436}
437
438
439/* built-in 'cd <path>' handler */
440static int builtin_cd(struct child_prog *child)
441{
442 char *newdir;
443 if (child->argv[1] == NULL)
444 newdir = getenv("HOME");
445 else
446 newdir = child->argv[1];
447 if (chdir(newdir)) {
448 printf("cd: %s: %s\n", newdir, strerror(errno));
449 return EXIT_FAILURE;
450 }
451 set_cwd();
452 return EXIT_SUCCESS;
453}
454
455/* built-in 'env' handler */
456static int builtin_env(struct child_prog *dummy)
457{
458 char **e = environ;
459 if (e == NULL) return EXIT_FAILURE;
460 for (; *e; e++) {
461 puts(*e);
462 }
463 return EXIT_SUCCESS;
464}
465
466/* built-in 'exec' handler */
467static int builtin_exec(struct child_prog *child)
468{
469 if (child->argv[1] == NULL)
470 return EXIT_SUCCESS; /* Really? */
471 child->argv++;
472 pseudo_exec(child);
473 /* never returns */
474}
475
476/* built-in 'exit' handler */
477static int builtin_exit(struct child_prog *child)
478{
479 if (child->argv[1] == NULL)
480 exit(last_return_code);
481 exit (atoi(child->argv[1]));
482}
483
484/* built-in 'export VAR=value' handler */
485static int builtin_export(struct child_prog *child)
486{
487 int res = 0;
488 char *name = child->argv[1];
489
490 if (name == NULL) {
491 return (builtin_env(child));
492 }
493
494 name = strdup(name);
495
496 if(name) {
497 char *value = strchr(name, '=');
498
499 if (!value) {
500 char *tmp;
501 /* They are exporting something without an =VALUE */
502
503 value = get_local_var(name);
504 if (value) {
505 size_t ln = strlen(name);
506
507 tmp = realloc(name, ln+strlen(value)+2);
508 if(tmp==NULL)
509 res = -1;
510 else {
511 sprintf(tmp+ln, "=%s", value);
512 name = tmp;
513 }
514 } else {
515 /* bash does not return an error when trying to export
516 * an undefined variable. Do likewise. */
517 res = 1;
518 }
519 }
520 }
521 if (res<0)
522 perror_msg("export");
523 else if(res==0)
524 res = set_local_var(name, 1);
525 else
526 res = 0;
527 free(name);
528 return res;
529}
530
531/* built-in 'fg' and 'bg' handler */
532static int builtin_fg_bg(struct child_prog *child)
533{
534 int i, jobnum;
535 struct pipe *pi=NULL;
536
537 if (!interactive)
538 return EXIT_FAILURE;
539 /* If they gave us no args, assume they want the last backgrounded task */
540 if (!child->argv[1]) {
541 for (pi = job_list; pi; pi = pi->next) {
542 if (pi->jobid == last_jobid) {
543 break;
544 }
545 }
546 if (!pi) {
547 error_msg("%s: no current job", child->argv[0]);
548 return EXIT_FAILURE;
549 }
550 } else {
551 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
552 error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
553 return EXIT_FAILURE;
554 }
555 for (pi = job_list; pi; pi = pi->next) {
556 if (pi->jobid == jobnum) {
557 break;
558 }
559 }
560 if (!pi) {
561 error_msg("%s: %d: no such job", child->argv[0], jobnum);
562 return EXIT_FAILURE;
563 }
564 }
565
566 if (*child->argv[0] == 'f') {
567 /* Put the job into the foreground. */
568 tcsetpgrp(shell_terminal, pi->pgrp);
569 }
570
571 /* Restart the processes in the job */
572 for (i = 0; i < pi->num_progs; i++)
573 pi->progs[i].is_stopped = 0;
574
575 if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) {
576 if (i == ESRCH) {
577 remove_bg_job(pi);
578 } else {
579 perror_msg("kill (SIGCONT)");
580 }
581 }
582
583 pi->stopped_progs = 0;
584 return EXIT_SUCCESS;
585}
586
587/* built-in 'help' handler */
588static int builtin_help(struct child_prog *dummy)
589{
590 struct built_in_command *x;
591
592 printf("\nBuilt-in commands:\n");
593 printf("-------------------\n");
594 for (x = bltins; x->cmd; x++) {
595 if (x->descr==NULL)
596 continue;
597 printf("%s\t%s\n", x->cmd, x->descr);
598 }
599 printf("\n\n");
600 return EXIT_SUCCESS;
601}
602
603/* built-in 'jobs' handler */
604static int builtin_jobs(struct child_prog *child)
605{
606 struct pipe *job;
607 char *status_string;
608
609 for (job = job_list; job; job = job->next) {
610 if (job->running_progs == job->stopped_progs)
611 status_string = "Stopped";
612 else
613 status_string = "Running";
614
615 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
616 }
617 return EXIT_SUCCESS;
618}
619
620
621/* built-in 'pwd' handler */
622static int builtin_pwd(struct child_prog *dummy)
623{
624 puts(set_cwd());
625 return EXIT_SUCCESS;
626}
627
628/* built-in 'read VAR' handler */
629static int builtin_read(struct child_prog *child)
630{
631 int res;
632
633 if (child->argv[1]) {
634 char string[BUFSIZ];
635 char *var = 0;
636
637 string[0] = 0; /* In case stdin has only EOF */
638 /* read string */
639 fgets(string, sizeof(string), stdin);
640 chomp(string);
641 var = malloc(strlen(child->argv[1])+strlen(string)+2);
642 if(var) {
643 sprintf(var, "%s=%s", child->argv[1], string);
644 res = set_local_var(var, 0);
645 } else
646 res = -1;
647 if (res)
648 fprintf(stderr, "read: %m\n");
649 free(var); /* So not move up to avoid breaking errno */
650 return res;
651 } else {
652 do res=getchar(); while(res!='\n' && res!=EOF);
653 return 0;
654 }
655}
656
657/* built-in 'set VAR=value' handler */
658static int builtin_set(struct child_prog *child)
659{
660 char *temp = child->argv[1];
661 struct variables *e;
662
663 if (temp == NULL)
664 for(e = top_vars; e; e=e->next)
665 printf("%s=%s\n", e->name, e->value);
666 else
667 set_local_var(temp, 0);
668
669 return EXIT_SUCCESS;
670}
671
672
673/* Built-in 'shift' handler */
674static int builtin_shift(struct child_prog *child)
675{
676 int n=1;
677 if (child->argv[1]) {
678 n=atoi(child->argv[1]);
679 }
680 if (n>=0 && n<global_argc) {
681 /* XXX This probably breaks $0 */
682 global_argc -= n;
683 global_argv += n;
684 return EXIT_SUCCESS;
685 } else {
686 return EXIT_FAILURE;
687 }
688}
689
690/* Built-in '.' handler (read-in and execute commands from file) */
691static int builtin_source(struct child_prog *child)
692{
693 FILE *input;
694 int status;
695
696 if (child->argv[1] == NULL)
697 return EXIT_FAILURE;
698
699 /* XXX search through $PATH is missing */
700 input = fopen(child->argv[1], "r");
701 if (!input) {
702 error_msg("Couldn't open file '%s'", child->argv[1]);
703 return EXIT_FAILURE;
704 }
705
706 /* Now run the file */
707 /* XXX argv and argc are broken; need to save old global_argv
708 * (pointer only is OK!) on this stack frame,
709 * set global_argv=child->argv+1, recurse, and restore. */
710 mark_open(fileno(input));
711 status = parse_file_outer(input);
712 mark_closed(fileno(input));
713 fclose(input);
714 return (status);
715}
716
717static int builtin_umask(struct child_prog *child)
718{
719 mode_t new_umask;
720 const char *arg = child->argv[1];
721 char *end;
722 if (arg) {
723 new_umask=strtoul(arg, &end, 8);
724 if (*end!='\0' || end == arg) {
725 return EXIT_FAILURE;
726 }
727 } else {
728 printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
729 }
730 umask(new_umask);
731 return EXIT_SUCCESS;
732}
733
734/* built-in 'unset VAR' handler */
735static int builtin_unset(struct child_prog *child)
736{
737 /* bash returned already true */
738 unset_local_var(child->argv[1]);
739 return EXIT_SUCCESS;
740}
741
742static int builtin_not_written(struct child_prog *child)
743{
744 printf("builtin_%s not written\n",child->argv[0]);
745 return EXIT_FAILURE;
746}
747
748static int b_check_space(o_string *o, int len)
749{
750 /* It would be easy to drop a more restrictive policy
751 * in here, such as setting a maximum string length */
752 if (o->length + len > o->maxlen) {
753 char *old_data = o->data;
754 /* assert (data == NULL || o->maxlen != 0); */
755 o->maxlen += max(2*len, B_CHUNK);
756 o->data = realloc(o->data, 1 + o->maxlen);
757 if (o->data == NULL) {
758 free(old_data);
759 }
760 }
761 return o->data == NULL;
762}
763
764static int b_addchr(o_string *o, int ch)
765{
766 debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
767 if (b_check_space(o, 1)) return B_NOSPAC;
768 o->data[o->length] = ch;
769 o->length++;
770 o->data[o->length] = '\0';
771 return 0;
772}
773
774static void b_reset(o_string *o)
775{
776 o->length = 0;
777 o->nonnull = 0;
778 if (o->data != NULL) *o->data = '\0';
779}
780
781static void b_free(o_string *o)
782{
783 b_reset(o);
784 if (o->data != NULL) free(o->data);
785 o->data = NULL;
786 o->maxlen = 0;
787}
788
789/* My analysis of quoting semantics tells me that state information
790 * is associated with a destination, not a source.
791 */
792static int b_addqchr(o_string *o, int ch, int quote)
793{
794 if (quote && strchr("*?[\\",ch)) {
795 int rc;
796 rc = b_addchr(o, '\\');
797 if (rc) return rc;
798 }
799 return b_addchr(o, ch);
800}
801
802/* belongs in utility.c */
803char *simple_itoa(unsigned int i)
804{
805 /* 21 digits plus null terminator, good for 64-bit or smaller ints */
806 static char local[22];
807 char *p = &local[21];
808 *p-- = '\0';
809 do {
810 *p-- = '0' + i % 10;
811 i /= 10;
812 } while (i > 0);
813 return p + 1;
814}
815
816static int b_adduint(o_string *o, unsigned int i)
817{
818 int r;
819 char *p = simple_itoa(i);
820 /* no escape checking necessary */
821 do r=b_addchr(o, *p++); while (r==0 && *p);
822 return r;
823}
824
825static int static_get(struct in_str *i)
826{
827 int ch=*i->p++;
828 if (ch=='\0') return EOF;
829 return ch;
830}
831
832static int static_peek(struct in_str *i)
833{
834 return *i->p;
835}
836
837static inline void cmdedit_set_initial_prompt(void)
838{
839#ifndef BB_FEATURE_SH_FANCY_PROMPT
840 PS1 = NULL;
841#else
842 PS1 = getenv("PS1");
843 if(PS1==0)
844 PS1 = "\\w \\$ ";
845#endif
846}
847
848static inline void setup_prompt_string(int promptmode, char **prompt_str)
849{
850 debug_printf("setup_prompt_string %d ",promptmode);
851#ifndef BB_FEATURE_SH_FANCY_PROMPT
852 /* Set up the prompt */
853 if (promptmode == 1) {
854 if (PS1)
855 free(PS1);
856 PS1=xmalloc(strlen(cwd)+4);
857 sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# ");
858 *prompt_str = PS1;
859 } else {
860 *prompt_str = PS2;
861 }
862#else
863 *prompt_str = (promptmode==1)? PS1 : PS2;
864#endif
865 debug_printf("result %s\n",*prompt_str);
866}
867
868static void get_user_input(struct in_str *i)
869{
870 char *prompt_str;
871 static char the_command[BUFSIZ];
872
873 setup_prompt_string(i->promptmode, &prompt_str);
874#ifdef BB_FEATURE_COMMAND_EDITING
875 /*
876 ** enable command line editing only while a command line
877 ** is actually being read; otherwise, we'll end up bequeathing
878 ** atexit() handlers and other unwanted stuff to our
879 ** child processes (rob@sysgo.de)
880 */
881 cmdedit_read_input(prompt_str, the_command);
882#else
883 fputs(prompt_str, stdout);
884 fflush(stdout);
885 the_command[0]=fgetc(i->file);
886 the_command[1]='\0';
887#endif
888 fflush(stdout);
889 i->p = the_command;
890}
891
892/* This is the magic location that prints prompts
893 * and gets data back from the user */
894static int file_get(struct in_str *i)
895{
896 int ch;
897
898 ch = 0;
899 /* If there is data waiting, eat it up */
900 if (i->p && *i->p) {
901 ch=*i->p++;
902 } else {
903 /* need to double check i->file because we might be doing something
904 * more complicated by now, like sourcing or substituting. */
905 if (i->__promptme && interactive && i->file == stdin) {
906 while(! i->p || (interactive && strlen(i->p)==0) ) {
907 get_user_input(i);
908 }
909 i->promptmode=2;
910 i->__promptme = 0;
911 if (i->p && *i->p) {
912 ch=*i->p++;
913 }
914 } else {
915 ch = fgetc(i->file);
916 }
917
918 debug_printf("b_getch: got a %d\n", ch);
919 }
920 if (ch == '\n') i->__promptme=1;
921 return ch;
922}
923
924/* All the callers guarantee this routine will never be
925 * used right after a newline, so prompting is not needed.
926 */
927static int file_peek(struct in_str *i)
928{
929 if (i->p && *i->p) {
930 return *i->p;
931 } else {
932 i->peek_buf[0] = fgetc(i->file);
933 i->peek_buf[1] = '\0';
934 i->p = i->peek_buf;
935 debug_printf("b_peek: got a %d\n", *i->p);
936 return *i->p;
937 }
938}
939
940static void setup_file_in_str(struct in_str *i, FILE *f)
941{
942 i->peek = file_peek;
943 i->get = file_get;
944 i->__promptme=1;
945 i->promptmode=1;
946 i->file = f;
947 i->p = NULL;
948}
949
950static void setup_string_in_str(struct in_str *i, const char *s)
951{
952 i->peek = static_peek;
953 i->get = static_get;
954 i->__promptme=1;
955 i->promptmode=1;
956 i->p = s;
957}
958
959static void mark_open(int fd)
960{
961 struct close_me *new = xmalloc(sizeof(struct close_me));
962 new->fd = fd;
963 new->next = close_me_head;
964 close_me_head = new;
965}
966
967static void mark_closed(int fd)
968{
969 struct close_me *tmp;
970 if (close_me_head == NULL || close_me_head->fd != fd)
971 error_msg_and_die("corrupt close_me");
972 tmp = close_me_head;
973 close_me_head = close_me_head->next;
974 free(tmp);
975}
976
977static void close_all()
978{
979 struct close_me *c;
980 for (c=close_me_head; c; c=c->next) {
981 close(c->fd);
982 }
983 close_me_head = NULL;
984}
985
986/* squirrel != NULL means we squirrel away copies of stdin, stdout,
987 * and stderr if they are redirected. */
988static int setup_redirects(struct child_prog *prog, int squirrel[])
989{
990 int openfd, mode;
991 struct redir_struct *redir;
992
993 for (redir=prog->redirects; redir; redir=redir->next) {
994 if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
995 /* something went wrong in the parse. Pretend it didn't happen */
996 continue;
997 }
998 if (redir->dup == -1) {
999 mode=redir_table[redir->type].mode;
1000 openfd = open(redir->word.gl_pathv[0], mode, 0666);
1001 if (openfd < 0) {
1002 /* this could get lost if stderr has been redirected, but
1003 bash and ash both lose it as well (though zsh doesn't!) */
1004 perror_msg("error opening %s", redir->word.gl_pathv[0]);
1005 return 1;
1006 }
1007 } else {
1008 openfd = redir->dup;
1009 }
1010
1011 if (openfd != redir->fd) {
1012 if (squirrel && redir->fd < 3) {
1013 squirrel[redir->fd] = dup(redir->fd);
1014 }
1015 if (openfd == -3) {
1016 close(openfd);
1017 } else {
1018 dup2(openfd, redir->fd);
1019 if (redir->dup == -1)
1020 close (openfd);
1021 }
1022 }
1023 }
1024 return 0;
1025}
1026
1027static void restore_redirects(int squirrel[])
1028{
1029 int i, fd;
1030 for (i=0; i<3; i++) {
1031 fd = squirrel[i];
1032 if (fd != -1) {
1033 /* No error checking. I sure wouldn't know what
1034 * to do with an error if I found one! */
1035 dup2(fd, i);
1036 close(fd);
1037 }
1038 }
1039}
1040
1041/* never returns */
1042/* XXX no exit() here. If you don't exec, use _exit instead.
1043 * The at_exit handlers apparently confuse the calling process,
1044 * in particular stdin handling. Not sure why? */
1045static void pseudo_exec(struct child_prog *child)
1046{
1047 int i, rcode;
1048 struct built_in_command *x;
1049 if (child->argv) {
1050 for (i=0; is_assignment(child->argv[i]); i++) {
1051 debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
1052 putenv(strdup(child->argv[i]));
1053 }
1054 child->argv+=i; /* XXX this hack isn't so horrible, since we are about
1055 to exit, and therefore don't need to keep data
1056 structures consistent for free() use. */
1057 /* If a variable is assigned in a forest, and nobody listens,
1058 * was it ever really set?
1059 */
1060 if (child->argv[0] == NULL) {
1061 _exit(EXIT_SUCCESS);
1062 }
1063
1064 /*
1065 * Check if the command matches any of the builtins.
1066 * Depending on context, this might be redundant. But it's
1067 * easier to waste a few CPU cycles than it is to figure out
1068 * if this is one of those cases.
1069 */
1070 for (x = bltins; x->cmd; x++) {
1071 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1072 debug_printf("builtin exec %s\n", child->argv[0]);
1073 rcode = x->function(child);
1074 fflush(stdout);
1075 _exit(rcode);
1076 }
1077 }
1078
1079 /* Check if the command matches any busybox internal commands
1080 * ("applets") here.
1081 * FIXME: This feature is not 100% safe, since
1082 * BusyBox is not fully reentrant, so we have no guarantee the things
1083 * from the .bss are still zeroed, or that things from .data are still
1084 * at their defaults. We could exec ourself from /proc/self/exe, but I
1085 * really dislike relying on /proc for things. We could exec ourself
1086 * from global_argv[0], but if we are in a chroot, we may not be able
1087 * to find ourself... */
1088#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1089 {
1090 int argc_l;
1091 char** argv_l=child->argv;
1092 char *name = child->argv[0];
1093
1094#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
1095 /* Following discussions from November 2000 on the busybox mailing
1096 * list, the default configuration, (without
1097 * get_last_path_component()) lets the user force use of an
1098 * external command by specifying the full (with slashes) filename.
1099 * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets
1100 * _aways_ override external commands, so if you want to run
1101 * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the
1102 * filesystem and is _not_ busybox. Some systems may want this,
1103 * most do not. */
1104 name = get_last_path_component(name);
1105#endif
1106 /* Count argc for use in a second... */
1107 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
1108 optind = 1;
1109 debug_printf("running applet %s\n", name);
1110 run_applet_by_name(name, argc_l, child->argv);
1111 }
1112#endif
1113 debug_printf("exec of %s\n",child->argv[0]);
1114 execvp(child->argv[0],child->argv);
1115 perror_msg("couldn't exec: %s",child->argv[0]);
1116 _exit(1);
1117 } else if (child->group) {
1118 debug_printf("runtime nesting to group\n");
1119 interactive=0; /* crucial!!!! */
1120 rcode = run_list_real(child->group);
1121 /* OK to leak memory by not calling free_pipe_list,
1122 * since this process is about to exit */
1123 _exit(rcode);
1124 } else {
1125 /* Can happen. See what bash does with ">foo" by itself. */
1126 debug_printf("trying to pseudo_exec null command\n");
1127 _exit(EXIT_SUCCESS);
1128 }
1129}
1130
1131static void insert_bg_job(struct pipe *pi)
1132{
1133 struct pipe *thejob;
1134
1135 /* Linear search for the ID of the job to use */
1136 pi->jobid = 1;
1137 for (thejob = job_list; thejob; thejob = thejob->next)
1138 if (thejob->jobid >= pi->jobid)
1139 pi->jobid = thejob->jobid + 1;
1140
1141 /* add thejob to the list of running jobs */
1142 if (!job_list) {
1143 thejob = job_list = xmalloc(sizeof(*thejob));
1144 } else {
1145 for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
1146 thejob->next = xmalloc(sizeof(*thejob));
1147 thejob = thejob->next;
1148 }
1149
1150 /* physically copy the struct job */
1151 memcpy(thejob, pi, sizeof(struct pipe));
1152 thejob->next = NULL;
1153 thejob->running_progs = thejob->num_progs;
1154 thejob->stopped_progs = 0;
1155 thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
1156
1157 //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0])
1158 {
1159 char *bar=thejob->text;
1160 char **foo=pi->progs[0].argv;
1161 while(foo && *foo) {
1162 bar += sprintf(bar, "%s ", *foo++);
1163 }
1164 }
1165
1166 /* we don't wait for background thejobs to return -- append it
1167 to the list of backgrounded thejobs and leave it alone */
1168 printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
1169 last_bg_pid = thejob->progs[0].pid;
1170 last_jobid = thejob->jobid;
1171}
1172
1173/* remove a backgrounded job */
1174static void remove_bg_job(struct pipe *pi)
1175{
1176 struct pipe *prev_pipe;
1177
1178 if (pi == job_list) {
1179 job_list = pi->next;
1180 } else {
1181 prev_pipe = job_list;
1182 while (prev_pipe->next != pi)
1183 prev_pipe = prev_pipe->next;
1184 prev_pipe->next = pi->next;
1185 }
1186 if (job_list)
1187 last_jobid = job_list->jobid;
1188 else
1189 last_jobid = 0;
1190
1191 pi->stopped_progs = 0;
1192 free_pipe(pi, 0);
1193 free(pi);
1194}
1195
1196/* Checks to see if any processes have exited -- if they
1197 have, figure out why and see if a job has completed */
1198static int checkjobs(struct pipe* fg_pipe)
1199{
1200 int attributes;
1201 int status;
1202 int prognum = 0;
1203 struct pipe *pi;
1204 pid_t childpid;
1205
1206 attributes = WUNTRACED;
1207 if (fg_pipe==NULL) {
1208 attributes |= WNOHANG;
1209 }
1210
1211 while ((childpid = waitpid(-1, &status, attributes)) > 0) {
1212 if (fg_pipe) {
1213 int i, rcode = 0;
1214 for (i=0; i < fg_pipe->num_progs; i++) {
1215 if (fg_pipe->progs[i].pid == childpid) {
1216 if (i==fg_pipe->num_progs-1)
1217 rcode=WEXITSTATUS(status);
1218 (fg_pipe->num_progs)--;
1219 return(rcode);
1220 }
1221 }
1222 }
1223
1224 for (pi = job_list; pi; pi = pi->next) {
1225 prognum = 0;
1226 while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
1227 prognum++;
1228 }
1229 if (prognum < pi->num_progs)
1230 break;
1231 }
1232
1233 if(pi==NULL) {
1234 debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
1235 continue;
1236 }
1237
1238 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1239 /* child exited */
1240 pi->running_progs--;
1241 pi->progs[prognum].pid = 0;
1242
1243 if (!pi->running_progs) {
1244 printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
1245 remove_bg_job(pi);
1246 }
1247 } else {
1248 /* child stopped */
1249 pi->stopped_progs++;
1250 pi->progs[prognum].is_stopped = 1;
1251
1252#if 0
1253 /* Printing this stuff is a pain, since it tends to
1254 * overwrite the prompt an inconveinient moments. So
1255 * don't do that. */
1256 if (pi->stopped_progs == pi->num_progs) {
1257 printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
1258 }
1259#endif
1260 }
1261 }
1262
1263 if (childpid == -1 && errno != ECHILD)
1264 perror_msg("waitpid");
1265
1266 /* move the shell to the foreground */
1267 //if (interactive && tcsetpgrp(shell_terminal, getpgid(0)))
1268 // perror_msg("tcsetpgrp-2");
1269 return -1;
1270}
1271
1272/* Figure out our controlling tty, checking in order stderr,
1273 * stdin, and stdout. If check_pgrp is set, also check that
1274 * we belong to the foreground process group associated with
1275 * that tty. The value of shell_terminal is needed in order to call
1276 * tcsetpgrp(shell_terminal, ...); */
1277void controlling_tty(int check_pgrp)
1278{
1279 pid_t curpgrp;
1280
1281 if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0
1282 && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0
1283 && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0)
1284 goto shell_terminal_error;
1285
1286 if (check_pgrp && curpgrp != getpgid(0))
1287 goto shell_terminal_error;
1288
1289 return;
1290
1291shell_terminal_error:
1292 shell_terminal = -1;
1293 return;
1294}
1295
1296/* run_pipe_real() starts all the jobs, but doesn't wait for anything
1297 * to finish. See checkjobs().
1298 *
1299 * return code is normally -1, when the caller has to wait for children
1300 * to finish to determine the exit status of the pipe. If the pipe
1301 * is a simple builtin command, however, the action is done by the
1302 * time run_pipe_real returns, and the exit code is provided as the
1303 * return value.
1304 *
1305 * The input of the pipe is always stdin, the output is always
1306 * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
1307 * because it tries to avoid running the command substitution in
1308 * subshell, when that is in fact necessary. The subshell process
1309 * now has its stdout directed to the input of the appropriate pipe,
1310 * so this routine is noticeably simpler.
1311 */
1312static int run_pipe_real(struct pipe *pi)
1313{
1314 int i;
1315 int nextin, nextout;
1316 int pipefds[2]; /* pipefds[0] is for reading */
1317 struct child_prog *child;
1318 struct built_in_command *x;
1319
1320 nextin = 0;
1321 pi->pgrp = -1;
1322
1323 /* Check if this is a simple builtin (not part of a pipe).
1324 * Builtins within pipes have to fork anyway, and are handled in
1325 * pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
1326 */
1327 if (pi->num_progs == 1) child = & (pi->progs[0]);
1328 if (pi->num_progs == 1 && child->group && child->subshell == 0) {
1329 int squirrel[] = {-1, -1, -1};
1330 int rcode;
1331 debug_printf("non-subshell grouping\n");
1332 setup_redirects(child, squirrel);
1333 /* XXX could we merge code with following builtin case,
1334 * by creating a pseudo builtin that calls run_list_real? */
1335 rcode = run_list_real(child->group);
1336 restore_redirects(squirrel);
1337 return rcode;
1338 } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
1339 for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
1340 if (i!=0 && child->argv[i]==NULL) {
1341 /* assignments, but no command: set the local environment */
1342 for (i=0; child->argv[i]!=NULL; i++) {
1343
1344 /* Ok, this case is tricky. We have to decide if this is a
1345 * local variable, or an already exported variable. If it is
1346 * already exported, we have to export the new value. If it is
1347 * not exported, we need only set this as a local variable.
1348 * This junk is all to decide whether or not to export this
1349 * variable. */
1350 int export_me=0;
1351 char *name, *value;
1352 name = xstrdup(child->argv[i]);
1353 debug_printf("Local environment set: %s\n", name);
1354 value = strchr(name, '=');
1355 if (value)
1356 *value=0;
1357 if ( get_local_var(name)) {
1358 export_me=1;
1359 }
1360 free(name);
1361 set_local_var(child->argv[i], export_me);
1362 }
1363 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
1364 }
1365 for (x = bltins; x->cmd; x++) {
1366 if (strcmp(child->argv[i], x->cmd) == 0 ) {
1367 int squirrel[] = {-1, -1, -1};
1368 int rcode;
1369 if (x->function == builtin_exec && child->argv[i+1]==NULL) {
1370 debug_printf("magic exec\n");
1371 setup_redirects(child,NULL);
1372 return EXIT_SUCCESS;
1373 }
1374 debug_printf("builtin inline %s\n", child->argv[0]);
1375 /* XXX setup_redirects acts on file descriptors, not FILEs.
1376 * This is perfect for work that comes after exec().
1377 * Is it really safe for inline use? Experimentally,
1378 * things seem to work with glibc. */
1379 setup_redirects(child, squirrel);
1380 for (i=0; is_assignment(child->argv[i]); i++) {
1381 putenv(strdup(child->argv[i]));
1382 }
1383 child->argv+=i; /* XXX horrible hack */
1384 rcode = x->function(child);
1385 child->argv-=i; /* XXX restore hack so free() can work right */
1386 restore_redirects(squirrel);
1387 return rcode;
1388 }
1389 }
1390 }
1391
1392 for (i = 0; i < pi->num_progs; i++) {
1393 child = & (pi->progs[i]);
1394
1395 /* pipes are inserted between pairs of commands */
1396 if ((i + 1) < pi->num_progs) {
1397 if (pipe(pipefds)<0) perror_msg_and_die("pipe");
1398 nextout = pipefds[1];
1399 } else {
1400 nextout=1;
1401 pipefds[0] = -1;
1402 }
1403
1404 /* XXX test for failed fork()? */
1405 if (!(child->pid = fork())) {
1406 /* Set the handling for job control signals back to the default. */
1407 signal(SIGINT, SIG_DFL);
1408 signal(SIGQUIT, SIG_DFL);
1409 signal(SIGTERM, SIG_DFL);
1410 signal(SIGTSTP, SIG_DFL);
1411 signal(SIGTTIN, SIG_DFL);
1412 signal(SIGTTOU, SIG_DFL);
1413 signal(SIGCHLD, SIG_DFL);
1414
1415 close_all();
1416
1417 if (nextin != 0) {
1418 dup2(nextin, 0);
1419 close(nextin);
1420 }
1421 if (nextout != 1) {
1422 dup2(nextout, 1);
1423 close(nextout);
1424 }
1425 if (pipefds[0]!=-1) {
1426 close(pipefds[0]); /* opposite end of our output pipe */
1427 }
1428
1429 /* Like bash, explicit redirects override pipes,
1430 * and the pipe fd is available for dup'ing. */
1431 setup_redirects(child,NULL);
1432
1433 if (interactive && pi->followup!=PIPE_BG) {
1434 /* If we (the child) win the race, put ourselves in the process
1435 * group whose leader is the first process in this pipe. */
1436 if (pi->pgrp < 0) {
1437 pi->pgrp = getpid();
1438 }
1439 if (setpgid(0, pi->pgrp) == 0) {
1440 tcsetpgrp(2, pi->pgrp);
1441 }
1442 }
1443
1444 pseudo_exec(child);
1445 }
1446
1447
1448 /* put our child in the process group whose leader is the
1449 first process in this pipe */
1450 if (pi->pgrp < 0) {
1451 pi->pgrp = child->pid;
1452 }
1453 /* Don't check for errors. The child may be dead already,
1454 * in which case setpgid returns error code EACCES. */
1455 setpgid(child->pid, pi->pgrp);
1456
1457 if (nextin != 0)
1458 close(nextin);
1459 if (nextout != 1)
1460 close(nextout);
1461
1462 /* If there isn't another process, nextin is garbage
1463 but it doesn't matter */
1464 nextin = pipefds[0];
1465 }
1466 return -1;
1467}
1468
1469static int run_list_real(struct pipe *pi)
1470{
1471 int rcode=0;
1472 int if_code=0, next_if_code=0; /* need double-buffer to handle elif */
1473 reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
1474 for (;pi;pi=pi->next) {
1475 rmode = pi->r_mode;
1476 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);
1477 if (rmode == skip_more_in_this_rmode) continue;
1478 skip_more_in_this_rmode = RES_XXXX;
1479 if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
1480 if (rmode == RES_THEN && if_code) continue;
1481 if (rmode == RES_ELSE && !if_code) continue;
1482 if (rmode == RES_ELIF && !if_code) continue;
1483 if (pi->num_progs == 0) continue;
1484 rcode = run_pipe_real(pi);
1485 debug_printf("run_pipe_real returned %d\n",rcode);
1486 if (rcode!=-1) {
1487 /* We only ran a builtin: rcode was set by the return value
1488 * of run_pipe_real(), and we don't need to wait for anything. */
1489 } else if (pi->followup==PIPE_BG) {
1490 /* XXX check bash's behavior with nontrivial pipes */
1491 /* XXX compute jobid */
1492 /* XXX what does bash do with attempts to background builtins? */
1493 insert_bg_job(pi);
1494 rcode = EXIT_SUCCESS;
1495 } else {
1496 if (interactive) {
1497 /* move the new process group into the foreground */
1498 if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
1499 perror_msg("tcsetpgrp-3");
1500 rcode = checkjobs(pi);
1501 /* move the shell to the foreground */
1502 if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY)
1503 perror_msg("tcsetpgrp-4");
1504 } else {
1505 rcode = checkjobs(pi);
1506 }
1507 debug_printf("checkjobs returned %d\n",rcode);
1508 }
1509 last_return_code=rcode;
1510 if ( rmode == RES_IF || rmode == RES_ELIF )
1511 next_if_code=rcode; /* can be overwritten a number of times */
1512 if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
1513 (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
1514 skip_more_in_this_rmode=rmode;
1515 checkjobs(NULL);
1516 }
1517 return rcode;
1518}
1519
1520/* broken, of course, but OK for testing */
1521static char *indenter(int i)
1522{
1523 static char blanks[]=" ";
1524 return &blanks[sizeof(blanks)-i-1];
1525}
1526
1527/* return code is the exit status of the pipe */
1528static int free_pipe(struct pipe *pi, int indent)
1529{
1530 char **p;
1531 struct child_prog *child;
1532 struct redir_struct *r, *rnext;
1533 int a, i, ret_code=0;
1534 char *ind = indenter(indent);
1535
1536 if (pi->stopped_progs > 0)
1537 return ret_code;
1538 final_printf("%s run pipe: (pid %d)\n",ind,getpid());
1539 for (i=0; i<pi->num_progs; i++) {
1540 child = &pi->progs[i];
1541 final_printf("%s command %d:\n",ind,i);
1542 if (child->argv) {
1543 for (a=0,p=child->argv; *p; a++,p++) {
1544 final_printf("%s argv[%d] = %s\n",ind,a,*p);
1545 }
1546 globfree(&child->glob_result);
1547 child->argv=NULL;
1548 } else if (child->group) {
1549 final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);
1550 ret_code = free_pipe_list(child->group,indent+3);
1551 final_printf("%s end group\n",ind);
1552 } else {
1553 final_printf("%s (nil)\n",ind);
1554 }
1555 for (r=child->redirects; r; r=rnext) {
1556 final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip);
1557 if (r->dup == -1) {
1558 /* guard against the case >$FOO, where foo is unset or blank */
1559 if (r->word.gl_pathv) {
1560 final_printf(" %s\n", *r->word.gl_pathv);
1561 globfree(&r->word);
1562 }
1563 } else {
1564 final_printf("&%d\n", r->dup);
1565 }
1566 rnext=r->next;
1567 free(r);
1568 }
1569 child->redirects=NULL;
1570 }
1571 free(pi->progs); /* children are an array, they get freed all at once */
1572 pi->progs=NULL;
1573 return ret_code;
1574}
1575
1576static int free_pipe_list(struct pipe *head, int indent)
1577{
1578 int rcode=0; /* if list has no members */
1579 struct pipe *pi, *next;
1580 char *ind = indenter(indent);
1581 for (pi=head; pi; pi=next) {
1582 final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
1583 rcode = free_pipe(pi, indent);
1584 final_printf("%s pipe followup code %d\n", ind, pi->followup);
1585 next=pi->next;
1586 pi->next=NULL;
1587 free(pi);
1588 }
1589 return rcode;
1590}
1591
1592/* Select which version we will use */
1593static int run_list(struct pipe *pi)
1594{
1595 int rcode=0;
1596 if (fake_mode==0) {
1597 rcode = run_list_real(pi);
1598 }
1599 /* free_pipe_list has the side effect of clearing memory
1600 * In the long run that function can be merged with run_list_real,
1601 * but doing that now would hobble the debugging effort. */
1602 free_pipe_list(pi,0);
1603 return rcode;
1604}
1605
1606/* The API for glob is arguably broken. This routine pushes a non-matching
1607 * string into the output structure, removing non-backslashed backslashes.
1608 * If someone can prove me wrong, by performing this function within the
1609 * original glob(3) api, feel free to rewrite this routine into oblivion.
1610 * Return code (0 vs. GLOB_NOSPACE) matches glob(3).
1611 * XXX broken if the last character is '\\', check that before calling.
1612 */
1613static int globhack(const char *src, int flags, glob_t *pglob)
1614{
1615 int cnt=0, pathc;
1616 const char *s;
1617 char *dest;
1618 for (cnt=1, s=src; s && *s; s++) {
1619 if (*s == '\\') s++;
1620 cnt++;
1621 }
1622 dest = malloc(cnt);
1623 if (!dest) return GLOB_NOSPACE;
1624 if (!(flags & GLOB_APPEND)) {
1625 pglob->gl_pathv=NULL;
1626 pglob->gl_pathc=0;
1627 pglob->gl_offs=0;
1628 pglob->gl_offs=0;
1629 }
1630 pathc = ++pglob->gl_pathc;
1631 pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
1632 if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
1633 pglob->gl_pathv[pathc-1]=dest;
1634 pglob->gl_pathv[pathc]=NULL;
1635 for (s=src; s && *s; s++, dest++) {
1636 if (*s == '\\') s++;
1637 *dest = *s;
1638 }
1639 *dest='\0';
1640 return 0;
1641}
1642
1643/* XXX broken if the last character is '\\', check that before calling */
1644static int glob_needed(const char *s)
1645{
1646 for (; *s; s++) {
1647 if (*s == '\\') s++;
1648 if (strchr("*[?",*s)) return 1;
1649 }
1650 return 0;
1651}
1652
1653#if 0
1654static void globprint(glob_t *pglob)
1655{
1656 int i;
1657 debug_printf("glob_t at %p:\n", pglob);
1658 debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n",
1659 pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);
1660 for (i=0; i<pglob->gl_pathc; i++)
1661 debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,
1662 pglob->gl_pathv[i], pglob->gl_pathv[i]);
1663}
1664#endif
1665
1666static int xglob(o_string *dest, int flags, glob_t *pglob)
1667{
1668 int gr;
1669
1670 /* short-circuit for null word */
1671 /* we can code this better when the debug_printf's are gone */
1672 if (dest->length == 0) {
1673 if (dest->nonnull) {
1674 /* bash man page calls this an "explicit" null */
1675 gr = globhack(dest->data, flags, pglob);
1676 debug_printf("globhack returned %d\n",gr);
1677 } else {
1678 return 0;
1679 }
1680 } else if (glob_needed(dest->data)) {
1681 gr = glob(dest->data, flags, NULL, pglob);
1682 debug_printf("glob returned %d\n",gr);
1683 if (gr == GLOB_NOMATCH) {
1684 /* quote removal, or more accurately, backslash removal */
1685 gr = globhack(dest->data, flags, pglob);
1686 debug_printf("globhack returned %d\n",gr);
1687 }
1688 } else {
1689 gr = globhack(dest->data, flags, pglob);
1690 debug_printf("globhack returned %d\n",gr);
1691 }
1692 if (gr == GLOB_NOSPACE)
1693 error_msg_and_die("out of memory during glob");
1694 if (gr != 0) { /* GLOB_ABORTED ? */
1695 error_msg("glob(3) error %d",gr);
1696 }
1697 /* globprint(glob_target); */
1698 return gr;
1699}
1700
1701/* This is used to get/check local shell variables */
1702static char *get_local_var(const char *s)
1703{
1704 struct variables *cur;
1705
1706 if (!s)
1707 return NULL;
1708 for (cur = top_vars; cur; cur=cur->next)
1709 if(strcmp(cur->name, s)==0)
1710 return cur->value;
1711 return NULL;
1712}
1713
1714/* This is used to set local shell variables
1715 flg_export==0 if only local (not exporting) variable
1716 flg_export==1 if "new" exporting environ
1717 flg_export>1 if current startup environ (not call putenv()) */
1718static int set_local_var(const char *s, int flg_export)
1719{
1720 char *name, *value;
1721 int result=0;
1722 struct variables *cur;
1723
1724 name=strdup(s);
1725
1726 /* Assume when we enter this function that we are already in
1727 * NAME=VALUE format. So the first order of business is to
1728 * split 's' on the '=' into 'name' and 'value' */
1729 value = strchr(name, '=');
1730 if (value==0 && ++value==0) {
1731 free(name);
1732 return -1;
1733 }
1734 *value++ = 0;
1735
1736 for(cur = top_vars; cur; cur = cur->next) {
1737 if(strcmp(cur->name, name)==0)
1738 break;
1739 }
1740
1741 if(cur) {
1742 if(strcmp(cur->value, value)==0) {
1743 if(flg_export>0 && cur->flg_export==0)
1744 cur->flg_export=flg_export;
1745 else
1746 result++;
1747 } else {
1748 if(cur->flg_read_only) {
1749 error_msg("%s: readonly variable", name);
1750 result = -1;
1751 } else {
1752 if(flg_export>0 || cur->flg_export>1)
1753 cur->flg_export=1;
1754 free(cur->value);
1755
1756 cur->value = strdup(value);
1757 }
1758 }
1759 } else {
1760 cur = malloc(sizeof(struct variables));
1761 if(!cur) {
1762 result = -1;
1763 } else {
1764 cur->name = strdup(name);
1765 if(cur->name == 0) {
1766 free(cur);
1767 result = -1;
1768 } else {
1769 struct variables *bottom = top_vars;
1770 cur->value = strdup(value);
1771 cur->next = 0;
1772 cur->flg_export = flg_export;
1773 cur->flg_read_only = 0;
1774 while(bottom->next) bottom=bottom->next;
1775 bottom->next = cur;
1776 }
1777 }
1778 }
1779
1780 if(result==0 && cur->flg_export==1) {
1781 *(value-1) = '=';
1782 result = putenv(name);
1783 } else {
1784 free(name);
1785 if(result>0) /* equivalent to previous set */
1786 result = 0;
1787 }
1788 return result;
1789}
1790
1791static void unset_local_var(const char *name)
1792{
1793 struct variables *cur;
1794
1795 if (name) {
1796 for (cur = top_vars; cur; cur=cur->next) {
1797 if(strcmp(cur->name, name)==0)
1798 break;
1799 }
1800 if(cur!=0) {
1801 struct variables *next = top_vars;
1802 if(cur->flg_read_only) {
1803 error_msg("%s: readonly variable", name);
1804 return;
1805 } else {
1806 if(cur->flg_export)
1807 unsetenv(cur->name);
1808 free(cur->name);
1809 free(cur->value);
1810 while (next->next != cur)
1811 next = next->next;
1812 next->next = cur->next;
1813 }
1814 free(cur);
1815 }
1816 }
1817}
1818
1819static int is_assignment(const char *s)
1820{
1821 if (s==NULL || !isalpha(*s)) return 0;
1822 ++s;
1823 while(isalnum(*s) || *s=='_') ++s;
1824 return *s=='=';
1825}
1826
1827/* the src parameter allows us to peek forward to a possible &n syntax
1828 * for file descriptor duplication, e.g., "2>&1".
1829 * Return code is 0 normally, 1 if a syntax error is detected in src.
1830 * Resource errors (in xmalloc) cause the process to exit */
1831static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
1832 struct in_str *input)
1833{
1834 struct child_prog *child=ctx->child;
1835 struct redir_struct *redir = child->redirects;
1836 struct redir_struct *last_redir=NULL;
1837
1838 /* Create a new redir_struct and drop it onto the end of the linked list */
1839 while(redir) {
1840 last_redir=redir;
1841 redir=redir->next;
1842 }
1843 redir = xmalloc(sizeof(struct redir_struct));
1844 redir->next=NULL;
1845 redir->word.gl_pathv=NULL;
1846 if (last_redir) {
1847 last_redir->next=redir;
1848 } else {
1849 child->redirects=redir;
1850 }
1851
1852 redir->type=style;
1853 redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
1854
1855 debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
1856
1857 /* Check for a '2>&1' type redirect */
1858 redir->dup = redirect_dup_num(input);
1859 if (redir->dup == -2) return 1; /* syntax error */
1860 if (redir->dup != -1) {
1861 /* Erik had a check here that the file descriptor in question
1862 * is legit; I postpone that to "run time"
1863 * A "-" representation of "close me" shows up as a -3 here */
1864 debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
1865 } else {
1866 /* We do _not_ try to open the file that src points to,
1867 * since we need to return and let src be expanded first.
1868 * Set ctx->pending_redirect, so we know what to do at the
1869 * end of the next parsed word.
1870 */
1871 ctx->pending_redirect = redir;
1872 }
1873 return 0;
1874}
1875
1876struct pipe *new_pipe(void) {
1877 struct pipe *pi;
1878 pi = xmalloc(sizeof(struct pipe));
1879 pi->num_progs = 0;
1880 pi->progs = NULL;
1881 pi->next = NULL;
1882 pi->followup = 0; /* invalid */
1883 return pi;
1884}
1885
1886static void initialize_context(struct p_context *ctx)
1887{
1888 ctx->pipe=NULL;
1889 ctx->pending_redirect=NULL;
1890 ctx->child=NULL;
1891 ctx->list_head=new_pipe();
1892 ctx->pipe=ctx->list_head;
1893 ctx->w=RES_NONE;
1894 ctx->stack=NULL;
1895 done_command(ctx); /* creates the memory for working child */
1896}
1897
1898/* normal return is 0
1899 * if a reserved word is found, and processed, return 1
1900 * should handle if, then, elif, else, fi, for, while, until, do, done.
1901 * case, function, and select are obnoxious, save those for later.
1902 */
1903int reserved_word(o_string *dest, struct p_context *ctx)
1904{
1905 struct reserved_combo {
1906 char *literal;
1907 int code;
1908 long flag;
1909 };
1910 /* Mostly a list of accepted follow-up reserved words.
1911 * FLAG_END means we are done with the sequence, and are ready
1912 * to turn the compound list into a command.
1913 * FLAG_START means the word must start a new compound list.
1914 */
1915 static struct reserved_combo reserved_list[] = {
1916 { "if", RES_IF, FLAG_THEN | FLAG_START },
1917 { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI },
1918 { "elif", RES_ELIF, FLAG_THEN },
1919 { "else", RES_ELSE, FLAG_FI },
1920 { "fi", RES_FI, FLAG_END },
1921 { "for", RES_FOR, FLAG_DO | FLAG_START },
1922 { "while", RES_WHILE, FLAG_DO | FLAG_START },
1923 { "until", RES_UNTIL, FLAG_DO | FLAG_START },
1924 { "do", RES_DO, FLAG_DONE },
1925 { "done", RES_DONE, FLAG_END }
1926 };
1927 struct reserved_combo *r;
1928 for (r=reserved_list;
1929#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo)
1930 r<reserved_list+NRES; r++) {
1931 if (strcmp(dest->data, r->literal) == 0) {
1932 debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
1933 if (r->flag & FLAG_START) {
1934 struct p_context *new = xmalloc(sizeof(struct p_context));
1935 debug_printf("push stack\n");
1936 *new = *ctx; /* physical copy */
1937 initialize_context(ctx);
1938 ctx->stack=new;
1939 } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
1940 syntax();
1941 ctx->w = RES_SNTX;
1942 b_reset (dest);
1943 return 1;
1944 }
1945 ctx->w=r->code;
1946 ctx->old_flag = r->flag;
1947 if (ctx->old_flag & FLAG_END) {
1948 struct p_context *old;
1949 debug_printf("pop stack\n");
1950 old = ctx->stack;
1951 old->child->group = ctx->list_head;
1952 old->child->subshell = 0;
1953 *ctx = *old; /* physical copy */
1954 free(old);
1955 }
1956 b_reset (dest);
1957 return 1;
1958 }
1959 }
1960 return 0;
1961}
1962
1963/* normal return is 0.
1964 * Syntax or xglob errors return 1. */
1965static int done_word(o_string *dest, struct p_context *ctx)
1966{
1967 struct child_prog *child=ctx->child;
1968 glob_t *glob_target;
1969 int gr, flags = 0;
1970
1971 debug_printf("done_word: %s %p\n", dest->data, child);
1972 if (dest->length == 0 && !dest->nonnull) {
1973 debug_printf(" true null, ignored\n");
1974 return 0;
1975 }
1976 if (ctx->pending_redirect) {
1977 glob_target = &ctx->pending_redirect->word;
1978 } else {
1979 if (child->group) {
1980 syntax();
1981 return 1; /* syntax error, groups and arglists don't mix */
1982 }
1983 if (!child->argv) {
1984 debug_printf("checking %s for reserved-ness\n",dest->data);
1985 if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
1986 }
1987 glob_target = &child->glob_result;
1988 if (child->argv) flags |= GLOB_APPEND;
1989 }
1990 gr = xglob(dest, flags, glob_target);
1991 if (gr != 0) return 1;
1992
1993 b_reset(dest);
1994 if (ctx->pending_redirect) {
1995 ctx->pending_redirect=NULL;
1996 if (glob_target->gl_pathc != 1) {
1997 error_msg("ambiguous redirect");
1998 return 1;
1999 }
2000 } else {
2001 child->argv = glob_target->gl_pathv;
2002 }
2003 return 0;
2004}
2005
2006/* The only possible error here is out of memory, in which case
2007 * xmalloc exits. */
2008static int done_command(struct p_context *ctx)
2009{
2010 /* The child is really already in the pipe structure, so
2011 * advance the pipe counter and make a new, null child.
2012 * Only real trickiness here is that the uncommitted
2013 * child structure, to which ctx->child points, is not
2014 * counted in pi->num_progs. */
2015 struct pipe *pi=ctx->pipe;
2016 struct child_prog *prog=ctx->child;
2017
2018 if (prog && prog->group == NULL
2019 && prog->argv == NULL
2020 && prog->redirects == NULL) {
2021 debug_printf("done_command: skipping null command\n");
2022 return 0;
2023 } else if (prog) {
2024 pi->num_progs++;
2025 debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
2026 } else {
2027 debug_printf("done_command: initializing\n");
2028 }
2029 pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
2030
2031 prog = pi->progs + pi->num_progs;
2032 prog->redirects = NULL;
2033 prog->argv = NULL;
2034 prog->is_stopped = 0;
2035 prog->group = NULL;
2036 prog->glob_result.gl_pathv = NULL;
2037 prog->family = pi;
2038
2039 ctx->child=prog;
2040 /* but ctx->pipe and ctx->list_head remain unchanged */
2041 return 0;
2042}
2043
2044static int done_pipe(struct p_context *ctx, pipe_style type)
2045{
2046 struct pipe *new_p;
2047 done_command(ctx); /* implicit closure of previous command */
2048 debug_printf("done_pipe, type %d\n", type);
2049 ctx->pipe->followup = type;
2050 ctx->pipe->r_mode = ctx->w;
2051 new_p=new_pipe();
2052 ctx->pipe->next = new_p;
2053 ctx->pipe = new_p;
2054 ctx->child = NULL;
2055 done_command(ctx); /* set up new pipe to accept commands */
2056 return 0;
2057}
2058
2059/* peek ahead in the in_str to find out if we have a "&n" construct,
2060 * as in "2>&1", that represents duplicating a file descriptor.
2061 * returns either -2 (syntax error), -1 (no &), or the number found.
2062 */
2063static int redirect_dup_num(struct in_str *input)
2064{
2065 int ch, d=0, ok=0;
2066 ch = b_peek(input);
2067 if (ch != '&') return -1;
2068
2069 b_getch(input); /* get the & */
2070 ch=b_peek(input);
2071 if (ch == '-') {
2072 b_getch(input);
2073 return -3; /* "-" represents "close me" */
2074 }
2075 while (isdigit(ch)) {
2076 d = d*10+(ch-'0');
2077 ok=1;
2078 b_getch(input);
2079 ch = b_peek(input);
2080 }
2081 if (ok) return d;
2082
2083 error_msg("ambiguous redirect");
2084 return -2;
2085}
2086
2087/* If a redirect is immediately preceded by a number, that number is
2088 * supposed to tell which file descriptor to redirect. This routine
2089 * looks for such preceding numbers. In an ideal world this routine
2090 * needs to handle all the following classes of redirects...
2091 * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo
2092 * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo
2093 * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo
2094 * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo
2095 * A -1 output from this program means no valid number was found, so the
2096 * caller should use the appropriate default for this redirection.
2097 */
2098static int redirect_opt_num(o_string *o)
2099{
2100 int num;
2101
2102 if (o->length==0) return -1;
2103 for(num=0; num<o->length; num++) {
2104 if (!isdigit(*(o->data+num))) {
2105 return -1;
2106 }
2107 }
2108 /* reuse num (and save an int) */
2109 num=atoi(o->data);
2110 b_reset(o);
2111 return num;
2112}
2113
2114FILE *generate_stream_from_list(struct pipe *head)
2115{
2116 FILE *pf;
2117#if 1
2118 int pid, channel[2];
2119 if (pipe(channel)<0) perror_msg_and_die("pipe");
2120 pid=fork();
2121 if (pid<0) {
2122 perror_msg_and_die("fork");
2123 } else if (pid==0) {
2124 close(channel[0]);
2125 if (channel[1] != 1) {
2126 dup2(channel[1],1);
2127 close(channel[1]);
2128 }
2129#if 0
2130#define SURROGATE "surrogate response"
2131 write(1,SURROGATE,sizeof(SURROGATE));
2132 _exit(run_list(head));
2133#else
2134 _exit(run_list_real(head)); /* leaks memory */
2135#endif
2136 }
2137 debug_printf("forked child %d\n",pid);
2138 close(channel[1]);
2139 pf = fdopen(channel[0],"r");
2140 debug_printf("pipe on FILE *%p\n",pf);
2141#else
2142 free_pipe_list(head,0);
2143 pf=popen("echo surrogate response","r");
2144 debug_printf("started fake pipe on FILE *%p\n",pf);
2145#endif
2146 return pf;
2147}
2148
2149/* this version hacked for testing purposes */
2150/* return code is exit status of the process that is run. */
2151static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end)
2152{
2153 int retcode;
2154 o_string result=NULL_O_STRING;
2155 struct p_context inner;
2156 FILE *p;
2157 struct in_str pipe_str;
2158 initialize_context(&inner);
2159
2160 /* recursion to generate command */
2161 retcode = parse_stream(&result, &inner, input, subst_end);
2162 if (retcode != 0) return retcode; /* syntax error or EOF */
2163 done_word(&result, &inner);
2164 done_pipe(&inner, PIPE_SEQ);
2165 b_free(&result);
2166
2167 p=generate_stream_from_list(inner.list_head);
2168 if (p==NULL) return 1;
2169 mark_open(fileno(p));
2170 setup_file_in_str(&pipe_str, p);
2171
2172 /* now send results of command back into original context */
2173 retcode = parse_stream(dest, ctx, &pipe_str, '\0');
2174 /* XXX In case of a syntax error, should we try to kill the child?
2175 * That would be tough to do right, so just read until EOF. */
2176 if (retcode == 1) {
2177 while (b_getch(&pipe_str)!=EOF) { /* discard */ };
2178 }
2179
2180 debug_printf("done reading from pipe, pclose()ing\n");
2181 /* This is the step that wait()s for the child. Should be pretty
2182 * safe, since we just read an EOF from its stdout. We could try
2183 * to better, by using wait(), and keeping track of background jobs
2184 * at the same time. That would be a lot of work, and contrary
2185 * to the KISS philosophy of this program. */
2186 mark_closed(fileno(p));
2187 retcode=pclose(p);
2188 free_pipe_list(inner.list_head,0);
2189 debug_printf("pclosed, retcode=%d\n",retcode);
2190 /* XXX this process fails to trim a single trailing newline */
2191 return retcode;
2192}
2193
2194static int parse_group(o_string *dest, struct p_context *ctx,
2195 struct in_str *input, int ch)
2196{
2197 int rcode, endch=0;
2198 struct p_context sub;
2199 struct child_prog *child = ctx->child;
2200 if (child->argv) {
2201 syntax();
2202 return 1; /* syntax error, groups and arglists don't mix */
2203 }
2204 initialize_context(&sub);
2205 switch(ch) {
2206 case '(': endch=')'; child->subshell=1; break;
2207 case '{': endch='}'; break;
2208 default: syntax(); /* really logic error */
2209 }
2210 rcode=parse_stream(dest,&sub,input,endch);
2211 done_word(dest,&sub); /* finish off the final word in the subcontext */
2212 done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */
2213 child->group = sub.list_head;
2214 return rcode;
2215 /* child remains "open", available for possible redirects */
2216}
2217
2218/* basically useful version until someone wants to get fancier,
2219 * see the bash man page under "Parameter Expansion" */
2220static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src)
2221{
2222 const char *p=NULL;
2223 if (src->data) {
2224 p = getenv(src->data);
2225 if (!p)
2226 p = get_local_var(src->data);
2227 }
2228 if (p) parse_string(dest, ctx, p); /* recursion */
2229 b_free(src);
2230}
2231
2232/* return code: 0 for OK, 1 for syntax error */
2233static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
2234{
2235 int i, advance=0;
2236 o_string alt=NULL_O_STRING;
2237 char sep[]=" ";
2238 int ch = input->peek(input); /* first character after the $ */
2239 debug_printf("handle_dollar: ch=%c\n",ch);
2240 if (isalpha(ch)) {
2241 while(ch=b_peek(input),isalnum(ch) || ch=='_') {
2242 b_getch(input);
2243 b_addchr(&alt,ch);
2244 }
2245 lookup_param(dest, ctx, &alt);
2246 } else if (isdigit(ch)) {
2247 i = ch-'0'; /* XXX is $0 special? */
2248 if (i<global_argc) {
2249 parse_string(dest, ctx, global_argv[i]); /* recursion */
2250 }
2251 advance = 1;
2252 } else switch (ch) {
2253 case '$':
2254 b_adduint(dest,getpid());
2255 advance = 1;
2256 break;
2257 case '!':
2258 if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
2259 advance = 1;
2260 break;
2261 case '?':
2262 b_adduint(dest,last_return_code);
2263 advance = 1;
2264 break;
2265 case '#':
2266 b_adduint(dest,global_argc ? global_argc-1 : 0);
2267 advance = 1;
2268 break;
2269 case '{':
2270 b_getch(input);
2271 /* XXX maybe someone will try to escape the '}' */
2272 while(ch=b_getch(input),ch!=EOF && ch!='}') {
2273 b_addchr(&alt,ch);
2274 }
2275 if (ch != '}') {
2276 syntax();
2277 return 1;
2278 }
2279 lookup_param(dest, ctx, &alt);
2280 break;
2281 case '(':
2282 b_getch(input);
2283 process_command_subs(dest, ctx, input, ')');
2284 break;
2285 case '*':
2286 sep[0]=ifs[0];
2287 for (i=1; i<global_argc; i++) {
2288 parse_string(dest, ctx, global_argv[i]);
2289 if (i+1 < global_argc) parse_string(dest, ctx, sep);
2290 }
2291 break;
2292 case '@':
2293 case '-':
2294 case '_':
2295 /* still unhandled, but should be eventually */
2296 error_msg("unhandled syntax: $%c",ch);
2297 return 1;
2298 break;
2299 default:
2300 b_addqchr(dest,'$',dest->quote);
2301 }
2302 /* Eat the character if the flag was set. If the compiler
2303 * is smart enough, we could substitute "b_getch(input);"
2304 * for all the "advance = 1;" above, and also end up with
2305 * a nice size-optimized program. Hah! That'll be the day.
2306 */
2307 if (advance) b_getch(input);
2308 return 0;
2309}
2310
2311int parse_string(o_string *dest, struct p_context *ctx, const char *src)
2312{
2313 struct in_str foo;
2314 setup_string_in_str(&foo, src);
2315 return parse_stream(dest, ctx, &foo, '\0');
2316}
2317
2318/* return code is 0 for normal exit, 1 for syntax error */
2319int parse_stream(o_string *dest, struct p_context *ctx,
2320 struct in_str *input, int end_trigger)
2321{
2322 unsigned int ch, m;
2323 int redir_fd;
2324 redir_type redir_style;
2325 int next;
2326
2327 /* Only double-quote state is handled in the state variable dest->quote.
2328 * A single-quote triggers a bypass of the main loop until its mate is
2329 * found. When recursing, quote state is passed in via dest->quote. */
2330
2331 debug_printf("parse_stream, end_trigger=%d\n",end_trigger);
2332 while ((ch=b_getch(input))!=EOF) {
2333 m = map[ch];
2334 next = (ch == '\n') ? 0 : b_peek(input);
2335 debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n",
2336 ch,ch,m,dest->quote);
2337 if (m==0 || ((m==1 || m==2) && dest->quote)) {
2338 b_addqchr(dest, ch, dest->quote);
2339 } else {
2340 if (m==2) { /* unquoted IFS */
2341 done_word(dest, ctx);
2342 /* If we aren't performing a substitution, treat a newline as a
2343 * command separator. */
2344 if (end_trigger != '\0' && ch=='\n')
2345 done_pipe(ctx,PIPE_SEQ);
2346 }
2347 if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
2348 debug_printf("leaving parse_stream (triggered)\n");
2349 return 0;
2350 }
2351#if 0
2352 if (ch=='\n') {
2353 /* Yahoo! Time to run with it! */
2354 done_pipe(ctx,PIPE_SEQ);
2355 run_list(ctx->list_head);
2356 initialize_context(ctx);
2357 }
2358#endif
2359 if (m!=2) switch (ch) {
2360 case '#':
2361 if (dest->length == 0 && !dest->quote) {
2362 while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); }
2363 } else {
2364 b_addqchr(dest, ch, dest->quote);
2365 }
2366 break;
2367 case '\\':
2368 if (next == EOF) {
2369 syntax();
2370 return 1;
2371 }
2372 b_addqchr(dest, '\\', dest->quote);
2373 b_addqchr(dest, b_getch(input), dest->quote);
2374 break;
2375 case '$':
2376 if (handle_dollar(dest, ctx, input)!=0) return 1;
2377 break;
2378 case '\'':
2379 dest->nonnull = 1;
2380 while(ch=b_getch(input),ch!=EOF && ch!='\'') {
2381 b_addchr(dest,ch);
2382 }
2383 if (ch==EOF) {
2384 syntax();
2385 return 1;
2386 }
2387 break;
2388 case '"':
2389 dest->nonnull = 1;
2390 dest->quote = !dest->quote;
2391 break;
2392 case '`':
2393 process_command_subs(dest, ctx, input, '`');
2394 break;
2395 case '>':
2396 redir_fd = redirect_opt_num(dest);
2397 done_word(dest, ctx);
2398 redir_style=REDIRECT_OVERWRITE;
2399 if (next == '>') {
2400 redir_style=REDIRECT_APPEND;
2401 b_getch(input);
2402 } else if (next == '(') {
2403 syntax(); /* until we support >(list) Process Substitution */
2404 return 1;
2405 }
2406 setup_redirect(ctx, redir_fd, redir_style, input);
2407 break;
2408 case '<':
2409 redir_fd = redirect_opt_num(dest);
2410 done_word(dest, ctx);
2411 redir_style=REDIRECT_INPUT;
2412 if (next == '<') {
2413 redir_style=REDIRECT_HEREIS;
2414 b_getch(input);
2415 } else if (next == '>') {
2416 redir_style=REDIRECT_IO;
2417 b_getch(input);
2418 } else if (next == '(') {
2419 syntax(); /* until we support <(list) Process Substitution */
2420 return 1;
2421 }
2422 setup_redirect(ctx, redir_fd, redir_style, input);
2423 break;
2424 case ';':
2425 done_word(dest, ctx);
2426 done_pipe(ctx,PIPE_SEQ);
2427 break;
2428 case '&':
2429 done_word(dest, ctx);
2430 if (next=='&') {
2431 b_getch(input);
2432 done_pipe(ctx,PIPE_AND);
2433 } else {
2434 done_pipe(ctx,PIPE_BG);
2435 }
2436 break;
2437 case '|':
2438 done_word(dest, ctx);
2439 if (next=='|') {
2440 b_getch(input);
2441 done_pipe(ctx,PIPE_OR);
2442 } else {
2443 /* we could pick up a file descriptor choice here
2444 * with redirect_opt_num(), but bash doesn't do it.
2445 * "echo foo 2| cat" yields "foo 2". */
2446 done_command(ctx);
2447 }
2448 break;
2449 case '(':
2450 case '{':
2451 if (parse_group(dest, ctx, input, ch)!=0) return 1;
2452 break;
2453 case ')':
2454 case '}':
2455 syntax(); /* Proper use of this character caught by end_trigger */
2456 return 1;
2457 break;
2458 default:
2459 syntax(); /* this is really an internal logic error */
2460 return 1;
2461 }
2462 }
2463 }
2464 /* complain if quote? No, maybe we just finished a command substitution
2465 * that was quoted. Example:
2466 * $ echo "`cat foo` plus more"
2467 * and we just got the EOF generated by the subshell that ran "cat foo"
2468 * The only real complaint is if we got an EOF when end_trigger != '\0',
2469 * that is, we were really supposed to get end_trigger, and never got
2470 * one before the EOF. Can't use the standard "syntax error" return code,
2471 * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
2472 debug_printf("leaving parse_stream (EOF)\n");
2473 if (end_trigger != '\0') return -1;
2474 return 0;
2475}
2476
2477void mapset(const unsigned char *set, int code)
2478{
2479 const unsigned char *s;
2480 for (s=set; *s; s++) map[*s] = code;
2481}
2482
2483void update_ifs_map(void)
2484{
2485 /* char *ifs and char map[256] are both globals. */
2486 ifs = getenv("IFS");
2487 if (ifs == NULL) ifs=" \t\n";
2488 /* Precompute a list of 'flow through' behavior so it can be treated
2489 * quickly up front. Computation is necessary because of IFS.
2490 * Special case handling of IFS == " \t\n" is not implemented.
2491 * The map[] array only really needs two bits each, and on most machines
2492 * that would be faster because of the reduced L1 cache footprint.
2493 */
2494 memset(map,0,sizeof(map)); /* most characters flow through always */
2495 mapset("\\$'\"`", 3); /* never flow through */
2496 mapset("<>;&|(){}#", 1); /* flow through if quoted */
2497 mapset(ifs, 2); /* also flow through if quoted */
2498}
2499
2500/* most recursion does not come through here, the exeception is
2501 * from builtin_source() */
2502int parse_stream_outer(struct in_str *inp)
2503{
2504
2505 struct p_context ctx;
2506 o_string temp=NULL_O_STRING;
2507 int rcode;
2508 do {
2509 initialize_context(&ctx);
2510 update_ifs_map();
2511 inp->promptmode=1;
2512 rcode = parse_stream(&temp, &ctx, inp, '\n');
2513 done_word(&temp, &ctx);
2514 done_pipe(&ctx,PIPE_SEQ);
2515 run_list(ctx.list_head);
2516 b_free(&temp);
2517 } while (rcode != -1); /* loop on syntax errors, return on EOF */
2518 return 0;
2519}
2520
2521static int parse_string_outer(const char *s)
2522{
2523 struct in_str input;
2524 setup_string_in_str(&input, s);
2525 return parse_stream_outer(&input);
2526}
2527
2528static int parse_file_outer(FILE *f)
2529{
2530 int rcode;
2531 struct in_str input;
2532 setup_file_in_str(&input, f);
2533 rcode = parse_stream_outer(&input);
2534 return rcode;
2535}
2536
2537/* Make sure we have a controlling tty. If we get started under a job
2538 * aware app (like bash for example), make sure we are now in charge so
2539 * we don't fight over who gets the foreground */
2540static void setup_job_control()
2541{
2542 static pid_t shell_pgrp;
2543 /* Loop until we are in the foreground. */
2544 while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
2545 kill (- shell_pgrp, SIGTTIN);
2546
2547 /* Ignore interactive and job-control signals. */
2548 signal(SIGINT, SIG_IGN);
2549 signal(SIGQUIT, SIG_IGN);
2550 signal(SIGTERM, SIG_IGN);
2551 signal(SIGTSTP, SIG_IGN);
2552 signal(SIGTTIN, SIG_IGN);
2553 signal(SIGTTOU, SIG_IGN);
2554 signal(SIGCHLD, SIG_IGN);
2555
2556 /* Put ourselves in our own process group. */
2557 setsid();
2558 shell_pgrp = getpid ();
2559 setpgid (shell_pgrp, shell_pgrp);
2560
2561 /* Grab control of the terminal. */
2562 tcsetpgrp(shell_terminal, shell_pgrp);
2563}
2564
2565int hush_main(int argc, char **argv)
2566{
2567 int opt;
2568 FILE *input;
2569 char **e = environ;
2570
2571 /* XXX what should these be while sourcing /etc/profile? */
2572 global_argc = argc;
2573 global_argv = argv;
2574
2575 /* (re?) initialize globals. Sometimes hush_main() ends up calling
2576 * hush_main(), therefore we cannot rely on the BSS to zero out this
2577 * stuff. Reset these to 0 every time. */
2578 ifs = NULL;
2579 /* map[] is taken care of with call to update_ifs_map() */
2580 fake_mode = 0;
2581 interactive = 0;
2582 close_me_head = NULL;
2583 last_bg_pid = 0;
2584 job_list = NULL;
2585 last_jobid = 0;
2586
2587 /* Initialize some more globals to non-zero values */
2588 set_cwd();
2589#ifdef BB_FEATURE_COMMAND_EDITING
2590 cmdedit_set_initial_prompt();
2591#else
2592 PS1 = NULL;
2593#endif
2594 PS2 = "> ";
2595
2596 /* initialize our shell local variables with the values
2597 * currently living in the environment */
2598 if (e) {
2599 for (; *e; e++)
2600 set_local_var(*e, 2); /* without call putenv() */
2601 }
2602
2603 last_return_code=EXIT_SUCCESS;
2604
2605
2606 if (argv[0] && argv[0][0] == '-') {
2607 debug_printf("\nsourcing /etc/profile\n");
2608 if ((input = fopen("/etc/profile", "r")) != NULL) {
2609 mark_open(fileno(input));
2610 parse_file_outer(input);
2611 mark_closed(fileno(input));
2612 fclose(input);
2613 }
2614 }
2615 input=stdin;
2616
2617 while ((opt = getopt(argc, argv, "c:xif")) > 0) {
2618 switch (opt) {
2619 case 'c':
2620 {
2621 global_argv = argv+optind;
2622 global_argc = argc-optind;
2623 opt = parse_string_outer(optarg);
2624 goto final_return;
2625 }
2626 break;
2627 case 'i':
2628 interactive++;
2629 break;
2630 case 'f':
2631 fake_mode++;
2632 break;
2633 default:
2634#ifndef BB_VER
2635 fprintf(stderr, "Usage: sh [FILE]...\n"
2636 " or: sh -c command [args]...\n\n");
2637 exit(EXIT_FAILURE);
2638#else
2639 show_usage();
2640#endif
2641 }
2642 }
2643 /* A shell is interactive if the `-i' flag was given, or if all of
2644 * the following conditions are met:
2645 * no -c command
2646 * no arguments remaining or the -s flag given
2647 * standard input is a terminal
2648 * standard output is a terminal
2649 * Refer to Posix.2, the description of the `sh' utility. */
2650 if (argv[optind]==NULL && input==stdin &&
2651 isatty(fileno(stdin)) && isatty(fileno(stdout))) {
2652 interactive++;
2653 }
2654
2655 debug_printf("\ninteractive=%d\n", interactive);
2656 if (interactive) {
2657 /* Looks like they want an interactive shell */
2658#ifndef BB_FEATURE_SH_EXTRA_QUIET
2659 printf( "\n\n" BB_BANNER " hush - the humble shell v0.01 (testing)\n");
2660 printf( "Enter 'help' for a list of built-in commands.\n\n");
2661#endif
2662 setup_job_control();
2663 }
2664
2665 if (argv[optind]==NULL) {
2666 opt=parse_file_outer(stdin);
2667 goto final_return;
2668 }
2669
2670 debug_printf("\nrunning script '%s'\n", argv[optind]);
2671 global_argv = argv+optind;
2672 global_argc = argc-optind;
2673 input = xfopen(argv[optind], "r");
2674 opt = parse_file_outer(input);
2675
2676#ifdef BB_FEATURE_CLEAN_UP
2677 fclose(input);
2678 if (cwd && cwd != unknown)
2679 free((char*)cwd);
2680 {
2681 struct variables *cur, *tmp;
2682 for(cur = top_vars; cur; cur = tmp) {
2683 tmp = cur->next;
2684 if (!cur->flg_read_only) {
2685 free(cur->name);
2686 free(cur->value);
2687 free(cur);
2688 }
2689 }
2690 }
2691#endif
2692
2693final_return:
2694 return(opt?opt:last_return_code);
2695}
diff --git a/id.c b/id.c
deleted file mode 100644
index 85b288c0c..000000000
--- a/id.c
+++ /dev/null
@@ -1,97 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini id implementation for busybox
4 *
5 * Copyright (C) 2000 by Randolph Chung <tausq@debian.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include "busybox.h"
24#include <stdio.h>
25#include <unistd.h>
26#include <getopt.h>
27#include <string.h>
28#include <sys/types.h>
29
30extern int id_main(int argc, char **argv)
31{
32 int no_user = 0, no_group = 0, print_real = 0;
33 int name_not_number = 0;
34 char user[9], group[9];
35 long gid;
36 long pwnam, grnam;
37 int opt;
38
39 gid = 0;
40
41 while ((opt = getopt(argc, argv, "ugrn")) > 0) {
42 switch (opt) {
43 case 'u':
44 no_group++;
45 break;
46 case 'g':
47 no_user++;
48 break;
49 case 'r':
50 print_real++;
51 break;
52 case 'n':
53 name_not_number++;
54 break;
55 default:
56 show_usage();
57 }
58 }
59
60 if (no_user && no_group) show_usage();
61
62 if (argv[optind] == NULL) {
63 if (print_real) {
64 my_getpwuid(user, getuid());
65 my_getgrgid(group, getgid());
66 } else {
67 my_getpwuid(user, geteuid());
68 my_getgrgid(group, getegid());
69 }
70 } else {
71 strncpy(user, argv[optind], 8);
72 user[8] = '\0';
73 gid = my_getpwnamegid(user);
74 my_getgrgid(group, gid);
75 }
76
77 pwnam=my_getpwnam(user);
78 grnam=my_getgrnam(group);
79
80 if (no_group) {
81 if(name_not_number && user)
82 puts(user);
83 else
84 printf("%ld\n", pwnam);
85 } else if (no_user) {
86 if(name_not_number && group)
87 puts(group);
88 else
89 printf("%ld\n", grnam);
90 } else {
91 printf("uid=%ld(%s) gid=%ld(%s)\n", pwnam, user, grnam, group);
92 }
93 return(0);
94}
95
96
97/* END CODE */
diff --git a/ifconfig.c b/ifconfig.c
deleted file mode 100644
index c77ea04b1..000000000
--- a/ifconfig.c
+++ /dev/null
@@ -1,492 +0,0 @@
1/* ifconfig
2 *
3 * Similar to the standard Unix ifconfig, but with only the necessary
4 * parts for AF_INET, and without any printing of if info (for now).
5 *
6 * Bjorn Wesen, Axis Communications AB
7 *
8 *
9 * Authors of the original ifconfig was:
10 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
11 *
12 * This program is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU General
14 * Public License as published by the Free Software
15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version.
17 *
18 * $Id: ifconfig.c,v 1.12 2001/08/10 06:02:23 mjn3 Exp $
19 *
20 */
21
22/*
23 * Heavily modified by Manuel Novoa III Mar 6, 2001
24 *
25 * From initial port to busybox, removed most of the redundancy by
26 * converting to a table-driven approach. Added several (optional)
27 * args missing from initial port.
28 *
29 * Still missing: media, tunnel.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h> // strcmp and friends
35#include <ctype.h> // isdigit and friends
36#include <stddef.h> /* offsetof */
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <sys/ioctl.h>
40#include <netinet/in.h>
41#include <arpa/inet.h>
42#include <net/if.h>
43#include <net/if_arp.h>
44#include <linux/if_ether.h>
45#include "busybox.h"
46
47#ifdef BB_FEATURE_IFCONFIG_SLIP
48#include <linux/if_slip.h>
49#endif
50
51/* I don't know if this is needed for busybox or not. Anyone? */
52#define QUESTIONABLE_ALIAS_CASE
53
54
55/* Defines for glibc2.0 users. */
56#ifndef SIOCSIFTXQLEN
57#define SIOCSIFTXQLEN 0x8943
58#define SIOCGIFTXQLEN 0x8942
59#endif
60
61/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
62#ifndef ifr_qlen
63#define ifr_qlen ifr_ifru.ifru_mtu
64#endif
65
66#ifndef IFF_DYNAMIC
67#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
68#endif
69
70/*
71 * Here are the bit masks for the "flags" member of struct options below.
72 * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
73 * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg.
74 */
75#define N_CLR 0x01
76#define M_CLR 0x02
77#define N_SET 0x04
78#define M_SET 0x08
79#define N_ARG 0x10
80#define M_ARG 0x20
81
82#define M_MASK (M_CLR | M_SET | M_ARG)
83#define N_MASK (N_CLR | N_SET | N_ARG)
84#define SET_MASK (N_SET | M_SET)
85#define CLR_MASK (N_CLR | M_CLR)
86#define SET_CLR_MASK (SET_MASK | CLR_MASK)
87#define ARG_MASK (M_ARG | N_ARG)
88
89/*
90 * Here are the bit masks for the "arg_flags" member of struct options below.
91 */
92
93/*
94 * cast type:
95 * 00 int
96 * 01 char *
97 * 02 HOST_COPY in_ether
98 * 03 HOST_COPY INET_resolve
99 */
100#define A_CAST_TYPE 0x03
101/*
102 * map type:
103 * 00 not a map type (mem_start, io_addr, irq)
104 * 04 memstart (unsigned long)
105 * 08 io_addr (unsigned short)
106 * 0C irq (unsigned char)
107 */
108#define A_MAP_TYPE 0x0C
109#define A_ARG_REQ 0x10 /* Set if an arg is required. */
110#define A_NETMASK 0x20 /* Set if netmask (check for multiple sets). */
111#define A_SET_AFTER 0x40 /* Set a flag at the end. */
112#define A_COLON_CHK 0x80 /* Is this needed? See below. */
113
114/*
115 * These defines are for dealing with the A_CAST_TYPE field.
116 */
117#define A_CAST_CHAR_PTR 0x01
118#define A_CAST_RESOLVE 0x01
119#define A_CAST_HOST_COPY 0x02
120#define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY
121#define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE)
122
123/*
124 * These defines are for dealing with the A_MAP_TYPE field.
125 */
126#define A_MAP_ULONG 0x04 /* memstart */
127#define A_MAP_USHORT 0x08 /* io_addr */
128#define A_MAP_UCHAR 0x0C /* irq */
129
130/*
131 * Define the bit masks signifying which operations to perform for each arg.
132 */
133
134#define ARG_METRIC (A_ARG_REQ /*| A_CAST_INT*/)
135#define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/)
136#define ARG_TXQUEUELEN (A_ARG_REQ /*| A_CAST_INT*/)
137#define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG)
138#define ARG_IO_ADDR (A_ARG_REQ | A_MAP_USHORT)
139#define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR)
140#define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
141#define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
142#define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
143#define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
144#define ARG_POINTOPOINT (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
145#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR)
146#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR)
147#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
148
149
150/*
151 * Set up the tables. Warning! They must have corresponding order!
152 */
153
154struct arg1opt {
155 const char *name;
156 unsigned short selector;
157 unsigned short ifr_offset;
158};
159
160struct options {
161 const char *name;
162 const unsigned char flags;
163 const unsigned char arg_flags;
164 const unsigned short selector;
165};
166
167#define ifreq_offsetof(x) offsetof(struct ifreq, x)
168
169static const struct arg1opt Arg1Opt[] = {
170 {"SIOCSIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric)},
171 {"SIOCSIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu)},
172 {"SIOCSIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen)},
173 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
174 {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
175 {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
176#ifdef BB_FEATURE_IFCONFIG_HW
177 {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)},
178#endif
179 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
180#ifdef SIOCSKEEPALIVE
181 {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},
182#endif
183#ifdef SIOCSOUTFILL
184 {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)},
185#endif
186#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
187 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)},
188 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)},
189 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)},
190#endif
191 /* Last entry if for unmatched (possibly hostname) arg. */
192 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)},
193};
194
195static const struct options OptArray[] = {
196 {"metric", N_ARG, ARG_METRIC, 0},
197 {"mtu", N_ARG, ARG_MTU, 0},
198 {"txqueuelen", N_ARG, ARG_TXQUEUELEN, 0},
199 {"dstaddr", N_ARG, ARG_DSTADDR, 0},
200 {"netmask", N_ARG, ARG_NETMASK, 0},
201 {"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST},
202#ifdef BB_FEATURE_IFCONFIG_HW
203 {"hw", N_ARG, ARG_HW, 0},
204#endif
205 {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
206#ifdef SIOCSKEEPALIVE
207 {"keepalive", N_ARG, ARG_KEEPALIVE, 0},
208#endif
209#ifdef SIOCSOUTFILL
210 {"outfill", N_ARG, ARG_OUTFILL, 0},
211#endif
212#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
213 {"mem_start", N_ARG, ARG_MEM_START, 0},
214 {"io_addr", N_ARG, ARG_IO_ADDR, 0},
215 {"irq", N_ARG, ARG_IRQ, 0},
216#endif
217 {"arp", N_CLR | M_SET, 0, IFF_NOARP},
218 {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS},
219 {"promisc", N_SET | M_CLR, 0, IFF_PROMISC},
220 {"multicast", N_SET | M_CLR, 0, IFF_MULTICAST},
221 {"allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI},
222 {"dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC},
223 {"up", N_SET , 0, (IFF_UP | IFF_RUNNING)},
224 {"down", N_CLR , 0, IFF_UP},
225 { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING)}
226};
227
228/*
229 * A couple of prototypes.
230 */
231
232#ifdef BB_FEATURE_IFCONFIG_HW
233static int in_ether(char *bufp, struct sockaddr *sap);
234#endif
235
236#ifdef BB_FEATURE_IFCONFIG_STATUS
237extern int interface_opt_a;
238extern int display_interfaces(char *ifname);
239#endif
240
241/*
242 * Our main function.
243 */
244
245int ifconfig_main(int argc, char **argv)
246{
247 struct ifreq ifr;
248 struct sockaddr_in sai;
249#ifdef BB_FEATURE_IFCONFIG_HW
250 struct sockaddr sa;
251#endif
252 const struct arg1opt *a1op;
253 const struct options *op;
254 int sockfd; /* socket fd we use to manipulate stuff with */
255 int goterr;
256 int selector;
257 char *p;
258 char host[128];
259 unsigned char mask;
260 unsigned char did_flags;
261
262 goterr = 0;
263 did_flags = 0;
264
265 /* skip argv[0] */
266 ++argv;
267 --argc;
268
269#ifdef BB_FEATURE_IFCONFIG_STATUS
270 if ((argc > 0) && (strcmp(*argv,"-a") == 0)) {
271 interface_opt_a = 1;
272 --argc;
273 ++argv;
274 }
275#endif
276
277 if(argc <= 1) {
278#ifdef BB_FEATURE_IFCONFIG_STATUS
279 return display_interfaces(argc ? *argv : NULL);
280#else
281 error_msg_and_die( "ifconfig was not compiled with interface status display support.");
282#endif
283 }
284
285 /* Create a channel to the NET kernel. */
286 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
287 perror_msg_and_die("socket");
288 }
289
290 /* get interface name */
291 safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
292
293 /* Process the remaining arguments. */
294 while (*++argv != (char *) NULL) {
295 p = *argv;
296 mask = N_MASK;
297 if (*p == '-') { /* If the arg starts with '-'... */
298 ++p; /* advance past it and */
299 mask = M_MASK; /* set the appropriate mask. */
300 }
301 for (op = OptArray ; op->name ; op++) { /* Find table entry. */
302 if (strcmp(p,op->name) == 0) { /* If name matches... */
303 if ((mask &= op->flags)) { /* set the mask and go. */
304 goto FOUND_ARG;;
305 }
306 /* If we get here, there was a valid arg with an */
307 /* invalid '-' prefix. */
308 ++goterr;
309 goto LOOP;
310 }
311 }
312
313 /* We fell through, so treat as possible hostname. */
314 a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
315 mask = op->arg_flags;
316 goto HOSTNAME;
317
318 FOUND_ARG:
319 if (mask & ARG_MASK) {
320 mask = op->arg_flags;
321 a1op = Arg1Opt + (op - OptArray);
322 if (mask & A_NETMASK & did_flags) {
323 show_usage();
324 }
325 if (*++argv == NULL) {
326 if (mask & A_ARG_REQ) {
327 show_usage();
328 } else {
329 --argv;
330 mask &= A_SET_AFTER; /* just for broadcast */
331 }
332 } else { /* got an arg so process it */
333 HOSTNAME:
334 did_flags |= (mask & A_NETMASK);
335 if (mask & A_CAST_HOST_COPY) {
336#ifdef BB_FEATURE_IFCONFIG_HW
337 if (mask & A_CAST_RESOLVE) {
338#endif
339 safe_strncpy(host, *argv, (sizeof host));
340 sai.sin_family = AF_INET;
341 sai.sin_port = 0;
342 if (!strcmp(host, "default")) {
343 /* Default is special, meaning 0.0.0.0. */
344 sai.sin_addr.s_addr = INADDR_ANY;
345 } else if (inet_aton(host, &sai.sin_addr) == 0) {
346 /* It's not a dotted quad. */
347 ++goterr;
348 continue;
349 }
350 p = (char *) &sai;
351#ifdef BB_FEATURE_IFCONFIG_HW
352 } else { /* A_CAST_HOST_COPY_IN_ETHER */
353 /* This is the "hw" arg case. */
354 if (strcmp("ether", *argv) || (*++argv == NULL)) {
355 show_usage();
356 }
357 safe_strncpy(host, *argv, (sizeof host));
358 if (in_ether(host, &sa)) {
359 fprintf(stderr, "invalid hw-addr %s\n", host);
360 ++goterr;
361 continue;
362 }
363 p = (char *) &sa;
364 }
365#endif
366 memcpy((((char *)(&ifr)) + a1op->ifr_offset),
367 p, sizeof(struct sockaddr));
368 } else {
369 unsigned int i = strtoul(*argv,NULL,0);
370 p = ((char *)(&ifr)) + a1op->ifr_offset;
371#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
372 if (mask & A_MAP_TYPE) {
373 if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
374 ++goterr;
375 continue;
376 }
377 if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
378 *((unsigned char *) p) = i;
379 } else if (mask & A_MAP_USHORT) {
380 *((unsigned short *) p) = i;
381 } else {
382 *((unsigned long *) p) = i;
383 }
384 } else
385#endif
386 if (mask & A_CAST_CHAR_PTR) {
387 *((caddr_t *) p) = (caddr_t) i;
388 } else { /* A_CAST_INT */
389 *((int *) p) = i;
390 }
391 }
392
393 if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
394 perror(a1op->name);
395 ++goterr;
396 continue;
397 }
398
399#ifdef QUESTIONABLE_ALIAS_CASE
400 if (mask & A_COLON_CHK) {
401 /*
402 * Don't do the set_flag() if the address is an alias with
403 * a - at the end, since it's deleted already! - Roman
404 *
405 * Should really use regex.h here, not sure though how well
406 * it'll go with the cross-platform support etc.
407 */
408 char *ptr;
409 short int found_colon = 0;
410 for (ptr = ifr.ifr_name; *ptr; ptr++ ) {
411 if (*ptr == ':') {
412 found_colon++;
413 }
414 }
415
416 if (found_colon && *(ptr - 1) == '-') {
417 continue;
418 }
419 }
420#endif
421 }
422 if (!(mask & A_SET_AFTER)) {
423 continue;
424 }
425 mask = N_SET;
426 }
427
428 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
429 perror("SIOCGIFFLAGS");
430 ++goterr;
431 } else {
432 selector = op->selector;
433 if (mask & SET_MASK) {
434 ifr.ifr_flags |= selector;
435 } else {
436 ifr.ifr_flags &= ~selector;
437 }
438 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
439 perror("SIOCSIFFLAGS");
440 ++goterr;
441 }
442 }
443 LOOP:
444 } /* end of while-loop */
445
446 return goterr;
447}
448
449#ifdef BB_FEATURE_IFCONFIG_HW
450/* Input an Ethernet address and convert to binary. */
451static int
452in_ether(char *bufp, struct sockaddr *sap)
453{
454 unsigned char *ptr;
455 int i, j;
456 unsigned char val;
457 unsigned char c;
458
459 sap->sa_family = ARPHRD_ETHER;
460 ptr = sap->sa_data;
461
462 for (i = 0 ; i < ETH_ALEN ; i++) {
463 val = 0;
464
465 /* We might get a semicolon here - not required. */
466 if (i && (*bufp == ':')) {
467 bufp++;
468 }
469
470 for (j=0 ; j<2 ; j++) {
471 c = *bufp;
472 if (c >= '0' && c <= '9') {
473 c -= '0';
474 } else if (c >= 'a' && c <= 'f') {
475 c -= ('a' - 10);
476 } else if (c >= 'A' && c <= 'F') {
477 c -= ('A' - 10);
478 } else if (j && (c == ':' || c == 0)) {
479 break;
480 } else {
481 return -1;
482 }
483 ++bufp;
484 val <<= 4;
485 val += c;
486 }
487 *ptr++ = val;
488 }
489
490 return (int) (*bufp); /* Error if we don't end at end of string. */
491}
492#endif
diff --git a/include/applets.h b/include/applets.h
index 5ecfe3cba..35dd947fe 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -21,7 +21,7 @@
21 #define APPLET_ODDNAME(a,b,c,d) extern int b(int argc, char **argv); 21 #define APPLET_ODDNAME(a,b,c,d) extern int b(int argc, char **argv);
22 extern const char usage_messages[]; 22 extern const char usage_messages[];
23#elif defined(MAKE_USAGE) 23#elif defined(MAKE_USAGE)
24 #ifdef BB_FEATURE_VERBOSE_USAGE 24 #ifdef CONFIG_FEATURE_VERBOSE_USAGE
25 #define APPLET(a,b,c) a##_trivial_usage "\n\n" a##_full_usage "\0" 25 #define APPLET(a,b,c) a##_trivial_usage "\n\n" a##_full_usage "\0"
26 #define APPLET_NOUSAGE(a,b,c) "\0" 26 #define APPLET_NOUSAGE(a,b,c) "\0"
27 #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\n\n" d##_full_usage "\0" 27 #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\n\n" d##_full_usage "\0"
@@ -43,452 +43,452 @@
43 43
44 44
45 45
46#ifdef BB_TEST 46#ifdef CONFIG_TEST
47 APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN) 47 APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN)
48#endif 48#endif
49#ifdef BB_ADDGROUP 49#ifdef CONFIG_ADDGROUP
50 APPLET(addgroup, addgroup_main, _BB_DIR_BIN) 50 APPLET(addgroup, addgroup_main, _BB_DIR_BIN)
51#endif 51#endif
52#ifdef BB_ADDUSER 52#ifdef CONFIG_ADDUSER
53 APPLET(adduser, adduser_main, _BB_DIR_BIN) 53 APPLET(adduser, adduser_main, _BB_DIR_BIN)
54#endif 54#endif
55#ifdef BB_ADJTIMEX 55#ifdef CONFIG_ADJTIMEX
56 APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN) 56 APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN)
57#endif 57#endif
58#ifdef BB_AR 58#ifdef CONFIG_AR
59 APPLET(ar, ar_main, _BB_DIR_USR_BIN) 59 APPLET(ar, ar_main, _BB_DIR_USR_BIN)
60#endif 60#endif
61#ifdef BB_ASH 61#ifdef CONFIG_ASH
62 APPLET_NOUSAGE("ash", ash_main, _BB_DIR_BIN) 62 APPLET_NOUSAGE("ash", ash_main, _BB_DIR_BIN)
63#endif 63#endif
64#ifdef BB_BASENAME 64#ifdef CONFIG_BASENAME
65 APPLET(basename, basename_main, _BB_DIR_USR_BIN) 65 APPLET(basename, basename_main, _BB_DIR_USR_BIN)
66#endif 66#endif
67#ifdef BB_BUNZIP2 67#ifdef CONFIG_BUNZIP2
68 APPLET(bunzip2, bunzip2_main, _BB_DIR_USR_BIN) 68 APPLET(bunzip2, bunzip2_main, _BB_DIR_USR_BIN)
69#endif 69#endif
70 APPLET_NOUSAGE("busybox", busybox_main, _BB_DIR_BIN) 70 APPLET_NOUSAGE("busybox", busybox_main, _BB_DIR_BIN)
71#ifdef BB_CAT 71#ifdef CONFIG_CAT
72 APPLET(cat, cat_main, _BB_DIR_BIN) 72 APPLET(cat, cat_main, _BB_DIR_BIN)
73#endif 73#endif
74#ifdef BB_CHGRP 74#ifdef CONFIG_CHGRP
75 APPLET(chgrp, chgrp_main, _BB_DIR_BIN) 75 APPLET(chgrp, chgrp_main, _BB_DIR_BIN)
76#endif 76#endif
77#ifdef BB_CHMOD 77#ifdef CONFIG_CHMOD
78 APPLET(chmod, chmod_main, _BB_DIR_BIN) 78 APPLET(chmod, chmod_main, _BB_DIR_BIN)
79#endif 79#endif
80#ifdef BB_CHOWN 80#ifdef CONFIG_CHOWN
81 APPLET(chown, chown_main, _BB_DIR_BIN) 81 APPLET(chown, chown_main, _BB_DIR_BIN)
82#endif 82#endif
83#ifdef BB_CHROOT 83#ifdef CONFIG_CHROOT
84 APPLET(chroot, chroot_main, _BB_DIR_USR_SBIN) 84 APPLET(chroot, chroot_main, _BB_DIR_USR_SBIN)
85#endif 85#endif
86#ifdef BB_CHVT 86#ifdef CONFIG_CHVT
87 APPLET(chvt, chvt_main, _BB_DIR_USR_BIN) 87 APPLET(chvt, chvt_main, _BB_DIR_USR_BIN)
88#endif 88#endif
89#ifdef BB_CLEAR 89#ifdef CONFIG_CLEAR
90 APPLET(clear, clear_main, _BB_DIR_USR_BIN) 90 APPLET(clear, clear_main, _BB_DIR_USR_BIN)
91#endif 91#endif
92#ifdef BB_CMP 92#ifdef CONFIG_CMP
93 APPLET(cmp, cmp_main, _BB_DIR_USR_BIN) 93 APPLET(cmp, cmp_main, _BB_DIR_USR_BIN)
94#endif 94#endif
95#ifdef BB_CP 95#ifdef CONFIG_CP
96 APPLET(cp, cp_main, _BB_DIR_BIN) 96 APPLET(cp, cp_main, _BB_DIR_BIN)
97#endif 97#endif
98#ifdef BB_CPIO 98#ifdef CONFIG_CPIO
99 APPLET(cpio, cpio_main, _BB_DIR_BIN) 99 APPLET(cpio, cpio_main, _BB_DIR_BIN)
100#endif 100#endif
101#ifdef BB_CUT 101#ifdef CONFIG_CUT
102 APPLET(cut, cut_main, _BB_DIR_USR_BIN) 102 APPLET(cut, cut_main, _BB_DIR_USR_BIN)
103#endif 103#endif
104#ifdef BB_DATE 104#ifdef CONFIG_DATE
105 APPLET(date, date_main, _BB_DIR_BIN) 105 APPLET(date, date_main, _BB_DIR_BIN)
106#endif 106#endif
107#ifdef BB_DC 107#ifdef CONFIG_DC
108 APPLET(dc, dc_main, _BB_DIR_USR_BIN) 108 APPLET(dc, dc_main, _BB_DIR_USR_BIN)
109#endif 109#endif
110#ifdef BB_DD 110#ifdef CONFIG_DD
111 APPLET(dd, dd_main, _BB_DIR_BIN) 111 APPLET(dd, dd_main, _BB_DIR_BIN)
112#endif 112#endif
113#ifdef BB_DEALLOCVT 113#ifdef CONFIG_DEALLOCVT
114 APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN) 114 APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN)
115#endif 115#endif
116#ifdef BB_DELGROUP 116#ifdef CONFIG_DELGROUP
117 APPLET(delgroup, delgroup_main, _BB_DIR_BIN) 117 APPLET(delgroup, delgroup_main, _BB_DIR_BIN)
118#endif 118#endif
119#ifdef BB_DELUSER 119#ifdef CONFIG_DELUSER
120 APPLET(deluser, deluser_main, _BB_DIR_BIN) 120 APPLET(deluser, deluser_main, _BB_DIR_BIN)
121#endif 121#endif
122#ifdef BB_DF 122#ifdef CONFIG_DF
123 APPLET(df, df_main, _BB_DIR_BIN) 123 APPLET(df, df_main, _BB_DIR_BIN)
124#endif 124#endif
125#ifdef BB_DIRNAME 125#ifdef CONFIG_DIRNAME
126 APPLET(dirname, dirname_main, _BB_DIR_USR_BIN) 126 APPLET(dirname, dirname_main, _BB_DIR_USR_BIN)
127#endif 127#endif
128#ifdef BB_DMESG 128#ifdef CONFIG_DMESG
129 APPLET(dmesg, dmesg_main, _BB_DIR_BIN) 129 APPLET(dmesg, dmesg_main, _BB_DIR_BIN)
130#endif 130#endif
131#ifdef BB_DOS2UNIX 131#ifdef CONFIG_DOS2UNIX
132 APPLET(dos2unix, dos2unix_main, _BB_DIR_USR_BIN) 132 APPLET(dos2unix, dos2unix_main, _BB_DIR_USR_BIN)
133#endif 133#endif
134#ifdef BB_DPKG 134#ifdef CONFIG_DPKG
135 APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN) 135 APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN)
136#endif 136#endif
137#ifdef BB_DPKG_DEB 137#ifdef CONFIG_DPKG_DEB
138 APPLET_ODDNAME("dpkg-deb", dpkg_deb_main, _BB_DIR_USR_BIN, dpkg_deb) 138 APPLET_ODDNAME("dpkg-deb", dpkg_deb_main, _BB_DIR_USR_BIN, dpkg_deb)
139#endif 139#endif
140#ifdef BB_DU 140#ifdef CONFIG_DU
141 APPLET(du, du_main, _BB_DIR_USR_BIN) 141 APPLET(du, du_main, _BB_DIR_USR_BIN)
142#endif 142#endif
143#ifdef BB_DUMPKMAP 143#ifdef CONFIG_DUMPKMAP
144 APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN) 144 APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN)
145#endif 145#endif
146#ifdef BB_DUTMP 146#ifdef CONFIG_DUTMP
147 APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN) 147 APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN)
148#endif 148#endif
149#ifdef BB_ECHO 149#ifdef CONFIG_ECHO
150 APPLET(echo, echo_main, _BB_DIR_BIN) 150 APPLET(echo, echo_main, _BB_DIR_BIN)
151#endif 151#endif
152#if defined(BB_FEATURE_GREP_EGREP_ALIAS) && defined(BB_GREP) 152#if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS) && defined(CONFIG_GREP)
153 APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN) 153 APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN)
154#endif 154#endif
155#ifdef BB_ENV 155#ifdef CONFIG_ENV
156 APPLET(env, env_main, _BB_DIR_USR_BIN) 156 APPLET(env, env_main, _BB_DIR_USR_BIN)
157#endif 157#endif
158#ifdef BB_EXPR 158#ifdef CONFIG_EXPR
159 APPLET(expr, expr_main, _BB_DIR_USR_BIN) 159 APPLET(expr, expr_main, _BB_DIR_USR_BIN)
160#endif 160#endif
161#ifdef BB_TRUE_FALSE 161#ifdef CONFIG_TRUE_FALSE
162 APPLET(false, false_main, _BB_DIR_BIN) 162 APPLET(false, false_main, _BB_DIR_BIN)
163#endif 163#endif
164#ifdef BB_FBSET 164#ifdef CONFIG_FBSET
165 APPLET(fbset, fbset_main, _BB_DIR_USR_SBIN) 165 APPLET(fbset, fbset_main, _BB_DIR_USR_SBIN)
166#endif 166#endif
167#ifdef BB_FDFLUSH 167#ifdef CONFIG_FDFLUSH
168 APPLET(fdflush, fdflush_main, _BB_DIR_BIN) 168 APPLET(fdflush, fdflush_main, _BB_DIR_BIN)
169#endif 169#endif
170#ifdef BB_FIND 170#ifdef CONFIG_FIND
171 APPLET(find, find_main, _BB_DIR_USR_BIN) 171 APPLET(find, find_main, _BB_DIR_USR_BIN)
172#endif 172#endif
173#ifdef BB_FREE 173#ifdef CONFIG_FREE
174 APPLET(free, free_main, _BB_DIR_USR_BIN) 174 APPLET(free, free_main, _BB_DIR_USR_BIN)
175#endif 175#endif
176#ifdef BB_FREERAMDISK 176#ifdef CONFIG_FREERAMDISK
177 APPLET(freeramdisk, freeramdisk_main, _BB_DIR_SBIN) 177 APPLET(freeramdisk, freeramdisk_main, _BB_DIR_SBIN)
178#endif 178#endif
179#ifdef BB_FSCK_MINIX 179#ifdef CONFIG_FSCK_MINIX
180 APPLET_ODDNAME("fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix) 180 APPLET_ODDNAME("fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix)
181#endif 181#endif
182#ifdef BB_GETOPT 182#ifdef CONFIG_GETOPT
183 APPLET(getopt, getopt_main, _BB_DIR_BIN) 183 APPLET(getopt, getopt_main, _BB_DIR_BIN)
184#endif 184#endif
185#ifdef BB_GETTY 185#ifdef CONFIG_GETTY
186 APPLET(getty, getty_main, _BB_DIR_SBIN) 186 APPLET(getty, getty_main, _BB_DIR_SBIN)
187#endif 187#endif
188#ifdef BB_GREP 188#ifdef CONFIG_GREP
189 APPLET(grep, grep_main, _BB_DIR_BIN) 189 APPLET(grep, grep_main, _BB_DIR_BIN)
190#endif 190#endif
191#ifdef BB_GUNZIP 191#ifdef CONFIG_GUNZIP
192 APPLET(gunzip, gunzip_main, _BB_DIR_BIN) 192 APPLET(gunzip, gunzip_main, _BB_DIR_BIN)
193#endif 193#endif
194#ifdef BB_GZIP 194#ifdef CONFIG_GZIP
195 APPLET(gzip, gzip_main, _BB_DIR_BIN) 195 APPLET(gzip, gzip_main, _BB_DIR_BIN)
196#endif 196#endif
197#ifdef BB_HALT 197#ifdef CONFIG_HALT
198 APPLET(halt, halt_main, _BB_DIR_SBIN) 198 APPLET(halt, halt_main, _BB_DIR_SBIN)
199#endif 199#endif
200#ifdef BB_HEAD 200#ifdef CONFIG_HEAD
201 APPLET(head, head_main, _BB_DIR_USR_BIN) 201 APPLET(head, head_main, _BB_DIR_USR_BIN)
202#endif 202#endif
203#ifdef BB_HOSTID 203#ifdef CONFIG_HOSTID
204 APPLET(hostid, hostid_main, _BB_DIR_USR_BIN) 204 APPLET(hostid, hostid_main, _BB_DIR_USR_BIN)
205#endif 205#endif
206#ifdef BB_HOSTNAME 206#ifdef CONFIG_HOSTNAME
207 APPLET(hostname, hostname_main, _BB_DIR_BIN) 207 APPLET(hostname, hostname_main, _BB_DIR_BIN)
208#endif 208#endif
209#ifdef BB_HUSH 209#ifdef CONFIG_HUSH
210 APPLET_NOUSAGE("hush", hush_main, _BB_DIR_BIN) 210 APPLET_NOUSAGE("hush", hush_main, _BB_DIR_BIN)
211#endif 211#endif
212#ifdef BB_ID 212#ifdef CONFIG_ID
213 APPLET(id, id_main, _BB_DIR_USR_BIN) 213 APPLET(id, id_main, _BB_DIR_USR_BIN)
214#endif 214#endif
215#ifdef BB_IFCONFIG 215#ifdef CONFIG_IFCONFIG
216 APPLET(ifconfig, ifconfig_main, _BB_DIR_SBIN) 216 APPLET(ifconfig, ifconfig_main, _BB_DIR_SBIN)
217#endif 217#endif
218#ifdef BB_INIT 218#ifdef CONFIG_INIT
219 APPLET(init, init_main, _BB_DIR_SBIN) 219 APPLET(init, init_main, _BB_DIR_SBIN)
220#endif 220#endif
221#ifdef BB_INSMOD 221#ifdef CONFIG_INSMOD
222 APPLET(insmod, insmod_main, _BB_DIR_SBIN) 222 APPLET(insmod, insmod_main, _BB_DIR_SBIN)
223#endif 223#endif
224#ifdef BB_KILL 224#ifdef CONFIG_KILL
225 APPLET(kill, kill_main, _BB_DIR_BIN) 225 APPLET(kill, kill_main, _BB_DIR_BIN)
226#endif 226#endif
227#ifdef BB_KILLALL 227#ifdef CONFIG_KILLALL
228 APPLET(killall, kill_main, _BB_DIR_USR_BIN) 228 APPLET(killall, kill_main, _BB_DIR_USR_BIN)
229#endif 229#endif
230#ifdef BB_KLOGD 230#ifdef CONFIG_KLOGD
231 APPLET(klogd, klogd_main, _BB_DIR_SBIN) 231 APPLET(klogd, klogd_main, _BB_DIR_SBIN)
232#endif 232#endif
233#ifdef BB_LASH 233#ifdef CONFIG_LASH
234 APPLET(lash, lash_main, _BB_DIR_BIN) 234 APPLET(lash, lash_main, _BB_DIR_BIN)
235#endif 235#endif
236#ifdef BB_LENGTH 236#ifdef CONFIG_LENGTH
237 APPLET(length, length_main, _BB_DIR_USR_BIN) 237 APPLET(length, length_main, _BB_DIR_USR_BIN)
238#endif 238#endif
239#ifdef BB_FEATURE_LINUXRC 239#ifdef CONFIG_FEATURE_INITRD
240 APPLET_NOUSAGE("linuxrc", init_main, _BB_DIR_ROOT) 240 APPLET_NOUSAGE("linuxrc", init_main, _BB_DIR_ROOT)
241#endif 241#endif
242#ifdef BB_LN 242#ifdef CONFIG_LN
243 APPLET(ln, ln_main, _BB_DIR_BIN) 243 APPLET(ln, ln_main, _BB_DIR_BIN)
244#endif 244#endif
245#ifdef BB_LOADACM 245#ifdef CONFIG_LOADACM
246 APPLET(loadacm, loadacm_main, _BB_DIR_USR_BIN) 246 APPLET(loadacm, loadacm_main, _BB_DIR_USR_BIN)
247#endif 247#endif
248#ifdef BB_LOADFONT 248#ifdef CONFIG_LOADFONT
249 APPLET(loadfont, loadfont_main, _BB_DIR_USR_BIN) 249 APPLET(loadfont, loadfont_main, _BB_DIR_USR_BIN)
250#endif 250#endif
251#ifdef BB_LOADKMAP 251#ifdef CONFIG_LOADKMAP
252 APPLET(loadkmap, loadkmap_main, _BB_DIR_SBIN) 252 APPLET(loadkmap, loadkmap_main, _BB_DIR_SBIN)
253#endif 253#endif
254#ifdef BB_LOGGER 254#ifdef CONFIG_LOGGER
255 APPLET(logger, logger_main, _BB_DIR_USR_BIN) 255 APPLET(logger, logger_main, _BB_DIR_USR_BIN)
256#endif 256#endif
257#ifdef BB_LOGNAME 257#ifdef CONFIG_LOGNAME
258 APPLET(logname, logname_main, _BB_DIR_USR_BIN) 258 APPLET(logname, logname_main, _BB_DIR_USR_BIN)
259#endif 259#endif
260#ifdef BB_LOGREAD 260#ifdef CONFIG_LOGREAD
261 APPLET(logread, logread_main, _BB_DIR_SBIN) 261 APPLET(logread, logread_main, _BB_DIR_SBIN)
262#endif 262#endif
263#ifdef BB_LS 263#ifdef CONFIG_LS
264 APPLET(ls, ls_main, _BB_DIR_BIN) 264 APPLET(ls, ls_main, _BB_DIR_BIN)
265#endif 265#endif
266#ifdef BB_LSMOD 266#ifdef CONFIG_LSMOD
267 APPLET(lsmod, lsmod_main, _BB_DIR_SBIN) 267 APPLET(lsmod, lsmod_main, _BB_DIR_SBIN)
268#endif 268#endif
269#ifdef BB_MAKEDEVS 269#ifdef CONFIG_MAKEDEVS
270 APPLET(makedevs, makedevs_main, _BB_DIR_SBIN) 270 APPLET(makedevs, makedevs_main, _BB_DIR_SBIN)
271#endif 271#endif
272#ifdef BB_MD5SUM 272#ifdef CONFIG_MD5SUM
273 APPLET(md5sum, md5sum_main, _BB_DIR_USR_BIN) 273 APPLET(md5sum, md5sum_main, _BB_DIR_USR_BIN)
274#endif 274#endif
275#ifdef BB_MKDIR 275#ifdef CONFIG_MKDIR
276 APPLET(mkdir, mkdir_main, _BB_DIR_BIN) 276 APPLET(mkdir, mkdir_main, _BB_DIR_BIN)
277#endif 277#endif
278#ifdef BB_MKFIFO 278#ifdef CONFIG_MKFIFO
279 APPLET(mkfifo, mkfifo_main, _BB_DIR_USR_BIN) 279 APPLET(mkfifo, mkfifo_main, _BB_DIR_USR_BIN)
280#endif 280#endif
281#ifdef BB_MKFS_MINIX 281#ifdef CONFIG_MKFS_MINIX
282 APPLET_ODDNAME("mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN, mkfs_minix) 282 APPLET_ODDNAME("mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN, mkfs_minix)
283#endif 283#endif
284#ifdef BB_MKNOD 284#ifdef CONFIG_MKNOD
285 APPLET(mknod, mknod_main, _BB_DIR_BIN) 285 APPLET(mknod, mknod_main, _BB_DIR_BIN)
286#endif 286#endif
287#ifdef BB_MKSWAP 287#ifdef CONFIG_MKSWAP
288 APPLET(mkswap, mkswap_main, _BB_DIR_SBIN) 288 APPLET(mkswap, mkswap_main, _BB_DIR_SBIN)
289#endif 289#endif
290#ifdef BB_MKTEMP 290#ifdef CONFIG_MKTEMP
291 APPLET(mktemp, mktemp_main, _BB_DIR_BIN) 291 APPLET(mktemp, mktemp_main, _BB_DIR_BIN)
292#endif 292#endif
293#ifdef BB_MODPROBE 293#ifdef CONFIG_MODPROBE
294 APPLET(modprobe, modprobe_main, _BB_DIR_SBIN) 294 APPLET(modprobe, modprobe_main, _BB_DIR_SBIN)
295#endif 295#endif
296#ifdef BB_MORE 296#ifdef CONFIG_MORE
297 APPLET(more, more_main, _BB_DIR_BIN) 297 APPLET(more, more_main, _BB_DIR_BIN)
298#endif 298#endif
299#ifdef BB_MOUNT 299#ifdef CONFIG_MOUNT
300 APPLET(mount, mount_main, _BB_DIR_BIN) 300 APPLET(mount, mount_main, _BB_DIR_BIN)
301#endif 301#endif
302#ifdef BB_MSH 302#ifdef CONFIG_MSH
303 APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN) 303 APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN)
304#endif 304#endif
305#ifdef BB_MT 305#ifdef CONFIG_MT
306 APPLET(mt, mt_main, _BB_DIR_BIN) 306 APPLET(mt, mt_main, _BB_DIR_BIN)
307#endif 307#endif
308#ifdef BB_MV 308#ifdef CONFIG_MV
309 APPLET(mv, mv_main, _BB_DIR_BIN) 309 APPLET(mv, mv_main, _BB_DIR_BIN)
310#endif 310#endif
311#ifdef BB_NC 311#ifdef CONFIG_NC
312 APPLET(nc, nc_main, _BB_DIR_USR_BIN) 312 APPLET(nc, nc_main, _BB_DIR_USR_BIN)
313#endif 313#endif
314#ifdef BB_NSLOOKUP 314#ifdef CONFIG_NSLOOKUP
315 APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN) 315 APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN)
316#endif 316#endif
317#ifdef BB_PIDOF 317#ifdef CONFIG_PIDOF
318 APPLET(pidof, pidof_main, _BB_DIR_BIN) 318 APPLET(pidof, pidof_main, _BB_DIR_BIN)
319#endif 319#endif
320#ifdef BB_PING 320#ifdef CONFIG_PING
321 APPLET(ping, ping_main, _BB_DIR_BIN) 321 APPLET(ping, ping_main, _BB_DIR_BIN)
322#endif 322#endif
323#ifdef BB_PIVOT_ROOT 323#ifdef CONFIG_PIVOT_ROOT
324 APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN) 324 APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN)
325#endif 325#endif
326#ifdef BB_POWEROFF 326#ifdef CONFIG_POWEROFF
327 APPLET(poweroff, poweroff_main, _BB_DIR_SBIN) 327 APPLET(poweroff, poweroff_main, _BB_DIR_SBIN)
328#endif 328#endif
329#ifdef BB_PRINTF 329#ifdef CONFIG_PRINTF
330 APPLET(printf, printf_main, _BB_DIR_USR_BIN) 330 APPLET(printf, printf_main, _BB_DIR_USR_BIN)
331#endif 331#endif
332#ifdef BB_PS 332#ifdef CONFIG_PS
333 APPLET(ps, ps_main, _BB_DIR_BIN) 333 APPLET(ps, ps_main, _BB_DIR_BIN)
334#endif 334#endif
335#ifdef BB_PWD 335#ifdef CONFIG_PWD
336 APPLET(pwd, pwd_main, _BB_DIR_BIN) 336 APPLET(pwd, pwd_main, _BB_DIR_BIN)
337#endif 337#endif
338#ifdef BB_RDATE 338#ifdef CONFIG_RDATE
339 APPLET(rdate, rdate_main, _BB_DIR_USR_BIN) 339 APPLET(rdate, rdate_main, _BB_DIR_USR_BIN)
340#endif 340#endif
341#ifdef BB_READLINK 341#ifdef CONFIG_READLINK
342 APPLET(readlink, readlink_main, _BB_DIR_USR_BIN) 342 APPLET(readlink, readlink_main, _BB_DIR_USR_BIN)
343#endif 343#endif
344#ifdef BB_REBOOT 344#ifdef CONFIG_REBOOT
345 APPLET(reboot, reboot_main, _BB_DIR_SBIN) 345 APPLET(reboot, reboot_main, _BB_DIR_SBIN)
346#endif 346#endif
347#ifdef BB_RENICE 347#ifdef CONFIG_RENICE
348 APPLET(renice, renice_main, _BB_DIR_USR_BIN) 348 APPLET(renice, renice_main, _BB_DIR_USR_BIN)
349#endif 349#endif
350#ifdef BB_RESET 350#ifdef CONFIG_RESET
351 APPLET(reset, reset_main, _BB_DIR_USR_BIN) 351 APPLET(reset, reset_main, _BB_DIR_USR_BIN)
352#endif 352#endif
353#ifdef BB_RM 353#ifdef CONFIG_RM
354 APPLET(rm, rm_main, _BB_DIR_BIN) 354 APPLET(rm, rm_main, _BB_DIR_BIN)
355#endif 355#endif
356#ifdef BB_RMDIR 356#ifdef CONFIG_RMDIR
357 APPLET(rmdir, rmdir_main, _BB_DIR_BIN) 357 APPLET(rmdir, rmdir_main, _BB_DIR_BIN)
358#endif 358#endif
359#ifdef BB_RMMOD 359#ifdef CONFIG_RMMOD
360 APPLET(rmmod, rmmod_main, _BB_DIR_SBIN) 360 APPLET(rmmod, rmmod_main, _BB_DIR_SBIN)
361#endif 361#endif
362#ifdef BB_ROUTE 362#ifdef CONFIG_ROUTE
363 APPLET(route, route_main, _BB_DIR_SBIN) 363 APPLET(route, route_main, _BB_DIR_SBIN)
364#endif 364#endif
365#ifdef BB_RPM2CPIO 365#ifdef CONFIG_RPM2CPIO
366 APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN) 366 APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN)
367#endif 367#endif
368#ifdef BB_SED 368#ifdef CONFIG_SED
369 APPLET(sed, sed_main, _BB_DIR_BIN) 369 APPLET(sed, sed_main, _BB_DIR_BIN)
370#endif 370#endif
371#ifdef BB_SETKEYCODES 371#ifdef CONFIG_SETKEYCODES
372 APPLET(setkeycodes, setkeycodes_main, _BB_DIR_USR_BIN) 372 APPLET(setkeycodes, setkeycodes_main, _BB_DIR_USR_BIN)
373#endif 373#endif
374#if defined(BB_FEATURE_SH_IS_ASH) && defined(BB_ASH) 374#if defined(CONFIG_FEATURE_SH_IS_ASH) && defined(CONFIG_ASH)
375 APPLET_NOUSAGE("sh", ash_main, _BB_DIR_BIN) 375 APPLET_NOUSAGE("sh", ash_main, _BB_DIR_BIN)
376#elif defined(BB_FEATURE_SH_IS_HUSH) && defined(BB_HUSH) 376#elif defined(CONFIG_FEATURE_SH_IS_HUSH) && defined(CONFIG_HUSH)
377 APPLET_NOUSAGE("sh", hush_main, _BB_DIR_BIN) 377 APPLET_NOUSAGE("sh", hush_main, _BB_DIR_BIN)
378#elif defined(BB_FEATURE_SH_IS_LASH) && defined(BB_LASH) 378#elif defined(CONFIG_FEATURE_SH_IS_LASH) && defined(CONFIG_LASH)
379 APPLET_NOUSAGE("sh", lash_main, _BB_DIR_BIN) 379 APPLET_NOUSAGE("sh", lash_main, _BB_DIR_BIN)
380#elif defined(BB_FEATURE_SH_IS_MSH) && defined(BB_MSH) 380#elif defined(CONFIG_FEATURE_SH_IS_MSH) && defined(CONFIG_MSH)
381 APPLET_NOUSAGE("sh", msh_main, _BB_DIR_BIN) 381 APPLET_NOUSAGE("sh", msh_main, _BB_DIR_BIN)
382#endif 382#endif
383#ifdef BB_SLEEP 383#ifdef CONFIG_SLEEP
384 APPLET(sleep, sleep_main, _BB_DIR_BIN) 384 APPLET(sleep, sleep_main, _BB_DIR_BIN)
385#endif 385#endif
386#ifdef BB_SORT 386#ifdef CONFIG_SORT
387 APPLET(sort, sort_main, _BB_DIR_USR_BIN) 387 APPLET(sort, sort_main, _BB_DIR_USR_BIN)
388#endif 388#endif
389#ifdef BB_START_STOP_DAEMON 389#ifdef CONFIG_START_STOP_DAEMON
390 APPLET_ODDNAME("start-stop-daemon", start_stop_daemon_main, _BB_DIR_SBIN, start_stop_daemon) 390 APPLET_ODDNAME("start-stop-daemon", start_stop_daemon_main, _BB_DIR_SBIN, start_stop_daemon)
391#endif 391#endif
392#ifdef BB_STTY 392#ifdef CONFIG_STTY
393 APPLET(stty, stty_main, _BB_DIR_BIN) 393 APPLET(stty, stty_main, _BB_DIR_BIN)
394#endif 394#endif
395#ifdef BB_SWAPONOFF 395#ifdef CONFIG_SWAPONOFF
396 APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN) 396 APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN)
397#endif 397#endif
398#ifdef BB_SWAPONOFF 398#ifdef CONFIG_SWAPONOFF
399 APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN) 399 APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN)
400#endif 400#endif
401#ifdef BB_SYNC 401#ifdef CONFIG_SYNC
402 APPLET(sync, sync_main, _BB_DIR_BIN) 402 APPLET(sync, sync_main, _BB_DIR_BIN)
403#endif 403#endif
404#ifdef BB_SYSLOGD 404#ifdef CONFIG_SYSLOGD
405 APPLET(syslogd, syslogd_main, _BB_DIR_SBIN) 405 APPLET(syslogd, syslogd_main, _BB_DIR_SBIN)
406#endif 406#endif
407#ifdef BB_TAIL 407#ifdef CONFIG_TAIL
408 APPLET(tail, tail_main, _BB_DIR_USR_BIN) 408 APPLET(tail, tail_main, _BB_DIR_USR_BIN)
409#endif 409#endif
410#ifdef BB_TAR 410#ifdef CONFIG_TAR
411 APPLET(tar, tar_main, _BB_DIR_BIN) 411 APPLET(tar, tar_main, _BB_DIR_BIN)
412#endif 412#endif
413#ifdef BB_TEE 413#ifdef CONFIG_TEE
414 APPLET(tee, tee_main, _BB_DIR_USR_BIN) 414 APPLET(tee, tee_main, _BB_DIR_USR_BIN)
415#endif 415#endif
416#ifdef BB_TELNET 416#ifdef CONFIG_TELNET
417 APPLET(telnet, telnet_main, _BB_DIR_USR_BIN) 417 APPLET(telnet, telnet_main, _BB_DIR_USR_BIN)
418#endif 418#endif
419#ifdef BB_TEST 419#ifdef CONFIG_TEST
420 APPLET(test, test_main, _BB_DIR_USR_BIN) 420 APPLET(test, test_main, _BB_DIR_USR_BIN)
421#endif 421#endif
422#ifdef BB_TFTP 422#ifdef CONFIG_TFTP
423 APPLET(tftp, tftp_main, _BB_DIR_USR_BIN) 423 APPLET(tftp, tftp_main, _BB_DIR_USR_BIN)
424#endif 424#endif
425#ifdef BB_TOUCH 425#ifdef CONFIG_TOUCH
426 APPLET(touch, touch_main, _BB_DIR_BIN) 426 APPLET(touch, touch_main, _BB_DIR_BIN)
427#endif 427#endif
428#ifdef BB_TR 428#ifdef CONFIG_TR
429 APPLET(tr, tr_main, _BB_DIR_USR_BIN) 429 APPLET(tr, tr_main, _BB_DIR_USR_BIN)
430#endif 430#endif
431#ifdef BB_TRACEROUTE 431#ifdef CONFIG_TRACEROUTE
432 APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN) 432 APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN)
433#endif 433#endif
434#ifdef BB_TRUE_FALSE 434#ifdef CONFIG_TRUE_FALSE
435 APPLET(true, true_main, _BB_DIR_BIN) 435 APPLET(true, true_main, _BB_DIR_BIN)
436#endif 436#endif
437#ifdef BB_TTY 437#ifdef CONFIG_TTY
438 APPLET(tty, tty_main, _BB_DIR_USR_BIN) 438 APPLET(tty, tty_main, _BB_DIR_USR_BIN)
439#endif 439#endif
440#ifdef BB_UMOUNT 440#ifdef CONFIG_UMOUNT
441 APPLET(umount, umount_main, _BB_DIR_BIN) 441 APPLET(umount, umount_main, _BB_DIR_BIN)
442#endif 442#endif
443#ifdef BB_UNAME 443#ifdef CONFIG_UNAME
444 APPLET(uname, uname_main, _BB_DIR_BIN) 444 APPLET(uname, uname_main, _BB_DIR_BIN)
445#endif 445#endif
446#ifdef BB_UNIQ 446#ifdef CONFIG_UNIQ
447 APPLET(uniq, uniq_main, _BB_DIR_USR_BIN) 447 APPLET(uniq, uniq_main, _BB_DIR_USR_BIN)
448#endif 448#endif
449#ifdef BB_UNIX2DOS 449#ifdef CONFIG_UNIX2DOS
450 APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN) 450 APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN)
451#endif 451#endif
452#ifdef BB_UPDATE 452#ifdef CONFIG_UPDATE
453 APPLET(update, update_main, _BB_DIR_SBIN) 453 APPLET(update, update_main, _BB_DIR_SBIN)
454#endif 454#endif
455#ifdef BB_UPTIME 455#ifdef CONFIG_UPTIME
456 APPLET(uptime, uptime_main, _BB_DIR_USR_BIN) 456 APPLET(uptime, uptime_main, _BB_DIR_USR_BIN)
457#endif 457#endif
458#ifdef BB_USLEEP 458#ifdef CONFIG_USLEEP
459 APPLET(usleep, usleep_main, _BB_DIR_BIN) 459 APPLET(usleep, usleep_main, _BB_DIR_BIN)
460#endif 460#endif
461#ifdef BB_UUDECODE 461#ifdef CONFIG_UUDECODE
462 APPLET(uudecode, uudecode_main, _BB_DIR_USR_BIN) 462 APPLET(uudecode, uudecode_main, _BB_DIR_USR_BIN)
463#endif 463#endif
464#ifdef BB_UUENCODE 464#ifdef CONFIG_UUENCODE
465 APPLET(uuencode, uuencode_main, _BB_DIR_USR_BIN) 465 APPLET(uuencode, uuencode_main, _BB_DIR_USR_BIN)
466#endif 466#endif
467#ifdef BB_VI 467#ifdef CONFIG_VI
468 APPLET(vi, vi_main, _BB_DIR_BIN) 468 APPLET(vi, vi_main, _BB_DIR_BIN)
469#endif 469#endif
470#ifdef BB_WATCHDOG 470#ifdef CONFIG_WATCHDOG
471 APPLET(watchdog, watchdog_main, _BB_DIR_SBIN) 471 APPLET(watchdog, watchdog_main, _BB_DIR_SBIN)
472#endif 472#endif
473#ifdef BB_WC 473#ifdef CONFIG_WC
474 APPLET(wc, wc_main, _BB_DIR_USR_BIN) 474 APPLET(wc, wc_main, _BB_DIR_USR_BIN)
475#endif 475#endif
476#ifdef BB_WGET 476#ifdef CONFIG_WGET
477 APPLET(wget, wget_main, _BB_DIR_USR_BIN) 477 APPLET(wget, wget_main, _BB_DIR_USR_BIN)
478#endif 478#endif
479#ifdef BB_WHICH 479#ifdef CONFIG_WHICH
480 APPLET(which, which_main, _BB_DIR_USR_BIN) 480 APPLET(which, which_main, _BB_DIR_USR_BIN)
481#endif 481#endif
482#ifdef BB_WHOAMI 482#ifdef CONFIG_WHOAMI
483 APPLET(whoami, whoami_main, _BB_DIR_USR_BIN) 483 APPLET(whoami, whoami_main, _BB_DIR_USR_BIN)
484#endif 484#endif
485#ifdef BB_XARGS 485#ifdef CONFIG_XARGS
486 APPLET(xargs, xargs_main, _BB_DIR_USR_BIN) 486 APPLET(xargs, xargs_main, _BB_DIR_USR_BIN)
487#endif 487#endif
488#ifdef BB_YES 488#ifdef CONFIG_YES
489 APPLET(yes, yes_main, _BB_DIR_USR_BIN) 489 APPLET(yes, yes_main, _BB_DIR_USR_BIN)
490#endif 490#endif
491#ifdef BB_GUNZIP 491#ifdef CONFIG_GUNZIP
492 APPLET(zcat, gunzip_main, _BB_DIR_BIN) 492 APPLET(zcat, gunzip_main, _BB_DIR_BIN)
493#endif 493#endif
494 494
diff --git a/include/busybox.h b/include/busybox.h
index f79dac8c8..87cebc3d1 100644
--- a/include/busybox.h
+++ b/include/busybox.h
@@ -24,7 +24,7 @@
24#ifndef _BB_INTERNAL_H_ 24#ifndef _BB_INTERNAL_H_
25#define _BB_INTERNAL_H_ 1 25#define _BB_INTERNAL_H_ 1
26 26
27#include "Config.h" 27#include "config.h"
28 28
29#include <stdio.h> 29#include <stdio.h>
30#include <stdarg.h> 30#include <stdarg.h>
@@ -34,7 +34,7 @@
34#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")" 34#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")"
35 35
36#ifdef DMALLOC 36#ifdef DMALLOC
37#include "dmalloc.h" 37#include <dmalloc.h>
38#endif 38#endif
39 39
40#include <features.h> 40#include <features.h>
@@ -66,19 +66,19 @@ extern const struct BB_applet applets[];
66#include "applets.h" 66#include "applets.h"
67#undef PROTOTYPES 67#undef PROTOTYPES
68 68
69#ifdef BB_FEATURE_BUFFERS_GO_ON_STACK 69#ifdef CONFIG_FEATURE_BUFFERS_GO_ON_STACK
70#define RESERVE_BB_BUFFER(buffer,len) char buffer[len] 70#define RESERVE_CONFIG_BUFFER(buffer,len) char buffer[len]
71#define RESERVE_BB_UBUFFER(buffer,len) unsigned char buffer[len] 71#define RESERVE_CONFIG_UBUFFER(buffer,len) unsigned char buffer[len]
72#define RELEASE_BB_BUFFER(buffer) ((void)0) 72#define RELEASE_CONFIG_BUFFER(buffer) ((void)0)
73#else 73#else
74#ifdef BB_FEATURE_BUFFERS_GO_IN_BSS 74#ifdef CONFIG_FEATURE_BUFFERS_GO_IN_BSS
75#define RESERVE_BB_BUFFER(buffer,len) static char buffer[len] 75#define RESERVE_CONFIG_BUFFER(buffer,len) static char buffer[len]
76#define RESERVE_BB_UBUFFER(buffer,len) static unsigned char buffer[len] 76#define RESERVE_CONFIG_UBUFFER(buffer,len) static unsigned char buffer[len]
77#define RELEASE_BB_BUFFER(buffer) ((void)0) 77#define RELEASE_CONFIG_BUFFER(buffer) ((void)0)
78#else 78#else
79#define RESERVE_BB_BUFFER(buffer,len) char *buffer=xmalloc(len) 79#define RESERVE_CONFIG_BUFFER(buffer,len) char *buffer=xmalloc(len)
80#define RESERVE_BB_UBUFFER(buffer,len) unsigned char *buffer=xmalloc(len) 80#define RESERVE_CONFIG_UBUFFER(buffer,len) unsigned char *buffer=xmalloc(len)
81#define RELEASE_BB_BUFFER(buffer) free (buffer) 81#define RELEASE_CONFIG_BUFFER(buffer) free (buffer)
82#endif 82#endif
83#endif 83#endif
84 84
@@ -99,7 +99,7 @@ extern const struct BB_applet applets[];
99 99
100 100
101/* Pull in the utility routines from libbb */ 101/* Pull in the utility routines from libbb */
102#include "libbb/libbb.h" 102#include "libbb.h"
103 103
104 104
105 105
diff --git a/include/grp.h b/include/grp.h
index 87d4115ce..191c2d4e5 100644
--- a/include/grp.h
+++ b/include/grp.h
@@ -1,5 +1,5 @@
1#ifndef __BB_GRP_H 1#ifndef __CONFIG_GRP_H
2#define __BB_GRP_H 2#define __CONFIG_GRP_H
3 3
4#if defined USE_SYSTEM_PWD_GRP 4#if defined USE_SYSTEM_PWD_GRP
5#include <grp.h> 5#include <grp.h>
@@ -33,5 +33,5 @@ extern int initgroups __P ((__const char * user, gid_t gid));
33extern struct group * __getgrent __P ((int grp_fd)); 33extern struct group * __getgrent __P ((int grp_fd));
34 34
35#endif /* USE_SYSTEM_PWD_GRP */ 35#endif /* USE_SYSTEM_PWD_GRP */
36#endif /* __BB_GRP_H */ 36#endif /* __CONFIG_GRP_H */
37 37
diff --git a/include/libbb.h b/include/libbb.h
index 3ef0278f8..8b84077d8 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -21,8 +21,8 @@
21 * Permission has been granted to redistribute this code under the GPL. 21 * Permission has been granted to redistribute this code under the GPL.
22 * 22 *
23 */ 23 */
24#ifndef __LIBBB_H__ 24#ifndef __LIBCONFIG_H__
25#define __LIBBB_H__ 1 25#define __LIBCONFIG_H__ 1
26 26
27#include <stdio.h> 27#include <stdio.h>
28#include <stdarg.h> 28#include <stdarg.h>
@@ -32,15 +32,11 @@
32#include <netdb.h> 32#include <netdb.h>
33 33
34#ifdef DMALLOC 34#ifdef DMALLOC
35#include "dmalloc.h" 35#include <dmalloc.h>
36#endif 36#endif
37 37
38#include <features.h> 38#include <features.h>
39 39
40#ifndef _BB_INTERNAL_H_
41#include "../busybox.h"
42#endif
43
44#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__) 40#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__)
45/* libc5 doesn't define socklen_t */ 41/* libc5 doesn't define socklen_t */
46typedef unsigned int socklen_t; 42typedef unsigned int socklen_t;
@@ -295,7 +291,7 @@ extern const char * const name_longer_than_foo;
295extern const char * const unknown; 291extern const char * const unknown;
296extern const char * const can_not_create_raw_socket; 292extern const char * const can_not_create_raw_socket;
297 293
298#ifdef BB_FEATURE_DEVFS 294#ifdef CONFIG_FEATURE_DEVFS
299# define CURRENT_VC "/dev/vc/0" 295# define CURRENT_VC "/dev/vc/0"
300# define VC_1 "/dev/vc/1" 296# define VC_1 "/dev/vc/1"
301# define VC_2 "/dev/vc/2" 297# define VC_2 "/dev/vc/2"
@@ -323,4 +319,4 @@ extern const char * const can_not_create_raw_socket;
323#define CURRENT_TTY "/dev/tty" 319#define CURRENT_TTY "/dev/tty"
324#define CONSOLE_DEV "/dev/console" 320#define CONSOLE_DEV "/dev/console"
325 321
326#endif /* __LIBBB_H__ */ 322#endif /* __LIBCONFIG_H__ */
diff --git a/include/pwd.h b/include/pwd.h
index e603a96e3..2fd0ab06e 100644
--- a/include/pwd.h
+++ b/include/pwd.h
@@ -1,5 +1,5 @@
1#ifndef __BB_PWD_H 1#ifndef __CONFIG_PWD_H
2#define __BB_PWD_H 2#define __CONFIG_PWD_H
3 3
4#if defined USE_SYSTEM_PWD_GRP 4#if defined USE_SYSTEM_PWD_GRP
5#include <pwd.h> 5#include <pwd.h>
@@ -36,5 +36,5 @@ extern struct passwd * getpwnam __P ((__const char *));
36extern struct passwd * __getpwent __P ((__const int passwd_fd)); 36extern struct passwd * __getpwent __P ((__const int passwd_fd));
37 37
38#endif /* USE_SYSTEM_PWD_GRP */ 38#endif /* USE_SYSTEM_PWD_GRP */
39#endif /* __BB_PWD_H */ 39#endif /* __CONFIG_PWD_H */
40 40
diff --git a/include/usage.h b/include/usage.h
index 5e514274a..1de29666e 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -247,7 +247,7 @@
247#define deluser_full_usage \ 247#define deluser_full_usage \
248 "Deletes user USER from the system" 248 "Deletes user USER from the system"
249 249
250#ifdef BB_FEATURE_HUMAN_READABLE 250#ifdef CONFIG_FEATURE_HUMAN_READABLE
251 #define USAGE_HUMAN_READABLE(a) a 251 #define USAGE_HUMAN_READABLE(a) a
252 #define USAGE_NOT_HUMAN_READABLE(a) 252 #define USAGE_NOT_HUMAN_READABLE(a)
253#else 253#else
@@ -464,17 +464,17 @@
464#define fdflush_full_usage \ 464#define fdflush_full_usage \
465 "Forces floppy disk drive to detect disk change" 465 "Forces floppy disk drive to detect disk change"
466 466
467#ifdef BB_FEATURE_FIND_TYPE 467#ifdef CONFIG_FEATURE_FIND_TYPE
468 #define USAGE_FIND_TYPE(a) a 468 #define USAGE_FIND_TYPE(a) a
469#else 469#else
470 #define USAGE_FIND_TYPE(a) 470 #define USAGE_FIND_TYPE(a)
471#endif 471#endif
472#ifdef BB_FEATURE_FIND_PERM 472#ifdef CONFIG_FEATURE_FIND_PERM
473 #define USAGE_FIND_PERM(a) a 473 #define USAGE_FIND_PERM(a) a
474#else 474#else
475 #define USAGE_FIND_PERM(a) 475 #define USAGE_FIND_PERM(a)
476#endif 476#endif
477#ifdef BB_FEATURE_FIND_MTIME 477#ifdef CONFIG_FEATURE_FIND_MTIME
478 #define USAGE_FIND_MTIME(a) a 478 #define USAGE_FIND_MTIME(a) a
479#else 479#else
480 #define USAGE_FIND_MTIME(a) 480 #define USAGE_FIND_MTIME(a)
@@ -678,22 +678,22 @@
678 "$ id\n" \ 678 "$ id\n" \
679 "uid=1000(andersen) gid=1000(andersen)\n" 679 "uid=1000(andersen) gid=1000(andersen)\n"
680 680
681#ifdef BB_FEATURE_IFCONFIG_SLIP 681#ifdef CONFIG_FEATURE_IFCONFIG_SLIP
682 #define USAGE_SIOCSKEEPALIVE(a) a 682 #define USAGE_SIOCSKEEPALIVE(a) a
683#else 683#else
684 #define USAGE_SIOCSKEEPALIVE(a) 684 #define USAGE_SIOCSKEEPALIVE(a)
685#endif 685#endif
686#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 686#ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
687 #define USAGE_IFCONFIG_MII(a) a 687 #define USAGE_IFCONFIG_MII(a) a
688#else 688#else
689 #define USAGE_IFCONFIG_MII(a) 689 #define USAGE_IFCONFIG_MII(a)
690#endif 690#endif
691#ifdef BB_FEATURE_IFCONFIG_HW 691#ifdef CONFIG_FEATURE_IFCONFIG_HW
692 #define USAGE_IFCONFIG_HW(a) a 692 #define USAGE_IFCONFIG_HW(a) a
693#else 693#else
694 #define USAGE_IFCONFIG_HW(a) 694 #define USAGE_IFCONFIG_HW(a)
695#endif 695#endif
696#ifdef BB_FEATURE_IFCONFIG_STATUS 696#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
697 #define USAGE_IFCONFIG_OPT_A(a) a 697 #define USAGE_IFCONFIG_OPT_A(a) a
698#else 698#else
699 #define USAGE_IFCONFIG_OPT_A(a) 699 #define USAGE_IFCONFIG_OPT_A(a)
@@ -950,32 +950,32 @@
950#define logread_full_usage \ 950#define logread_full_usage \
951 "Shows the messages from syslogd (using circular buffer)." 951 "Shows the messages from syslogd (using circular buffer)."
952 952
953#ifdef BB_FEATURE_LS_TIMESTAMPS 953#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
954 #define USAGE_LS_TIMESTAMPS(a) a 954 #define USAGE_LS_TIMESTAMPS(a) a
955#else 955#else
956 #define USAGE_LS_TIMESTAMPS(a) 956 #define USAGE_LS_TIMESTAMPS(a)
957#endif 957#endif
958#ifdef BB_FEATURE_LS_FILETYPES 958#ifdef CONFIG_FEATURE_LS_FILETYPES
959 #define USAGE_LS_FILETYPES(a) a 959 #define USAGE_LS_FILETYPES(a) a
960#else 960#else
961 #define USAGE_LS_FILETYPES(a) 961 #define USAGE_LS_FILETYPES(a)
962#endif 962#endif
963#ifdef BB_FEATURE_LS_FOLLOWLINKS 963#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
964 #define USAGE_LS_FOLLOWLINKS(a) a 964 #define USAGE_LS_FOLLOWLINKS(a) a
965#else 965#else
966 #define USAGE_LS_FOLLOWLINKS(a) 966 #define USAGE_LS_FOLLOWLINKS(a)
967#endif 967#endif
968#ifdef BB_FEATURE_LS_RECURSIVE 968#ifdef CONFIG_FEATURE_LS_RECURSIVE
969 #define USAGE_LS_RECURSIVE(a) a 969 #define USAGE_LS_RECURSIVE(a) a
970#else 970#else
971 #define USAGE_LS_RECURSIVE(a) 971 #define USAGE_LS_RECURSIVE(a)
972#endif 972#endif
973#ifdef BB_FEATURE_LS_SORTFILES 973#ifdef CONFIG_FEATURE_LS_SORTFILES
974 #define USAGE_LS_SORTFILES(a) a 974 #define USAGE_LS_SORTFILES(a) a
975#else 975#else
976 #define USAGE_LS_SORTFILES(a) 976 #define USAGE_LS_SORTFILES(a)
977#endif 977#endif
978#ifdef BB_FEATURE_AUTOWIDTH 978#ifdef CONFIG_FEATURE_AUTOWIDTH
979 #define USAGE_AUTOWIDTH(a) a 979 #define USAGE_AUTOWIDTH(a) a
980#else 980#else
981 #define USAGE_AUTOWIDTH(a) 981 #define USAGE_AUTOWIDTH(a)
@@ -1145,12 +1145,12 @@
1145#define more_example_usage \ 1145#define more_example_usage \
1146 "$ dmesg | more\n" 1146 "$ dmesg | more\n"
1147 1147
1148#ifdef BB_FEATURE_MOUNT_LOOP 1148#ifdef CONFIG_FEATURE_MOUNT_LOOP
1149 #define USAGE_MOUNT_LOOP(a) a 1149 #define USAGE_MOUNT_LOOP(a) a
1150#else 1150#else
1151 #define USAGE_MOUNT_LOOP(a) 1151 #define USAGE_MOUNT_LOOP(a)
1152#endif 1152#endif
1153#ifdef BB_FEATURE_MTAB_SUPPORT 1153#ifdef CONFIG_FEATURE_MTAB_SUPPORT
1154 #define USAGE_MTAB(a) a 1154 #define USAGE_MTAB(a) a
1155#else 1155#else
1156 #define USAGE_MTAB(a) 1156 #define USAGE_MTAB(a)
@@ -1245,7 +1245,7 @@
1245 "$ pidof init\n" \ 1245 "$ pidof init\n" \
1246 "1\n" 1246 "1\n"
1247 1247
1248#ifndef BB_FEATURE_FANCY_PING 1248#ifndef CONFIG_FEATURE_FANCY_PING
1249#define ping_trivial_usage "host" 1249#define ping_trivial_usage "host"
1250#define ping_full_usage "Send ICMP ECHO_REQUEST packets to network hosts" 1250#define ping_full_usage "Send ICMP ECHO_REQUEST packets to network hosts"
1251#else 1251#else
@@ -1431,12 +1431,12 @@
1431 "[2 second delay results]\n" 1431 "[2 second delay results]\n"
1432 1432
1433 1433
1434#ifdef BB_FEATURE_SORT_UNIQUE 1434#ifdef CONFIG_FEATURE_SORT_UNIQUE
1435 #define USAGE_SORT_UNIQUE(a) a 1435 #define USAGE_SORT_UNIQUE(a) a
1436#else 1436#else
1437 #define USAGE_SORT_UNIQUE(a) 1437 #define USAGE_SORT_UNIQUE(a)
1438#endif 1438#endif
1439#ifdef BB_FEATURE_SORT_REVERSE 1439#ifdef CONFIG_FEATURE_SORT_REVERSE
1440 #define USAGE_SORT_REVERSE(a) a 1440 #define USAGE_SORT_REVERSE(a) a
1441#else 1441#else
1442 #define USAGE_SORT_REVERSE(a) 1442 #define USAGE_SORT_REVERSE(a)
@@ -1503,7 +1503,7 @@
1503 "Write all buffered filesystem blocks to disk." 1503 "Write all buffered filesystem blocks to disk."
1504 1504
1505 1505
1506#ifdef BB_FEATURE_REMOTE_LOG 1506#ifdef CONFIG_FEATURE_REMOTE_LOG
1507 #define USAGE_REMOTE_LOG(a) a 1507 #define USAGE_REMOTE_LOG(a) a
1508#else 1508#else
1509 #define USAGE_REMOTE_LOG(a) 1509 #define USAGE_REMOTE_LOG(a)
@@ -1525,7 +1525,7 @@
1525 "$ syslogd -R 192.168.1.1:601\n" 1525 "$ syslogd -R 192.168.1.1:601\n"
1526 1526
1527 1527
1528#ifndef BB_FEATURE_FANCY_TAIL 1528#ifndef CONFIG_FEATURE_FANCY_TAIL
1529 #define USAGE_UNSIMPLE_TAIL(a) 1529 #define USAGE_UNSIMPLE_TAIL(a)
1530#else 1530#else
1531 #define USAGE_UNSIMPLE_TAIL(a) a 1531 #define USAGE_UNSIMPLE_TAIL(a) a
@@ -1550,12 +1550,12 @@
1550 "$ tail -n 1 /etc/resolv.conf\n" \ 1550 "$ tail -n 1 /etc/resolv.conf\n" \
1551 "nameserver 10.0.0.1\n" 1551 "nameserver 10.0.0.1\n"
1552 1552
1553#ifdef BB_FEATURE_TAR_CREATE 1553#ifdef CONFIG_FEATURE_TAR_CREATE
1554 #define USAGE_TAR_CREATE(a) a 1554 #define USAGE_TAR_CREATE(a) a
1555#else 1555#else
1556 #define USAGE_TAR_CREATE(a) 1556 #define USAGE_TAR_CREATE(a)
1557#endif 1557#endif
1558#ifdef BB_FEATURE_TAR_EXCLUDE 1558#ifdef CONFIG_FEATURE_TAR_EXCLUDE
1559 #define USAGE_TAR_EXCLUDE(a) a 1559 #define USAGE_TAR_EXCLUDE(a) a
1560#else 1560#else
1561 #define USAGE_TAR_EXCLUDE(a) 1561 #define USAGE_TAR_EXCLUDE(a)
@@ -1619,17 +1619,17 @@
1619 "$ echo $?\n" \ 1619 "$ echo $?\n" \
1620 "1\n" 1620 "1\n"
1621 1621
1622#ifdef BB_FEATURE_TFTP_GET 1622#ifdef CONFIG_FEATURE_TFTP_GET
1623 #define USAGE_TFTP_GET(a) a 1623 #define USAGE_TFTP_GET(a) a
1624#else 1624#else
1625 #define USAGE_TFTP_GET(a) 1625 #define USAGE_TFTP_GET(a)
1626#endif 1626#endif
1627#ifdef BB_FEATURE_TFTP_PUT 1627#ifdef CONFIG_FEATURE_TFTP_PUT
1628 #define USAGE_TFTP_PUT(a) a 1628 #define USAGE_TFTP_PUT(a) a
1629#else 1629#else
1630 #define USAGE_TFTP_PUT(a) 1630 #define USAGE_TFTP_PUT(a)
1631#endif 1631#endif
1632#ifdef BB_FEATURE_TFTP_BLOCKSIZE 1632#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
1633 #define USAGE_TFTP_BS(a) a 1633 #define USAGE_TFTP_BS(a) a
1634#else 1634#else
1635 #define USAGE_TFTP_BS(a) 1635 #define USAGE_TFTP_BS(a)
@@ -1719,7 +1719,7 @@
1719 "$ tty\n" \ 1719 "$ tty\n" \
1720 "/dev/tty2\n" 1720 "/dev/tty2\n"
1721 1721
1722#ifdef BB_FEATURE_MOUNT_FORCE 1722#ifdef CONFIG_FEATURE_MOUNT_FORCE
1723 #define USAGE_MOUNT_FORCE(a) a 1723 #define USAGE_MOUNT_FORCE(a) a
1724#else 1724#else
1725 #define USAGE_MOUNT_FORCE(a) 1725 #define USAGE_MOUNT_FORCE(a)
diff --git a/init.c b/init.c
deleted file mode 100644
index 068e1df16..000000000
--- a/init.c
+++ /dev/null
@@ -1,1045 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini init implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 * Adjusted by so many folks, it's impossible to keep track.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25/* Turn this on to disable all the dangerous
26 rebooting stuff when debugging.
27#define DEBUG_INIT
28*/
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <errno.h>
33#include <paths.h>
34#include <signal.h>
35#include <stdarg.h>
36#include <string.h>
37#include <termios.h>
38#include <unistd.h>
39#include <limits.h>
40#include <sys/fcntl.h>
41#include <sys/ioctl.h>
42#include <sys/mount.h>
43#include <sys/types.h>
44#include <sys/wait.h>
45#include "busybox.h"
46#ifdef BB_SYSLOGD
47# include <sys/syslog.h>
48#endif
49
50
51/* From <linux/vt.h> */
52struct vt_stat {
53 unsigned short v_active; /* active vt */
54 unsigned short v_signal; /* signal to send */
55 unsigned short v_state; /* vt bitmask */
56};
57static const int VT_GETSTATE = 0x5603; /* get global vt state info */
58
59/* From <linux/serial.h> */
60struct serial_struct {
61 int type;
62 int line;
63 int port;
64 int irq;
65 int flags;
66 int xmit_fifo_size;
67 int custom_divisor;
68 int baud_base;
69 unsigned short close_delay;
70 char reserved_char[2];
71 int hub6;
72 unsigned short closing_wait; /* time to wait before closing */
73 unsigned short closing_wait2; /* no longer used... */
74 int reserved[4];
75};
76
77
78
79#ifndef RB_HALT_SYSTEM
80static const int RB_HALT_SYSTEM = 0xcdef0123;
81static const int RB_ENABLE_CAD = 0x89abcdef;
82static const int RB_DISABLE_CAD = 0;
83#define RB_POWER_OFF 0x4321fedc
84static const int RB_AUTOBOOT = 0x01234567;
85#endif
86
87#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__)
88 #include <sys/reboot.h>
89 #define init_reboot(magic) reboot(magic)
90#else
91 #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic)
92#endif
93
94#ifndef _PATH_STDPATH
95#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
96#endif
97
98
99#if defined BB_FEATURE_INIT_COREDUMPS
100/*
101 * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called
102 * before processes are spawned to set core file size as unlimited.
103 * This is for debugging only. Don't use this is production, unless
104 * you want core dumps lying about....
105 */
106#define CORE_ENABLE_FLAG_FILE "/.init_enable_core"
107#include <sys/resource.h>
108#include <sys/time.h>
109#endif
110
111#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
112
113#if __GNU_LIBRARY__ > 5
114 #include <sys/kdaemon.h>
115#else
116 extern int bdflush (int func, long int data);
117#endif
118
119
120#define SHELL "/bin/sh" /* Default shell */
121#define LOGIN_SHELL "-" SHELL /* Default login shell */
122#define INITTAB "/etc/inittab" /* inittab file location */
123#ifndef INIT_SCRIPT
124#define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */
125#endif
126
127#define MAXENV 16 /* Number of env. vars */
128//static const int MAXENV = 16; /* Number of env. vars */
129static const int LOG = 0x1;
130static const int CONSOLE = 0x2;
131
132/* Allowed init action types */
133typedef enum {
134 SYSINIT = 1,
135 RESPAWN,
136 ASKFIRST,
137 WAIT,
138 ONCE,
139 CTRLALTDEL,
140 SHUTDOWN
141} initActionEnum;
142
143/* A mapping between "inittab" action name strings and action type codes. */
144typedef struct initActionType {
145 const char *name;
146 initActionEnum action;
147} initActionType;
148
149static const struct initActionType actions[] = {
150 {"sysinit", SYSINIT},
151 {"respawn", RESPAWN},
152 {"askfirst", ASKFIRST},
153 {"wait", WAIT},
154 {"once", ONCE},
155 {"ctrlaltdel", CTRLALTDEL},
156 {"shutdown", SHUTDOWN},
157 {0, 0}
158};
159
160/* Set up a linked list of initActions, to be read from inittab */
161typedef struct initActionTag initAction;
162struct initActionTag {
163 pid_t pid;
164 char process[256];
165 char console[256];
166 initAction *nextPtr;
167 initActionEnum action;
168};
169static initAction *initActionList = NULL;
170
171
172static char *secondConsole = VC_2;
173static char *thirdConsole = VC_3;
174static char *fourthConsole = VC_4;
175static char *log = VC_5;
176static int kernelVersion = 0;
177static char termType[32] = "TERM=linux";
178static char console[32] = _PATH_CONSOLE;
179
180static void delete_initAction(initAction * action);
181
182static void loop_forever(void)
183{
184 while (1)
185 sleep (1);
186}
187
188/* Print a message to the specified device.
189 * Device may be bitwise-or'd from LOG | CONSOLE */
190static void message(int device, char *fmt, ...)
191 __attribute__ ((format (printf, 2, 3)));
192static void message(int device, char *fmt, ...)
193{
194 va_list arguments;
195 int fd;
196
197#ifdef BB_SYSLOGD
198
199 /* Log the message to syslogd */
200 if (device & LOG) {
201 char msg[1024];
202
203 va_start(arguments, fmt);
204 vsnprintf(msg, sizeof(msg), fmt, arguments);
205 va_end(arguments);
206 syslog_msg(LOG_USER, LOG_USER|LOG_INFO, msg);
207 }
208#else
209 static int log_fd = -1;
210
211 /* Take full control of the log tty, and never close it.
212 * It's mine, all mine! Muhahahaha! */
213 if (log_fd < 0) {
214 if (log == NULL) {
215 /* don't even try to log, because there is no such console */
216 log_fd = -2;
217 /* log to main console instead */
218 device = CONSOLE;
219 } else if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) {
220 log_fd = -2;
221 fprintf(stderr, "Bummer, can't write to log on %s!\r\n", log);
222 log = NULL;
223 device = CONSOLE;
224 }
225 }
226 if ((device & LOG) && (log_fd >= 0)) {
227 va_start(arguments, fmt);
228 vdprintf(log_fd, fmt, arguments);
229 va_end(arguments);
230 }
231#endif
232
233 if (device & CONSOLE) {
234 /* Always send console messages to /dev/console so people will see them. */
235 if (
236 (fd =
237 device_open(_PATH_CONSOLE,
238 O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) {
239 va_start(arguments, fmt);
240 vdprintf(fd, fmt, arguments);
241 va_end(arguments);
242 close(fd);
243 } else {
244 fprintf(stderr, "Bummer, can't print: ");
245 va_start(arguments, fmt);
246 vfprintf(stderr, fmt, arguments);
247 va_end(arguments);
248 }
249 }
250}
251
252/* Set terminal settings to reasonable defaults */
253static void set_term(int fd)
254{
255 struct termios tty;
256
257 tcgetattr(fd, &tty);
258
259 /* set control chars */
260 tty.c_cc[VINTR] = 3; /* C-c */
261 tty.c_cc[VQUIT] = 28; /* C-\ */
262 tty.c_cc[VERASE] = 127; /* C-? */
263 tty.c_cc[VKILL] = 21; /* C-u */
264 tty.c_cc[VEOF] = 4; /* C-d */
265 tty.c_cc[VSTART] = 17; /* C-q */
266 tty.c_cc[VSTOP] = 19; /* C-s */
267 tty.c_cc[VSUSP] = 26; /* C-z */
268
269 /* use line dicipline 0 */
270 tty.c_line = 0;
271
272 /* Make it be sane */
273 tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
274 tty.c_cflag |= CREAD|HUPCL|CLOCAL;
275
276
277 /* input modes */
278 tty.c_iflag = ICRNL | IXON | IXOFF;
279
280 /* output modes */
281 tty.c_oflag = OPOST | ONLCR;
282
283 /* local modes */
284 tty.c_lflag =
285 ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
286
287 tcsetattr(fd, TCSANOW, &tty);
288}
289
290/* How much memory does this machine have?
291 Units are kBytes to avoid overflow on 4GB machines */
292static int check_free_memory(void)
293{
294 struct sysinfo info;
295 unsigned int result, u, s=10;
296
297 if (sysinfo(&info) != 0) {
298 perror_msg("Error checking free memory");
299 return -1;
300 }
301
302 /* Kernels 2.0.x and 2.2.x return info.mem_unit==0 with values in bytes.
303 * Kernels 2.4.0 return info.mem_unit in bytes. */
304 u = info.mem_unit;
305 if (u==0) u=1;
306 while ( (u&1) == 0 && s > 0 ) { u>>=1; s--; }
307 result = (info.totalram>>s) + (info.totalswap>>s);
308 result = result*u;
309 if (result < 0) result = INT_MAX;
310 return result;
311}
312
313static void console_init(void)
314{
315 int fd;
316 int tried_devcons = 0;
317 int tried_vtprimary = 0;
318 struct vt_stat vt;
319 struct serial_struct sr;
320 char *s;
321
322 if ((s = getenv("TERM")) != NULL) {
323 snprintf(termType, sizeof(termType) - 1, "TERM=%s", s);
324 }
325
326 if ((s = getenv("CONSOLE")) != NULL) {
327 safe_strncpy(console, s, sizeof(console));
328 }
329#if #cpu(sparc)
330 /* sparc kernel supports console=tty[ab] parameter which is also
331 * passed to init, so catch it here */
332 else if ((s = getenv("console")) != NULL) {
333 /* remap tty[ab] to /dev/ttyS[01] */
334 if (strcmp(s, "ttya") == 0)
335 safe_strncpy(console, SC_0, sizeof(console));
336 else if (strcmp(s, "ttyb") == 0)
337 safe_strncpy(console, SC_1, sizeof(console));
338 }
339#endif
340 else {
341 /* 2.2 kernels: identify the real console backend and try to use it */
342 if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
343 /* this is a serial console */
344 snprintf(console, sizeof(console) - 1, SC_FORMAT, sr.line);
345 } else if (ioctl(0, VT_GETSTATE, &vt) == 0) {
346 /* this is linux virtual tty */
347 snprintf(console, sizeof(console) - 1, VC_FORMAT, vt.v_active);
348 } else {
349 safe_strncpy(console, _PATH_CONSOLE, sizeof(console));
350 tried_devcons++;
351 }
352 }
353
354 while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) {
355 /* Can't open selected console -- try /dev/console */
356 if (!tried_devcons) {
357 tried_devcons++;
358 safe_strncpy(console, _PATH_CONSOLE, sizeof(console));
359 continue;
360 }
361 /* Can't open selected console -- try vt1 */
362 if (!tried_vtprimary) {
363 tried_vtprimary++;
364 safe_strncpy(console, VC_1, sizeof(console));
365 continue;
366 }
367 break;
368 }
369 if (fd < 0) {
370 /* Perhaps we should panic here? */
371 safe_strncpy(console, "/dev/null", sizeof(console));
372 } else {
373 /* check for serial console and disable logging to tty5 & running a
374 * shell to tty2-4 */
375 if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
376 log = NULL;
377 secondConsole = NULL;
378 thirdConsole = NULL;
379 fourthConsole = NULL;
380 /* Force the TERM setting to vt102 for serial console --
381 * iff TERM is set to linux (the default) */
382 if (strcmp( termType, "TERM=linux" ) == 0)
383 safe_strncpy(termType, "TERM=vt102", sizeof(termType));
384 message(LOG | CONSOLE,
385 "serial console detected. Disabling virtual terminals.\r\n");
386 }
387 close(fd);
388 }
389 message(LOG, "console=%s\n", console);
390}
391
392static void fixup_argv(int argc, char **argv, char *new_argv0)
393{
394 int len;
395 /* Fix up argv[0] to be certain we claim to be init */
396 len = strlen(argv[0]);
397 memset(argv[0], 0, len);
398 strncpy(argv[0], new_argv0, len);
399
400 /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
401 len = 1;
402 while (argc > len) {
403 memset(argv[len], 0, strlen(argv[len]));
404 len++;
405 }
406}
407
408
409static pid_t run(char *command, char *terminal, int get_enter)
410{
411 int i, j;
412 int fd;
413 pid_t pid;
414 char *tmpCmd, *s;
415 char *cmd[255], *cmdpath;
416 char buf[255];
417 struct stat sb;
418 static const char press_enter[] =
419
420#ifdef CUSTOMIZED_BANNER
421#include CUSTOMIZED_BANNER
422#endif
423
424 "\nPlease press Enter to activate this console. ";
425 char *environment[MAXENV+1] = {
426 termType,
427 "HOME=/",
428 "PATH=/usr/bin:/bin:/usr/sbin:/sbin",
429 "SHELL=" SHELL,
430 "USER=root",
431 NULL
432 };
433
434 /* inherit environment to the child, merging our values -andy */
435 for (i=0; environ[i]; i++) {
436 for (j=0; environment[j]; j++) {
437 s = strchr(environment[j], '=');
438 if (!strncmp(environ[i], environment[j], s - environment[j]))
439 break;
440 }
441 if (!environment[j]) {
442 environment[j++] = environ[i];
443 environment[j] = NULL;
444 }
445 }
446
447 if ((pid = fork()) == 0) {
448 /* Clean up */
449 ioctl(0, TIOCNOTTY, 0);
450 close(0);
451 close(1);
452 close(2);
453 setsid();
454
455 /* Reset signal handlers set for parent process */
456 signal(SIGUSR1, SIG_DFL);
457 signal(SIGUSR2, SIG_DFL);
458 signal(SIGINT, SIG_DFL);
459 signal(SIGTERM, SIG_DFL);
460 signal(SIGHUP, SIG_DFL);
461
462 if ((fd = device_open(terminal, O_RDWR)) < 0) {
463 if (stat(terminal, &sb) != 0) {
464 message(LOG | CONSOLE, "device '%s' does not exist.\n",
465 terminal);
466 exit(1);
467 }
468 message(LOG | CONSOLE, "Bummer, can't open %s\r\n", terminal);
469 exit(1);
470 }
471 dup2(fd, 0);
472 dup2(fd, 1);
473 dup2(fd, 2);
474 ioctl(0, TIOCSCTTY, 1);
475 tcsetpgrp(0, getpgrp());
476 set_term(0);
477
478 /* See if any special /bin/sh requiring characters are present */
479 if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
480 cmd[0] = SHELL;
481 cmd[1] = "-c";
482 strcpy(buf, "exec ");
483 strncat(buf, command, sizeof(buf) - strlen(buf) - 1);
484 cmd[2] = buf;
485 cmd[3] = NULL;
486 } else {
487 /* Convert command (char*) into cmd (char**, one word per string) */
488 for (tmpCmd = command, i = 0;
489 (tmpCmd = strsep(&command, " \t")) != NULL;) {
490 if (*tmpCmd != '\0') {
491 cmd[i] = tmpCmd;
492 tmpCmd++;
493 i++;
494 }
495 }
496 cmd[i] = NULL;
497 }
498
499 cmdpath = cmd[0];
500
501 /*
502 Interactive shells want to see a dash in argv[0]. This
503 typically is handled by login, argv will be setup this
504 way if a dash appears at the front of the command path
505 (like "-/bin/sh").
506 */
507
508 if (*cmdpath == '-') {
509
510 /* skip over the dash */
511 ++cmdpath;
512
513 /* find the last component in the command pathname */
514 s = get_last_path_component(cmdpath);
515
516 /* make a new argv[0] */
517 if ((cmd[0] = malloc(strlen(s)+2)) == NULL) {
518 message(LOG | CONSOLE, "malloc failed");
519 cmd[0] = cmdpath;
520 } else {
521 cmd[0][0] = '-';
522 strcpy(cmd[0]+1, s);
523 }
524 }
525
526 if (get_enter == TRUE) {
527 /*
528 * Save memory by not exec-ing anything large (like a shell)
529 * before the user wants it. This is critical if swap is not
530 * enabled and the system has low memory. Generally this will
531 * be run on the second virtual console, and the first will
532 * be allowed to start a shell or whatever an init script
533 * specifies.
534 */
535#ifdef DEBUG_INIT
536 message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n",
537 cmd[0], getpid(), terminal);
538#endif
539 write(fileno(stdout), press_enter, sizeof(press_enter) - 1);
540 getc(stdin);
541 }
542
543#ifdef DEBUG_INIT
544 /* Log the process name and args */
545 message(LOG, "Starting pid %d, console %s: '%s'\r\n",
546 getpid(), terminal, command);
547#endif
548
549#if defined BB_FEATURE_INIT_COREDUMPS
550 if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) {
551 struct rlimit limit;
552 limit.rlim_cur = RLIM_INFINITY;
553 limit.rlim_max = RLIM_INFINITY;
554 setrlimit(RLIMIT_CORE, &limit);
555 }
556#endif
557
558 /* Now run it. The new program will take over this PID,
559 * so nothing further in init.c should be run. */
560 execve(cmdpath, cmd, environment);
561
562 /* We're still here? Some error happened. */
563 message(LOG | CONSOLE, "Bummer, could not run '%s': %s\n", cmdpath,
564 strerror(errno));
565 exit(-1);
566 }
567 return pid;
568}
569
570static int waitfor(char *command, char *terminal, int get_enter)
571{
572 int status, wpid;
573 int pid = run(command, terminal, get_enter);
574
575 while (1) {
576 wpid = wait(&status);
577 if (wpid > 0 && wpid != pid) {
578 continue;
579 }
580 if (wpid == pid)
581 break;
582 }
583 return wpid;
584}
585
586/* Make sure there is enough memory to do something useful. *
587 * Calls "swapon -a" if needed so be sure /etc/fstab is present... */
588static void check_memory(void)
589{
590 struct stat statBuf;
591
592 if (check_free_memory() > 1000)
593 return;
594
595 if (stat("/etc/fstab", &statBuf) == 0) {
596 /* swapon -a requires /proc typically */
597 waitfor("mount proc /proc -t proc", console, FALSE);
598 /* Try to turn on swap */
599 waitfor("swapon -a", console, FALSE);
600 if (check_free_memory() < 1000)
601 goto goodnight;
602 } else
603 goto goodnight;
604 return;
605
606 goodnight:
607 message(CONSOLE,
608 "Sorry, your computer does not have enough memory.\r\n");
609 loop_forever();
610}
611
612/* Run all commands to be run right before halt/reboot */
613static void run_actions(initActionEnum action)
614{
615 initAction *a, *tmp;
616 for (a = initActionList; a; a = tmp) {
617 tmp = a->nextPtr;
618 if (a->action == action) {
619 waitfor(a->process, a->console, FALSE);
620 delete_initAction(a);
621 }
622 }
623}
624
625
626#ifndef DEBUG_INIT
627static void shutdown_system(void)
628{
629
630 /* first disable our SIGHUP signal */
631 signal(SIGHUP, SIG_DFL);
632
633 /* Allow Ctrl-Alt-Del to reboot system. */
634 init_reboot(RB_ENABLE_CAD);
635
636 message(CONSOLE|LOG, "\r\nThe system is going down NOW !!\r\n");
637 sync();
638
639 /* Send signals to every process _except_ pid 1 */
640 message(CONSOLE|LOG, "Sending SIGTERM to all processes.\r\n");
641 kill(-1, SIGTERM);
642 sleep(1);
643 sync();
644
645 message(CONSOLE|LOG, "Sending SIGKILL to all processes.\r\n");
646 kill(-1, SIGKILL);
647 sleep(1);
648
649 /* run everything to be run at "shutdown" */
650 run_actions(SHUTDOWN);
651
652 sync();
653 if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) {
654 /* bdflush, kupdate not needed for kernels >2.2.11 */
655 bdflush(1, 0);
656 sync();
657 }
658}
659
660static void halt_signal(int sig)
661{
662 shutdown_system();
663 message(CONSOLE|LOG,
664 "The system is halted. Press %s or turn off power\r\n",
665 (secondConsole == NULL) /* serial console */
666 ? "Reset" : "CTRL-ALT-DEL");
667 sync();
668
669 /* allow time for last message to reach serial console */
670 sleep(2);
671
672 if (sig == SIGUSR2 && kernelVersion >= KERNEL_VERSION(2,2,0))
673 init_reboot(RB_POWER_OFF);
674 else
675 init_reboot(RB_HALT_SYSTEM);
676
677 loop_forever();
678}
679
680static void reboot_signal(int sig)
681{
682 shutdown_system();
683 message(CONSOLE|LOG, "Please stand by while rebooting the system.\r\n");
684 sync();
685
686 /* allow time for last message to reach serial console */
687 sleep(2);
688
689 init_reboot(RB_AUTOBOOT);
690
691 loop_forever();
692}
693
694static void ctrlaltdel_signal(int sig)
695{
696 run_actions(CTRLALTDEL);
697}
698
699#endif /* ! DEBUG_INIT */
700
701static void new_initAction(initActionEnum action, char *process, char *cons)
702{
703 initAction *newAction;
704#ifdef BB_FEATURE_INIT_NORMAL_ORDER
705 initAction *a;
706#endif
707
708 if (*cons == '\0')
709 cons = console;
710
711 /* If BusyBox detects that a serial console is in use,
712 * then entries not refering to the console or null devices will _not_ be run.
713 * The exception to this rule is the null device.
714 */
715 if (secondConsole == NULL && strcmp(cons, console)
716 && strcmp(cons, "/dev/null"))
717 return;
718 if (strcmp(cons, "/dev/null") == 0 && action == ASKFIRST)
719 return;
720
721 newAction = calloc((size_t) (1), sizeof(initAction));
722 if (!newAction) {
723 message(LOG | CONSOLE, "Memory allocation failure\n");
724 loop_forever();
725 }
726#ifdef BB_FEATURE_INIT_NORMAL_ORDER
727 for (a = initActionList; a && a->nextPtr; a = a->nextPtr) ;
728 if (a) {
729 a->nextPtr = newAction;
730 } else {
731 initActionList = newAction;
732 }
733#else
734 newAction->nextPtr = initActionList;
735 initActionList = newAction;
736#endif
737 strncpy(newAction->process, process, 255);
738 newAction->action = action;
739 strncpy(newAction->console, cons, 255);
740 newAction->pid = 0;
741// message(LOG|CONSOLE, "process='%s' action='%d' console='%s'\n",
742// newAction->process, newAction->action, newAction->console);
743}
744
745static void delete_initAction(initAction * action)
746{
747 initAction *a, *b = NULL;
748
749 for (a = initActionList; a; b = a, a = a->nextPtr) {
750 if (a == action) {
751 if (b == NULL) {
752 initActionList = a->nextPtr;
753 } else {
754 b->nextPtr = a->nextPtr;
755 }
756 free(a);
757 break;
758 }
759 }
760}
761
762/* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
763 * then parse_inittab() simply adds in some default
764 * actions(i.e., runs INIT_SCRIPT and then starts a pair
765 * of "askfirst" shells). If BB_FEATURE_USE_INITTAB
766 * _is_ defined, but /etc/inittab is missing, this
767 * results in the same set of default behaviors.
768 * */
769static void parse_inittab(void)
770{
771#ifdef BB_FEATURE_USE_INITTAB
772 FILE *file;
773 char buf[256], lineAsRead[256], tmpConsole[256];
774 char *id, *runlev, *action, *process, *eol;
775 const struct initActionType *a = actions;
776 int foundIt;
777
778
779 file = fopen(INITTAB, "r");
780 if (file == NULL) {
781 /* No inittab file -- set up some default behavior */
782#endif
783 /* Reboot on Ctrl-Alt-Del */
784 new_initAction(CTRLALTDEL, "/sbin/reboot", console);
785#ifdef BB_FEATURE_INIT_NORMAL_ORDER
786 /* Umount all filesystems on halt/reboot */
787 new_initAction(SHUTDOWN, "/bin/umount -a -r", console);
788 /* Swapoff on halt/reboot */
789 new_initAction(SHUTDOWN, "/sbin/swapoff -a", console);
790#else
791 /* Swapoff on halt/reboot */
792 new_initAction(SHUTDOWN, "/sbin/swapoff -a", console);
793 /* Umount all filesystems on halt/reboot */
794 new_initAction(SHUTDOWN, "/bin/umount -a -r", console);
795#endif
796 /* Askfirst shell on tty1 */
797 new_initAction(ASKFIRST, LOGIN_SHELL, console);
798 /* Askfirst shell on tty2 */
799 if (secondConsole != NULL)
800 new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole);
801 /* Askfirst shell on tty3 */
802 if (thirdConsole != NULL)
803 new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole);
804 /* Askfirst shell on tty4 */
805 if (fourthConsole != NULL)
806 new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole);
807 /* sysinit */
808 new_initAction(SYSINIT, INIT_SCRIPT, console);
809
810 return;
811#ifdef BB_FEATURE_USE_INITTAB
812 }
813
814 while (fgets(buf, 255, file) != NULL) {
815 foundIt = FALSE;
816 /* Skip leading spaces */
817 for (id = buf; *id == ' ' || *id == '\t'; id++);
818
819 /* Skip the line if it's a comment */
820 if (*id == '#' || *id == '\n')
821 continue;
822
823 /* Trim the trailing \n */
824 eol = strrchr(id, '\n');
825 if (eol != NULL)
826 *eol = '\0';
827
828 /* Keep a copy around for posterity's sake (and error msgs) */
829 strcpy(lineAsRead, buf);
830
831 /* Separate the ID field from the runlevels */
832 runlev = strchr(id, ':');
833 if (runlev == NULL || *(runlev + 1) == '\0') {
834 message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
835 continue;
836 } else {
837 *runlev = '\0';
838 ++runlev;
839 }
840
841 /* Separate the runlevels from the action */
842 action = strchr(runlev, ':');
843 if (action == NULL || *(action + 1) == '\0') {
844 message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
845 continue;
846 } else {
847 *action = '\0';
848 ++action;
849 }
850
851 /* Separate the action from the process */
852 process = strchr(action, ':');
853 if (process == NULL || *(process + 1) == '\0') {
854 message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
855 continue;
856 } else {
857 *process = '\0';
858 ++process;
859 }
860
861 /* Ok, now process it */
862 a = actions;
863 while (a->name != 0) {
864 if (strcmp(a->name, action) == 0) {
865 if (*id != '\0') {
866 strcpy(tmpConsole, "/dev/");
867 strncat(tmpConsole, id, 200);
868 id = tmpConsole;
869 }
870 new_initAction(a->action, process, id);
871 foundIt = TRUE;
872 }
873 a++;
874 }
875 if (foundIt == TRUE)
876 continue;
877 else {
878 /* Choke on an unknown action */
879 message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
880 }
881 }
882 return;
883#endif /* BB_FEATURE_USE_INITTAB */
884}
885
886
887
888extern int init_main(int argc, char **argv)
889{
890 initAction *a, *tmp;
891 pid_t wpid;
892 int status;
893
894#ifndef DEBUG_INIT
895 /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
896 if (getpid() != 1
897#ifdef BB_FEATURE_LINUXRC
898 && strstr(applet_name, "linuxrc") == NULL
899#endif
900 )
901 {
902 show_usage();
903 }
904 /* Set up sig handlers -- be sure to
905 * clear all of these in run() */
906 signal(SIGUSR1, halt_signal);
907 signal(SIGUSR2, halt_signal);
908 signal(SIGINT, ctrlaltdel_signal);
909 signal(SIGTERM, reboot_signal);
910
911 /* Turn off rebooting via CTL-ALT-DEL -- we get a
912 * SIGINT on CAD so we can shut things down gracefully... */
913 init_reboot(RB_DISABLE_CAD);
914#endif
915
916 /* Figure out what kernel this is running */
917 kernelVersion = get_kernel_revision();
918
919 /* Figure out where the default console should be */
920 console_init();
921
922 /* Close whatever files are open, and reset the console. */
923 close(0);
924 close(1);
925 close(2);
926 set_term(0);
927 chdir("/");
928 setsid();
929
930 /* Make sure PATH is set to something sane */
931 putenv("PATH="_PATH_STDPATH);
932
933 /* Hello world */
934#ifndef DEBUG_INIT
935 message(
936#if ! defined BB_FEATURE_EXTRA_QUIET
937 CONSOLE|
938#endif
939 LOG,
940 "init started: %s\r\n", full_version);
941#else
942 message(
943#if ! defined BB_FEATURE_EXTRA_QUIET
944 CONSOLE|
945#endif
946 LOG,
947 "init(%d) started: %s\r\n", getpid(), full_version);
948#endif
949
950
951 /* Make sure there is enough memory to do something useful. */
952 check_memory();
953
954 /* Check if we are supposed to be in single user mode */
955 if (argc > 1 && (!strcmp(argv[1], "single") ||
956 !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) {
957 /* Ask first then start a shell on tty2-4 */
958 if (secondConsole != NULL)
959 new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole);
960 if (thirdConsole != NULL)
961 new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole);
962 if (fourthConsole != NULL)
963 new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole);
964 /* Start a shell on tty1 */
965 new_initAction(RESPAWN, LOGIN_SHELL, console);
966 } else {
967 /* Not in single user mode -- see what inittab says */
968
969 /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
970 * then parse_inittab() simply adds in some default
971 * actions(i.e., runs INIT_SCRIPT and then starts a pair
972 * of "askfirst" shells */
973 parse_inittab();
974 }
975
976 /* Make the command line just say "init" -- thats all, nothing else */
977 fixup_argv(argc, argv, "init");
978
979 /* Now run everything that needs to be run */
980
981 /* First run the sysinit command */
982 run_actions(SYSINIT);
983 /* Next run anything that wants to block */
984 run_actions(WAIT);
985 /* Next run anything to be run only once */
986 for (a = initActionList; a; a = tmp) {
987 tmp = a->nextPtr;
988 if (a->action == ONCE) {
989 run(a->process, a->console, FALSE);
990 /* Now remove the "once" entry from the list */
991 delete_initAction(a);
992 }
993 }
994 /* If there is nothing else to do, stop */
995 if (initActionList == NULL) {
996 message(LOG | CONSOLE,
997 "No more tasks for init -- sleeping forever.\n");
998 loop_forever();
999 }
1000
1001 /* Now run the looping stuff for the rest of forever */
1002 while (1) {
1003 for (a = initActionList; a; a = a->nextPtr) {
1004 /* Only run stuff with pid==0. If they have
1005 * a pid, that means they are still running */
1006 if (a->pid == 0) {
1007 switch (a->action) {
1008 case RESPAWN:
1009 /* run the respawn stuff */
1010 a->pid = run(a->process, a->console, FALSE);
1011 break;
1012 case ASKFIRST:
1013 /* run the askfirst stuff */
1014 a->pid = run(a->process, a->console, TRUE);
1015 break;
1016 /* silence the compiler's incessant whining */
1017 default:
1018 break;
1019 }
1020 }
1021 }
1022 /* Wait for a child process to exit */
1023 wpid = wait(&status);
1024 if (wpid > 0) {
1025 /* Find out who died and clean up their corpse */
1026 for (a = initActionList; a; a = a->nextPtr) {
1027 if (a->pid == wpid) {
1028 a->pid = 0;
1029 message(LOG,
1030 "Process '%s' (pid %d) exited. Scheduling it for restart.\n",
1031 a->process, wpid);
1032 }
1033 }
1034 }
1035 sleep(1);
1036 }
1037}
1038
1039/*
1040Local Variables:
1041c-file-style: "linux"
1042c-basic-offset: 4
1043tab-width: 4
1044End:
1045*/
diff --git a/init/Makefile b/init/Makefile
new file mode 100644
index 000000000..472fb02b1
--- /dev/null
+++ b/init/Makefile
@@ -0,0 +1,39 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := init.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27obj-$(CONFIG_HALT) += halt.o
28obj-$(CONFIG_INIT) += init.o
29obj-$(CONFIG_POWEROFF) += poweroff.o
30obj-$(CONFIG_REBOOT) += reboot.o
31obj-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o
32
33
34# Hand off to toplevel Rules.mak
35include $(TOPDIR)/Rules.mak
36
37clean:
38 rm -f $(L_TARGET) *.o core
39
diff --git a/init/config.in b/init/config.in
new file mode 100644
index 000000000..1d4760c2c
--- /dev/null
+++ b/init/config.in
@@ -0,0 +1,25 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Init Utilities'
8
9
10bool 'init' CONFIG_INIT
11if [ "$CONFIG_INIT" = "y" ]; then
12 bool ' Support reading an inittab file?' CONFIG_FEATURE_USE_INITTAB
13 bool ' Support running init from within an initrd?' CONFIG_FEATURE_INITRD
14 bool ' Support dumping core for child processes (debugging only)?' CONFIG_FEATURE_INIT_COREDUMPS
15 bool ' Should init be _extra_ quiet on boot?' CONFIG_FEATURE_EXTRA_QUIET
16
17 # Some more apps that are meaningless without BusyBox running as init
18 bool 'halt' CONFIG_HALT
19 bool 'poweroff' CONFIG_POWEROFF
20 bool 'reboot' CONFIG_REBOOT
21 bool 'start-stop-daemon' CONFIG_START_STOP_DAEMON
22fi
23
24endmenu
25
diff --git a/init/halt.c b/init/halt.c
index d66e28d0e..307c1022d 100644
--- a/init/halt.c
+++ b/init/halt.c
@@ -26,7 +26,7 @@
26 26
27extern int halt_main(int argc, char **argv) 27extern int halt_main(int argc, char **argv)
28{ 28{
29#ifdef BB_FEATURE_LINUXRC 29#ifdef CONFIG_FEATURE_INITRD
30 /* don't assume init's pid == 1 */ 30 /* don't assume init's pid == 1 */
31 pid_t *pid = find_pid_by_name("init"); 31 pid_t *pid = find_pid_by_name("init");
32 if (!pid || *pid<=0) { 32 if (!pid || *pid<=0) {
diff --git a/init/init.c b/init/init.c
index 068e1df16..b6eaa46ea 100644
--- a/init/init.c
+++ b/init/init.c
@@ -43,7 +43,7 @@
43#include <sys/types.h> 43#include <sys/types.h>
44#include <sys/wait.h> 44#include <sys/wait.h>
45#include "busybox.h" 45#include "busybox.h"
46#ifdef BB_SYSLOGD 46#ifdef CONFIG_SYSLOGD
47# include <sys/syslog.h> 47# include <sys/syslog.h>
48#endif 48#endif
49 49
@@ -96,7 +96,7 @@ static const int RB_AUTOBOOT = 0x01234567;
96#endif 96#endif
97 97
98 98
99#if defined BB_FEATURE_INIT_COREDUMPS 99#if defined CONFIG_FEATURE_INIT_COREDUMPS
100/* 100/*
101 * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called 101 * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called
102 * before processes are spawned to set core file size as unlimited. 102 * before processes are spawned to set core file size as unlimited.
@@ -194,7 +194,7 @@ static void message(int device, char *fmt, ...)
194 va_list arguments; 194 va_list arguments;
195 int fd; 195 int fd;
196 196
197#ifdef BB_SYSLOGD 197#ifdef CONFIG_SYSLOGD
198 198
199 /* Log the message to syslogd */ 199 /* Log the message to syslogd */
200 if (device & LOG) { 200 if (device & LOG) {
@@ -546,7 +546,7 @@ static pid_t run(char *command, char *terminal, int get_enter)
546 getpid(), terminal, command); 546 getpid(), terminal, command);
547#endif 547#endif
548 548
549#if defined BB_FEATURE_INIT_COREDUMPS 549#if defined CONFIG_FEATURE_INIT_COREDUMPS
550 if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) { 550 if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) {
551 struct rlimit limit; 551 struct rlimit limit;
552 limit.rlim_cur = RLIM_INFINITY; 552 limit.rlim_cur = RLIM_INFINITY;
@@ -701,7 +701,7 @@ static void ctrlaltdel_signal(int sig)
701static void new_initAction(initActionEnum action, char *process, char *cons) 701static void new_initAction(initActionEnum action, char *process, char *cons)
702{ 702{
703 initAction *newAction; 703 initAction *newAction;
704#ifdef BB_FEATURE_INIT_NORMAL_ORDER 704#ifdef CONFIG_FEATURE_INIT_NORMAL_ORDER
705 initAction *a; 705 initAction *a;
706#endif 706#endif
707 707
@@ -723,7 +723,7 @@ static void new_initAction(initActionEnum action, char *process, char *cons)
723 message(LOG | CONSOLE, "Memory allocation failure\n"); 723 message(LOG | CONSOLE, "Memory allocation failure\n");
724 loop_forever(); 724 loop_forever();
725 } 725 }
726#ifdef BB_FEATURE_INIT_NORMAL_ORDER 726#ifdef CONFIG_FEATURE_INIT_NORMAL_ORDER
727 for (a = initActionList; a && a->nextPtr; a = a->nextPtr) ; 727 for (a = initActionList; a && a->nextPtr; a = a->nextPtr) ;
728 if (a) { 728 if (a) {
729 a->nextPtr = newAction; 729 a->nextPtr = newAction;
@@ -759,16 +759,16 @@ static void delete_initAction(initAction * action)
759 } 759 }
760} 760}
761 761
762/* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, 762/* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
763 * then parse_inittab() simply adds in some default 763 * then parse_inittab() simply adds in some default
764 * actions(i.e., runs INIT_SCRIPT and then starts a pair 764 * actions(i.e., runs INIT_SCRIPT and then starts a pair
765 * of "askfirst" shells). If BB_FEATURE_USE_INITTAB 765 * of "askfirst" shells). If CONFIG_FEATURE_USE_INITTAB
766 * _is_ defined, but /etc/inittab is missing, this 766 * _is_ defined, but /etc/inittab is missing, this
767 * results in the same set of default behaviors. 767 * results in the same set of default behaviors.
768 * */ 768 * */
769static void parse_inittab(void) 769static void parse_inittab(void)
770{ 770{
771#ifdef BB_FEATURE_USE_INITTAB 771#ifdef CONFIG_FEATURE_USE_INITTAB
772 FILE *file; 772 FILE *file;
773 char buf[256], lineAsRead[256], tmpConsole[256]; 773 char buf[256], lineAsRead[256], tmpConsole[256];
774 char *id, *runlev, *action, *process, *eol; 774 char *id, *runlev, *action, *process, *eol;
@@ -782,7 +782,7 @@ static void parse_inittab(void)
782#endif 782#endif
783 /* Reboot on Ctrl-Alt-Del */ 783 /* Reboot on Ctrl-Alt-Del */
784 new_initAction(CTRLALTDEL, "/sbin/reboot", console); 784 new_initAction(CTRLALTDEL, "/sbin/reboot", console);
785#ifdef BB_FEATURE_INIT_NORMAL_ORDER 785#ifdef CONFIG_FEATURE_INIT_NORMAL_ORDER
786 /* Umount all filesystems on halt/reboot */ 786 /* Umount all filesystems on halt/reboot */
787 new_initAction(SHUTDOWN, "/bin/umount -a -r", console); 787 new_initAction(SHUTDOWN, "/bin/umount -a -r", console);
788 /* Swapoff on halt/reboot */ 788 /* Swapoff on halt/reboot */
@@ -808,7 +808,7 @@ static void parse_inittab(void)
808 new_initAction(SYSINIT, INIT_SCRIPT, console); 808 new_initAction(SYSINIT, INIT_SCRIPT, console);
809 809
810 return; 810 return;
811#ifdef BB_FEATURE_USE_INITTAB 811#ifdef CONFIG_FEATURE_USE_INITTAB
812 } 812 }
813 813
814 while (fgets(buf, 255, file) != NULL) { 814 while (fgets(buf, 255, file) != NULL) {
@@ -880,7 +880,7 @@ static void parse_inittab(void)
880 } 880 }
881 } 881 }
882 return; 882 return;
883#endif /* BB_FEATURE_USE_INITTAB */ 883#endif /* CONFIG_FEATURE_USE_INITTAB */
884} 884}
885 885
886 886
@@ -894,7 +894,7 @@ extern int init_main(int argc, char **argv)
894#ifndef DEBUG_INIT 894#ifndef DEBUG_INIT
895 /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ 895 /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
896 if (getpid() != 1 896 if (getpid() != 1
897#ifdef BB_FEATURE_LINUXRC 897#ifdef CONFIG_FEATURE_INITRD
898 && strstr(applet_name, "linuxrc") == NULL 898 && strstr(applet_name, "linuxrc") == NULL
899#endif 899#endif
900 ) 900 )
@@ -933,14 +933,14 @@ extern int init_main(int argc, char **argv)
933 /* Hello world */ 933 /* Hello world */
934#ifndef DEBUG_INIT 934#ifndef DEBUG_INIT
935 message( 935 message(
936#if ! defined BB_FEATURE_EXTRA_QUIET 936#if ! defined CONFIG_FEATURE_EXTRA_QUIET
937 CONSOLE| 937 CONSOLE|
938#endif 938#endif
939 LOG, 939 LOG,
940 "init started: %s\r\n", full_version); 940 "init started: %s\r\n", full_version);
941#else 941#else
942 message( 942 message(
943#if ! defined BB_FEATURE_EXTRA_QUIET 943#if ! defined CONFIG_FEATURE_EXTRA_QUIET
944 CONSOLE| 944 CONSOLE|
945#endif 945#endif
946 LOG, 946 LOG,
@@ -966,7 +966,7 @@ extern int init_main(int argc, char **argv)
966 } else { 966 } else {
967 /* Not in single user mode -- see what inittab says */ 967 /* Not in single user mode -- see what inittab says */
968 968
969 /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, 969 /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
970 * then parse_inittab() simply adds in some default 970 * then parse_inittab() simply adds in some default
971 * actions(i.e., runs INIT_SCRIPT and then starts a pair 971 * actions(i.e., runs INIT_SCRIPT and then starts a pair
972 * of "askfirst" shells */ 972 * of "askfirst" shells */
diff --git a/init/poweroff.c b/init/poweroff.c
index db20a4572..cec2d6ddd 100644
--- a/init/poweroff.c
+++ b/init/poweroff.c
@@ -26,7 +26,7 @@
26 26
27extern int poweroff_main(int argc, char **argv) 27extern int poweroff_main(int argc, char **argv)
28{ 28{
29#ifdef BB_FEATURE_LINUXRC 29#ifdef CONFIG_FEATURE_INITRD
30 /* don't assume init's pid == 1 */ 30 /* don't assume init's pid == 1 */
31 pid_t *pid = find_pid_by_name("init"); 31 pid_t *pid = find_pid_by_name("init");
32 if (!pid || *pid<=0) { 32 if (!pid || *pid<=0) {
diff --git a/init/reboot.c b/init/reboot.c
index 35afd74ff..a13d42492 100644
--- a/init/reboot.c
+++ b/init/reboot.c
@@ -26,7 +26,7 @@
26 26
27extern int reboot_main(int argc, char **argv) 27extern int reboot_main(int argc, char **argv)
28{ 28{
29#ifdef BB_FEATURE_LINUXRC 29#ifdef CONFIG_FEATURE_INITRD
30 /* don't assume init's pid == 1 */ 30 /* don't assume init's pid == 1 */
31 pid_t *pid = find_pid_by_name("init"); 31 pid_t *pid = find_pid_by_name("init");
32 if (!pid || *pid<=0) { 32 if (!pid || *pid<=0) {
diff --git a/insmod.c b/insmod.c
deleted file mode 100644
index 6b81ca754..000000000
--- a/insmod.c
+++ /dev/null
@@ -1,3485 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini insmod implementation for busybox
4 *
5 * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k,
6 * and MIPS.
7 *
8 *
9 * Copyright (C) 1999,2000,2001 by Lineo, inc.
10 * Written by Erik Andersen <andersen@lineo.com>
11 * and Ron Alder <alder@lineo.com>
12 *
13 * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
14 * and (theoretically) SH3. I have only tested SH4 in little endian mode.
15 *
16 * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
17 * Nicolas Ferre <nicolas.ferre@alcove.fr> to support ARM7TDMI. Only
18 * very minor changes required to also work with StrongArm and presumably
19 * all ARM based systems.
20 *
21 * Magnus Damm <damm@opensource.se> added PowerPC support 20-Feb-2001.
22 * PowerPC specific code stolen from modutils-2.3.16,
23 * written by Paul Mackerras, Copyright 1996, 1997 Linux International.
24 * I've only tested the code on mpc8xx platforms in big-endian mode.
25 * Did some cleanup and added BB_USE_xxx_ENTRIES...
26 *
27 * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001.
28 * based on modutils-2.4.2
29 * MIPS specific support for Elf loading and relocation.
30 * Copyright 1996, 1997 Linux International.
31 * Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
32 *
33 * Based almost entirely on the Linux modutils-2.3.11 implementation.
34 * Copyright 1996, 1997 Linux International.
35 * New implementation contributed by Richard Henderson <rth@tamu.edu>
36 * Based on original work by Bjorn Ekwall <bj0rn@blox.se>
37 * Restructured (and partly rewritten) by:
38 * Björn Ekwall <bj0rn@blox.se> February 1999
39 *
40 * This program is free software; you can redistribute it and/or modify
41 * it under the terms of the GNU General Public License as published by
42 * the Free Software Foundation; either version 2 of the License, or
43 * (at your option) any later version.
44 *
45 * This program is distributed in the hope that it will be useful,
46 * but WITHOUT ANY WARRANTY; without even the implied warranty of
47 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
48 * General Public License for more details.
49 *
50 * You should have received a copy of the GNU General Public License
51 * along with this program; if not, write to the Free Software
52 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
53 *
54 */
55
56#include <stdlib.h>
57#include <stdio.h>
58#include <stddef.h>
59#include <errno.h>
60#include <unistd.h>
61#include <dirent.h>
62#include <ctype.h>
63#include <assert.h>
64#include <string.h>
65#include <getopt.h>
66#include <sys/utsname.h>
67#include "busybox.h"
68
69#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
70# undef BB_FEATURE_OLD_MODULE_INTERFACE
71# define new_sys_init_module init_module
72#else
73# define old_sys_init_module init_module
74#endif
75
76#ifdef BB_FEATURE_INSMOD_LOADINKMEM
77#define LOADBITS 0
78#else
79#define LOADBITS 1
80#endif
81
82#if defined(__powerpc__)
83#define BB_USE_PLT_ENTRIES
84#define BB_PLT_ENTRY_SIZE 16
85#endif
86
87#if defined(__arm__)
88#define BB_USE_PLT_ENTRIES
89#define BB_PLT_ENTRY_SIZE 8
90#define BB_USE_GOT_ENTRIES
91#define BB_GOT_ENTRY_SIZE 8
92#endif
93
94#if defined(__sh__)
95#define BB_USE_GOT_ENTRIES
96#define BB_GOT_ENTRY_SIZE 4
97#endif
98
99#if defined(__i386__)
100#define BB_USE_GOT_ENTRIES
101#define BB_GOT_ENTRY_SIZE 4
102#endif
103
104#if defined(__mips__)
105// neither used
106#endif
107
108//----------------------------------------------------------------------------
109//--------modutils module.h, lines 45-242
110//----------------------------------------------------------------------------
111
112/* Definitions for the Linux module syscall interface.
113 Copyright 1996, 1997 Linux International.
114
115 Contributed by Richard Henderson <rth@tamu.edu>
116
117 This file is part of the Linux modutils.
118
119 This program is free software; you can redistribute it and/or modify it
120 under the terms of the GNU General Public License as published by the
121 Free Software Foundation; either version 2 of the License, or (at your
122 option) any later version.
123
124 This program is distributed in the hope that it will be useful, but
125 WITHOUT ANY WARRANTY; without even the implied warranty of
126 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
127 General Public License for more details.
128
129 You should have received a copy of the GNU General Public License
130 along with this program; if not, write to the Free Software Foundation,
131 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
132
133
134#ifndef MODUTILS_MODULE_H
135static const int MODUTILS_MODULE_H = 1;
136
137#ident "$Id: insmod.c,v 1.73 2001/08/22 05:41:57 andersen Exp $"
138
139/* This file contains the structures used by the 2.0 and 2.1 kernels.
140 We do not use the kernel headers directly because we do not wish
141 to be dependant on a particular kernel version to compile insmod. */
142
143
144/*======================================================================*/
145/* The structures used by Linux 2.0. */
146
147/* The symbol format used by get_kernel_syms(2). */
148struct old_kernel_sym
149{
150 unsigned long value;
151 char name[60];
152};
153
154struct old_module_ref
155{
156 unsigned long module; /* kernel addresses */
157 unsigned long next;
158};
159
160struct old_module_symbol
161{
162 unsigned long addr;
163 unsigned long name;
164};
165
166struct old_symbol_table
167{
168 int size; /* total, including string table!!! */
169 int n_symbols;
170 int n_refs;
171 struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */
172 struct old_module_ref ref[0]; /* actual size defined by n_refs */
173};
174
175struct old_mod_routines
176{
177 unsigned long init;
178 unsigned long cleanup;
179};
180
181struct old_module
182{
183 unsigned long next;
184 unsigned long ref; /* the list of modules that refer to me */
185 unsigned long symtab;
186 unsigned long name;
187 int size; /* size of module in pages */
188 unsigned long addr; /* address of module */
189 int state;
190 unsigned long cleanup; /* cleanup routine */
191};
192
193/* Sent to init_module(2) or'ed into the code size parameter. */
194static const int OLD_MOD_AUTOCLEAN = 0x40000000; /* big enough, but no sign problems... */
195
196int get_kernel_syms(struct old_kernel_sym *);
197int old_sys_init_module(const char *name, char *code, unsigned codesize,
198 struct old_mod_routines *, struct old_symbol_table *);
199
200/*======================================================================*/
201/* For sizeof() which are related to the module platform and not to the
202 environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */
203
204#define tgt_sizeof_char sizeof(char)
205#define tgt_sizeof_short sizeof(short)
206#define tgt_sizeof_int sizeof(int)
207#define tgt_sizeof_long sizeof(long)
208#define tgt_sizeof_char_p sizeof(char *)
209#define tgt_sizeof_void_p sizeof(void *)
210#define tgt_long long
211
212#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64)
213#undef tgt_sizeof_long
214#undef tgt_sizeof_char_p
215#undef tgt_sizeof_void_p
216#undef tgt_long
217static const int tgt_sizeof_long = 8;
218static const int tgt_sizeof_char_p = 8;
219static const int tgt_sizeof_void_p = 8;
220#define tgt_long long long
221#endif
222
223/*======================================================================*/
224/* The structures used in Linux 2.1. */
225
226/* Note: new_module_symbol does not use tgt_long intentionally */
227struct new_module_symbol
228{
229 unsigned long value;
230 unsigned long name;
231};
232
233struct new_module_persist;
234
235struct new_module_ref
236{
237 unsigned tgt_long dep; /* kernel addresses */
238 unsigned tgt_long ref;
239 unsigned tgt_long next_ref;
240};
241
242struct new_module
243{
244 unsigned tgt_long size_of_struct; /* == sizeof(module) */
245 unsigned tgt_long next;
246 unsigned tgt_long name;
247 unsigned tgt_long size;
248
249 tgt_long usecount;
250 unsigned tgt_long flags; /* AUTOCLEAN et al */
251
252 unsigned nsyms;
253 unsigned ndeps;
254
255 unsigned tgt_long syms;
256 unsigned tgt_long deps;
257 unsigned tgt_long refs;
258 unsigned tgt_long init;
259 unsigned tgt_long cleanup;
260 unsigned tgt_long ex_table_start;
261 unsigned tgt_long ex_table_end;
262#ifdef __alpha__
263 unsigned tgt_long gp;
264#endif
265 /* Everything after here is extension. */
266 unsigned tgt_long persist_start;
267 unsigned tgt_long persist_end;
268 unsigned tgt_long can_unload;
269 unsigned tgt_long runsize;
270#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
271 const char *kallsyms_start; /* All symbols for kernel debugging */
272 const char *kallsyms_end;
273 const char *archdata_start; /* arch specific data for module */
274 const char *archdata_end;
275 const char *kernel_data; /* Reserved for kernel internal use */
276#endif
277};
278
279#define ARCHDATA_SEC_NAME "__archdata"
280#define KALLSYMS_SEC_NAME "__kallsyms"
281
282
283struct new_module_info
284{
285 unsigned long addr;
286 unsigned long size;
287 unsigned long flags;
288 long usecount;
289};
290
291/* Bits of module.flags. */
292static const int NEW_MOD_RUNNING = 1;
293static const int NEW_MOD_DELETED = 2;
294static const int NEW_MOD_AUTOCLEAN = 4;
295static const int NEW_MOD_VISITED = 8;
296static const int NEW_MOD_USED_ONCE = 16;
297
298int new_sys_init_module(const char *name, const struct new_module *);
299int query_module(const char *name, int which, void *buf, size_t bufsize,
300 size_t *ret);
301
302/* Values for query_module's which. */
303
304static const int QM_MODULES = 1;
305static const int QM_DEPS = 2;
306static const int QM_REFS = 3;
307static const int QM_SYMBOLS = 4;
308static const int QM_INFO = 5;
309
310/*======================================================================*/
311/* The system calls unchanged between 2.0 and 2.1. */
312
313unsigned long create_module(const char *, size_t);
314int delete_module(const char *);
315
316
317#endif /* module.h */
318
319//----------------------------------------------------------------------------
320//--------end of modutils module.h
321//----------------------------------------------------------------------------
322
323
324
325//----------------------------------------------------------------------------
326//--------modutils obj.h, lines 253-462
327//----------------------------------------------------------------------------
328
329/* Elf object file loading and relocation routines.
330 Copyright 1996, 1997 Linux International.
331
332 Contributed by Richard Henderson <rth@tamu.edu>
333
334 This file is part of the Linux modutils.
335
336 This program is free software; you can redistribute it and/or modify it
337 under the terms of the GNU General Public License as published by the
338 Free Software Foundation; either version 2 of the License, or (at your
339 option) any later version.
340
341 This program is distributed in the hope that it will be useful, but
342 WITHOUT ANY WARRANTY; without even the implied warranty of
343 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
344 General Public License for more details.
345
346 You should have received a copy of the GNU General Public License
347 along with this program; if not, write to the Free Software Foundation,
348 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
349
350
351#ifndef MODUTILS_OBJ_H
352static const int MODUTILS_OBJ_H = 1;
353
354#ident "$Id: insmod.c,v 1.73 2001/08/22 05:41:57 andersen Exp $"
355
356/* The relocatable object is manipulated using elfin types. */
357
358#include <stdio.h>
359#include <elf.h>
360
361
362/* Machine-specific elf macros for i386 et al. */
363
364/* the SH changes have only been tested on the SH4 in =little endian= mode */
365/* I'm not sure about big endian, so let's warn: */
366
367#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__)
368#error insmod.c may require changes for use on big endian SH4/SH3
369#endif
370
371/* it may or may not work on the SH1/SH2... So let's error on those
372 also */
373#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__))))
374#error insmod.c may require changes for non-SH3/SH4 use
375#endif
376
377#define ELFCLASSM ELFCLASS32
378
379#if (defined(__mc68000__))
380#define ELFDATAM ELFDATA2MSB
381#endif
382
383
384
385#if defined(__sh__)
386
387#define MATCH_MACHINE(x) (x == EM_SH)
388#define SHT_RELM SHT_RELA
389#define Elf32_RelM Elf32_Rela
390#define ELFDATAM ELFDATA2LSB
391
392#elif defined(__arm__)
393
394#define MATCH_MACHINE(x) (x == EM_ARM)
395#define SHT_RELM SHT_REL
396#define Elf32_RelM Elf32_Rel
397#define ELFDATAM ELFDATA2LSB
398
399#elif defined(__powerpc__)
400
401#define MATCH_MACHINE(x) (x == EM_PPC)
402#define SHT_RELM SHT_RELA
403#define Elf32_RelM Elf32_Rela
404#define ELFDATAM ELFDATA2MSB
405
406#elif defined(__mips__)
407
408/* Account for ELF spec changes. */
409#ifndef EM_MIPS_RS3_LE
410#ifdef EM_MIPS_RS4_BE
411#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE
412#else
413#define EM_MIPS_RS3_LE 10
414#endif
415#endif /* !EM_MIPS_RS3_LE */
416
417#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
418#define SHT_RELM SHT_REL
419#define Elf32_RelM Elf32_Rel
420#ifdef __MIPSEB__
421#define ELFDATAM ELFDATA2MSB
422#endif
423#ifdef __MIPSEL__
424#define ELFDATAM ELFDATA2LSB
425#endif
426
427#elif defined(__i386__)
428
429/* presumably we can use these for anything but the SH and ARM*/
430/* this is the previous behavior, but it does result in
431 insmod.c being broken on anything except i386 */
432#ifndef EM_486
433#define MATCH_MACHINE(x) (x == EM_386)
434#else
435#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486)
436#endif
437
438#define SHT_RELM SHT_REL
439#define Elf32_RelM Elf32_Rel
440#define ELFDATAM ELFDATA2LSB
441
442#elif defined(__mc68000__)
443
444#define MATCH_MACHINE(x) (x == EM_68K)
445#define SHT_RELM SHT_RELA
446#define Elf32_RelM Elf32_Rela
447
448#else
449#error Sorry, but insmod.c does not yet support this architecture...
450#endif
451
452#ifndef ElfW
453# if ELFCLASSM == ELFCLASS32
454# define ElfW(x) Elf32_ ## x
455# define ELFW(x) ELF32_ ## x
456# else
457# define ElfW(x) Elf64_ ## x
458# define ELFW(x) ELF64_ ## x
459# endif
460#endif
461
462/* For some reason this is missing from libc5. */
463#ifndef ELF32_ST_INFO
464# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
465#endif
466
467#ifndef ELF64_ST_INFO
468# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
469#endif
470
471struct obj_string_patch;
472struct obj_symbol_patch;
473
474struct obj_section
475{
476 ElfW(Shdr) header;
477 const char *name;
478 char *contents;
479 struct obj_section *load_next;
480 int idx;
481};
482
483struct obj_symbol
484{
485 struct obj_symbol *next; /* hash table link */
486 const char *name;
487 unsigned long value;
488 unsigned long size;
489 int secidx; /* the defining section index/module */
490 int info;
491 int ksymidx; /* for export to the kernel symtab */
492 int referenced; /* actually used in the link */
493};
494
495/* Hardcode the hash table size. We shouldn't be needing so many
496 symbols that we begin to degrade performance, and we get a big win
497 by giving the compiler a constant divisor. */
498
499#define HASH_BUCKETS 521
500
501struct obj_file
502{
503 ElfW(Ehdr) header;
504 ElfW(Addr) baseaddr;
505 struct obj_section **sections;
506 struct obj_section *load_order;
507 struct obj_section **load_order_search_start;
508 struct obj_string_patch *string_patches;
509 struct obj_symbol_patch *symbol_patches;
510 int (*symbol_cmp)(const char *, const char *);
511 unsigned long (*symbol_hash)(const char *);
512 unsigned long local_symtab_size;
513 struct obj_symbol **local_symtab;
514 struct obj_symbol *symtab[HASH_BUCKETS];
515};
516
517enum obj_reloc
518{
519 obj_reloc_ok,
520 obj_reloc_overflow,
521 obj_reloc_dangerous,
522 obj_reloc_unhandled
523};
524
525struct obj_string_patch
526{
527 struct obj_string_patch *next;
528 int reloc_secidx;
529 ElfW(Addr) reloc_offset;
530 ElfW(Addr) string_offset;
531};
532
533struct obj_symbol_patch
534{
535 struct obj_symbol_patch *next;
536 int reloc_secidx;
537 ElfW(Addr) reloc_offset;
538 struct obj_symbol *sym;
539};
540
541
542/* Generic object manipulation routines. */
543
544static unsigned long obj_elf_hash(const char *);
545
546static unsigned long obj_elf_hash_n(const char *, unsigned long len);
547
548static struct obj_symbol *obj_find_symbol (struct obj_file *f,
549 const char *name);
550
551static ElfW(Addr) obj_symbol_final_value(struct obj_file *f,
552 struct obj_symbol *sym);
553
554#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
555static void obj_set_symbol_compare(struct obj_file *f,
556 int (*cmp)(const char *, const char *),
557 unsigned long (*hash)(const char *));
558#endif
559
560static struct obj_section *obj_find_section (struct obj_file *f,
561 const char *name);
562
563static void obj_insert_section_load_order (struct obj_file *f,
564 struct obj_section *sec);
565
566static struct obj_section *obj_create_alloced_section (struct obj_file *f,
567 const char *name,
568 unsigned long align,
569 unsigned long size);
570
571static struct obj_section *obj_create_alloced_section_first (struct obj_file *f,
572 const char *name,
573 unsigned long align,
574 unsigned long size);
575
576static void *obj_extend_section (struct obj_section *sec, unsigned long more);
577
578static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
579 const char *string);
580
581static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
582 struct obj_symbol *sym);
583
584static int obj_check_undefineds(struct obj_file *f);
585
586static void obj_allocate_commons(struct obj_file *f);
587
588static unsigned long obj_load_size (struct obj_file *f);
589
590static int obj_relocate (struct obj_file *f, ElfW(Addr) base);
591
592static struct obj_file *obj_load(FILE *f, int loadprogbits);
593
594static int obj_create_image (struct obj_file *f, char *image);
595
596/* Architecture specific manipulation routines. */
597
598static struct obj_file *arch_new_file (void);
599
600static struct obj_section *arch_new_section (void);
601
602static struct obj_symbol *arch_new_symbol (void);
603
604static enum obj_reloc arch_apply_relocation (struct obj_file *f,
605 struct obj_section *targsec,
606 struct obj_section *symsec,
607 struct obj_symbol *sym,
608 ElfW(RelM) *rel, ElfW(Addr) value);
609
610static int arch_create_got (struct obj_file *f);
611
612static int arch_init_module (struct obj_file *f, struct new_module *);
613
614#endif /* obj.h */
615//----------------------------------------------------------------------------
616//--------end of modutils obj.h
617//----------------------------------------------------------------------------
618
619
620
621
622
623#define _PATH_MODULES "/lib/modules"
624static const int STRVERSIONLEN = 32;
625
626/*======================================================================*/
627
628static int flag_force_load = 0;
629static int flag_autoclean = 0;
630static int flag_verbose = 0;
631static int flag_export = 1;
632
633
634/*======================================================================*/
635
636/* previously, these were named i386_* but since we could be
637 compiling for the sh, I've renamed them to the more general
638 arch_* These structures are the same between the x86 and SH,
639 and we can't support anything else right now anyway. In the
640 future maybe they should be #if defined'd */
641
642/* Done ;-) */
643
644
645
646#if defined(BB_USE_PLT_ENTRIES)
647struct arch_plt_entry
648{
649 int offset;
650 int allocated:1;
651 int inited:1; /* has been set up */
652};
653#endif
654
655#if defined(BB_USE_GOT_ENTRIES)
656struct arch_got_entry {
657 int offset;
658 unsigned offset_done:1;
659 unsigned reloc_done:1;
660};
661#endif
662
663#if defined(__mips__)
664struct mips_hi16
665{
666 struct mips_hi16 *next;
667 Elf32_Addr *addr;
668 Elf32_Addr value;
669};
670#endif
671
672struct arch_file {
673 struct obj_file root;
674#if defined(BB_USE_PLT_ENTRIES)
675 struct obj_section *plt;
676#endif
677#if defined(BB_USE_GOT_ENTRIES)
678 struct obj_section *got;
679#endif
680#if defined(__mips__)
681 struct mips_hi16 *mips_hi16_list;
682#endif
683};
684
685struct arch_symbol {
686 struct obj_symbol root;
687#if defined(BB_USE_PLT_ENTRIES)
688 struct arch_plt_entry pltent;
689#endif
690#if defined(BB_USE_GOT_ENTRIES)
691 struct arch_got_entry gotent;
692#endif
693};
694
695
696struct external_module {
697 const char *name;
698 ElfW(Addr) addr;
699 int used;
700 size_t nsyms;
701 struct new_module_symbol *syms;
702};
703
704static struct new_module_symbol *ksyms;
705static size_t nksyms;
706
707static struct external_module *ext_modules;
708static int n_ext_modules;
709static int n_ext_modules_used;
710extern int delete_module(const char *);
711
712static char m_filename[FILENAME_MAX + 1];
713static char m_fullName[FILENAME_MAX + 1];
714
715
716
717/*======================================================================*/
718
719
720static int check_module_name_match(const char *filename, struct stat *statbuf,
721 void *userdata)
722{
723 char *fullname = (char *) userdata;
724
725 if (fullname[0] == '\0')
726 return (FALSE);
727 else {
728 char *tmp, *tmp1 = strdup(filename);
729 tmp = get_last_path_component(tmp1);
730 if (strcmp(tmp, fullname) == 0) {
731 free(tmp1);
732 /* Stop searching if we find a match */
733 safe_strncpy(m_filename, filename, sizeof(m_filename));
734 return (TRUE);
735 }
736 free(tmp1);
737 }
738 return (FALSE);
739}
740
741
742/*======================================================================*/
743
744static struct obj_file *arch_new_file(void)
745{
746 struct arch_file *f;
747 f = xmalloc(sizeof(*f));
748
749#if defined(BB_USE_PLT_ENTRIES)
750 f->plt = NULL;
751#endif
752#if defined(BB_USE_GOT_ENTRIES)
753 f->got = NULL;
754#endif
755#if defined(__mips__)
756 f->mips_hi16_list = NULL;
757#endif
758
759 return &f->root;
760}
761
762static struct obj_section *arch_new_section(void)
763{
764 return xmalloc(sizeof(struct obj_section));
765}
766
767static struct obj_symbol *arch_new_symbol(void)
768{
769 struct arch_symbol *sym;
770 sym = xmalloc(sizeof(*sym));
771
772#if defined(BB_USE_PLT_ENTRIES)
773 memset(&sym->pltent, 0, sizeof(sym->pltent));
774#endif
775#if defined(BB_USE_GOT_ENTRIES)
776 memset(&sym->gotent, 0, sizeof(sym->gotent));
777#endif
778
779 return &sym->root;
780}
781
782static enum obj_reloc
783arch_apply_relocation(struct obj_file *f,
784 struct obj_section *targsec,
785 struct obj_section *symsec,
786 struct obj_symbol *sym,
787 ElfW(RelM) *rel, ElfW(Addr) v)
788{
789 struct arch_file *ifile = (struct arch_file *) f;
790#if !(defined(__mips__))
791 struct arch_symbol *isym = (struct arch_symbol *) sym;
792#endif
793
794 ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
795 ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
796#if defined(BB_USE_GOT_ENTRIES)
797 ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
798#endif
799#if defined(BB_USE_PLT_ENTRIES)
800 ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
801 struct arch_plt_entry *pe;
802 unsigned long *ip;
803#endif
804 enum obj_reloc ret = obj_reloc_ok;
805
806 switch (ELF32_R_TYPE(rel->r_info)) {
807
808/* even though these constants seem to be the same for
809 the i386 and the sh, we "#if define" them for clarity
810 and in case that ever changes */
811#if defined(__sh__)
812 case R_SH_NONE:
813#elif defined(__arm__)
814 case R_ARM_NONE:
815#elif defined(__i386__)
816 case R_386_NONE:
817#elif defined(__mc68000__)
818 case R_68K_NONE:
819#elif defined(__powerpc__)
820 case R_PPC_NONE:
821#elif defined(__mips__)
822 case R_MIPS_NONE:
823#endif
824 break;
825
826#if defined(__sh__)
827 case R_SH_DIR32:
828#elif defined(__arm__)
829 case R_ARM_ABS32:
830#elif defined(__i386__)
831 case R_386_32:
832#elif defined(__mc68000__)
833 case R_68K_32:
834#elif defined(__powerpc__)
835 case R_PPC_ADDR32:
836#elif defined(__mips__)
837 case R_MIPS_32:
838#endif
839 *loc += v;
840 break;
841#if defined(__mc68000__)
842 case R_68K_8:
843 if (v > 0xff)
844 ret = obj_reloc_overflow;
845 *(char *)loc = v;
846 break;
847 case R_68K_16:
848 if (v > 0xffff)
849 ret = obj_reloc_overflow;
850 *(short *)loc = v;
851 break;
852#endif /* __mc68000__ */
853
854#if defined(__powerpc__)
855 case R_PPC_ADDR16_HA:
856 *(unsigned short *)loc = (v + 0x8000) >> 16;
857 break;
858
859 case R_PPC_ADDR16_HI:
860 *(unsigned short *)loc = v >> 16;
861 break;
862
863 case R_PPC_ADDR16_LO:
864 *(unsigned short *)loc = v;
865 break;
866#endif
867
868#if defined(__mips__)
869 case R_MIPS_26:
870 if (v % 4)
871 ret = obj_reloc_dangerous;
872 if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000))
873 ret = obj_reloc_overflow;
874 *loc =
875 (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) &
876 0x03ffffff);
877 break;
878
879 case R_MIPS_HI16:
880 {
881 struct mips_hi16 *n;
882
883 /* We cannot relocate this one now because we don't know the value
884 of the carry we need to add. Save the information, and let LO16
885 do the actual relocation. */
886 n = (struct mips_hi16 *) xmalloc(sizeof *n);
887 n->addr = loc;
888 n->value = v;
889 n->next = ifile->mips_hi16_list;
890 ifile->mips_hi16_list = n;
891 break;
892 }
893
894 case R_MIPS_LO16:
895 {
896 unsigned long insnlo = *loc;
897 Elf32_Addr val, vallo;
898
899 /* Sign extend the addend we extract from the lo insn. */
900 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
901
902 if (ifile->mips_hi16_list != NULL) {
903 struct mips_hi16 *l;
904
905 l = ifile->mips_hi16_list;
906 while (l != NULL) {
907 struct mips_hi16 *next;
908 unsigned long insn;
909
910 /* The value for the HI16 had best be the same. */
911 assert(v == l->value);
912
913 /* Do the HI16 relocation. Note that we actually don't
914 need to know anything about the LO16 itself, except where
915 to find the low 16 bits of the addend needed by the LO16. */
916 insn = *l->addr;
917 val =
918 ((insn & 0xffff) << 16) +
919 vallo;
920 val += v;
921
922 /* Account for the sign extension that will happen in the
923 low bits. */
924 val =
925 ((val >> 16) +
926 ((val & 0x8000) !=
927 0)) & 0xffff;
928
929 insn = (insn & ~0xffff) | val;
930 *l->addr = insn;
931
932 next = l->next;
933 free(l);
934 l = next;
935 }
936
937 ifile->mips_hi16_list = NULL;
938 }
939
940 /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */
941 val = v + vallo;
942 insnlo = (insnlo & ~0xffff) | (val & 0xffff);
943 *loc = insnlo;
944 break;
945 }
946#endif
947
948#if defined(__arm__)
949#elif defined(__sh__)
950 case R_SH_REL32:
951 *loc += v - dot;
952 break;
953#elif defined(__i386__)
954 case R_386_PLT32:
955 case R_386_PC32:
956 *loc += v - dot;
957 break;
958#elif defined(__mc68000__)
959 case R_68K_PC8:
960 v -= dot;
961 if ((Elf32_Sword)v > 0x7f || (Elf32_Sword)v < -(Elf32_Sword)0x80)
962 ret = obj_reloc_overflow;
963 *(char *)loc = v;
964 break;
965 case R_68K_PC16:
966 v -= dot;
967 if ((Elf32_Sword)v > 0x7fff || (Elf32_Sword)v < -(Elf32_Sword)0x8000)
968 ret = obj_reloc_overflow;
969 *(short *)loc = v;
970 break;
971 case R_68K_PC32:
972 *(int *)loc = v - dot;
973 break;
974#elif defined(__powerpc__)
975 case R_PPC_REL32:
976 *loc = v - dot;
977 break;
978#endif
979
980#if defined(__sh__)
981 case R_SH_PLT32:
982 *loc = v - dot;
983 break;
984#elif defined(__i386__)
985#endif
986
987#if defined(BB_USE_PLT_ENTRIES)
988
989#if defined(__arm__)
990 case R_ARM_PC24:
991 case R_ARM_PLT32:
992#endif
993#if defined(__powerpc__)
994 case R_PPC_REL24:
995#endif
996 /* find the plt entry and initialize it if necessary */
997 assert(isym != NULL);
998
999 pe = (struct arch_plt_entry*) &isym->pltent;
1000
1001 if (! pe->inited) {
1002 ip = (unsigned long *) (ifile->plt->contents + pe->offset);
1003
1004 /* generate some machine code */
1005
1006#if defined(__arm__)
1007 ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
1008 ip[1] = v; /* sym@ */
1009#endif
1010#if defined(__powerpc__)
1011 ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */
1012 ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */
1013 ip[2] = 0x7d6903a6; /* mtctr r11 */
1014 ip[3] = 0x4e800420; /* bctr */
1015#endif
1016 pe->inited = 1;
1017 }
1018
1019 /* relative distance to target */
1020 v -= dot;
1021 /* if the target is too far away.... */
1022 if ((int)v < -0x02000000 || (int)v >= 0x02000000) {
1023 /* go via the plt */
1024 v = plt + pe->offset - dot;
1025 }
1026 if (v & 3)
1027 ret = obj_reloc_dangerous;
1028
1029 /* merge the offset into the instruction. */
1030#if defined(__arm__)
1031 /* Convert to words. */
1032 v >>= 2;
1033
1034 *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
1035#endif
1036#if defined(__powerpc__)
1037 *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
1038#endif
1039 break;
1040#endif /* BB_USE_PLT_ENTRIES */
1041
1042#if defined(__arm__)
1043#elif defined(__sh__)
1044 case R_SH_GLOB_DAT:
1045 case R_SH_JMP_SLOT:
1046 *loc = v;
1047 break;
1048#elif defined(__i386__)
1049 case R_386_GLOB_DAT:
1050 case R_386_JMP_SLOT:
1051 *loc = v;
1052 break;
1053#elif defined(__mc68000__)
1054 case R_68K_GLOB_DAT:
1055 case R_68K_JMP_SLOT:
1056 *loc = v;
1057 break;
1058#endif
1059
1060#if defined(__arm__)
1061#elif defined(__sh__)
1062 case R_SH_RELATIVE:
1063 *loc += f->baseaddr + rel->r_addend;
1064 break;
1065#elif defined(__i386__)
1066 case R_386_RELATIVE:
1067 *loc += f->baseaddr;
1068 break;
1069#elif defined(__mc68000__)
1070 case R_68K_RELATIVE:
1071 *(int *)loc += f->baseaddr;
1072 break;
1073#endif
1074
1075#if defined(BB_USE_GOT_ENTRIES)
1076
1077#if !defined(__68k__)
1078#if defined(__sh__)
1079 case R_SH_GOTPC:
1080#elif defined(__arm__)
1081 case R_ARM_GOTPC:
1082#elif defined(__i386__)
1083 case R_386_GOTPC:
1084#endif
1085 assert(got != 0);
1086#if defined(__sh__)
1087 *loc += got - dot + rel->r_addend;;
1088#elif defined(__i386__) || defined(__arm__) || defined(__m68k_)
1089 *loc += got - dot;
1090#endif
1091 break;
1092#endif // __68k__
1093
1094#if defined(__sh__)
1095 case R_SH_GOT32:
1096#elif defined(__arm__)
1097 case R_ARM_GOT32:
1098#elif defined(__i386__)
1099 case R_386_GOT32:
1100#elif defined(__mc68000__)
1101 case R_68K_GOT32:
1102#endif
1103 assert(isym != NULL);
1104 /* needs an entry in the .got: set it, once */
1105 if (!isym->gotent.reloc_done) {
1106 isym->gotent.reloc_done = 1;
1107 *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v;
1108 }
1109 /* make the reloc with_respect_to_.got */
1110#if defined(__sh__)
1111 *loc += isym->gotent.offset + rel->r_addend;
1112#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__)
1113 *loc += isym->gotent.offset;
1114#endif
1115 break;
1116
1117 /* address relative to the got */
1118#if !defined(__mc68000__)
1119#if defined(__sh__)
1120 case R_SH_GOTOFF:
1121#elif defined(__arm__)
1122 case R_ARM_GOTOFF:
1123#elif defined(__i386__)
1124 case R_386_GOTOFF:
1125#elif defined(__mc68000__)
1126 case R_68K_GOTOFF:
1127#endif
1128 assert(got != 0);
1129 *loc += v - got;
1130 break;
1131#endif // __mc68000__
1132
1133#endif /* BB_USE_GOT_ENTRIES */
1134
1135 default:
1136 printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info));
1137 ret = obj_reloc_unhandled;
1138 break;
1139 }
1140
1141 return ret;
1142}
1143
1144static int arch_create_got(struct obj_file *f)
1145{
1146#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES)
1147 struct arch_file *ifile = (struct arch_file *) f;
1148 int i;
1149#if defined(BB_USE_GOT_ENTRIES)
1150 int got_offset = 0, gotneeded = 0;
1151#endif
1152#if defined(BB_USE_PLT_ENTRIES)
1153 int plt_offset = 0, pltneeded = 0;
1154#endif
1155 struct obj_section *relsec, *symsec, *strsec;
1156 ElfW(RelM) *rel, *relend;
1157 ElfW(Sym) *symtab, *extsym;
1158 const char *strtab, *name;
1159 struct arch_symbol *intsym;
1160
1161 for (i = 0; i < f->header.e_shnum; ++i) {
1162 relsec = f->sections[i];
1163 if (relsec->header.sh_type != SHT_RELM)
1164 continue;
1165
1166 symsec = f->sections[relsec->header.sh_link];
1167 strsec = f->sections[symsec->header.sh_link];
1168
1169 rel = (ElfW(RelM) *) relsec->contents;
1170 relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
1171 symtab = (ElfW(Sym) *) symsec->contents;
1172 strtab = (const char *) strsec->contents;
1173
1174 for (; rel < relend; ++rel) {
1175 extsym = &symtab[ELF32_R_SYM(rel->r_info)];
1176
1177 switch (ELF32_R_TYPE(rel->r_info)) {
1178#if defined(__arm__)
1179 case R_ARM_GOT32:
1180 break;
1181#elif defined(__sh__)
1182 case R_SH_GOT32:
1183 break;
1184#elif defined(__i386__)
1185 case R_386_GOT32:
1186 break;
1187#elif defined(__mc68000__)
1188 case R_68K_GOT32:
1189 break;
1190#endif
1191
1192#if defined(__powerpc__)
1193 case R_PPC_REL24:
1194 pltneeded = 1;
1195 break;
1196#endif
1197
1198#if defined(__arm__)
1199 case R_ARM_PC24:
1200 case R_ARM_PLT32:
1201 pltneeded = 1;
1202 break;
1203
1204 case R_ARM_GOTPC:
1205 case R_ARM_GOTOFF:
1206 gotneeded = 1;
1207 if (got_offset == 0)
1208 got_offset = 4;
1209#elif defined(__sh__)
1210 case R_SH_GOTPC:
1211 case R_SH_GOTOFF:
1212 gotneeded = 1;
1213#elif defined(__i386__)
1214 case R_386_GOTPC:
1215 case R_386_GOTOFF:
1216 gotneeded = 1;
1217#endif
1218
1219 default:
1220 continue;
1221 }
1222
1223 if (extsym->st_name != 0) {
1224 name = strtab + extsym->st_name;
1225 } else {
1226 name = f->sections[extsym->st_shndx]->name;
1227 }
1228 intsym = (struct arch_symbol *) obj_find_symbol(f, name);
1229#if defined(BB_USE_GOT_ENTRIES)
1230 if (!intsym->gotent.offset_done) {
1231 intsym->gotent.offset_done = 1;
1232 intsym->gotent.offset = got_offset;
1233 got_offset += BB_GOT_ENTRY_SIZE;
1234 }
1235#endif
1236#if defined(BB_USE_PLT_ENTRIES)
1237 if (pltneeded && intsym->pltent.allocated == 0) {
1238 intsym->pltent.allocated = 1;
1239 intsym->pltent.offset = plt_offset;
1240 plt_offset += BB_PLT_ENTRY_SIZE;
1241 intsym->pltent.inited = 0;
1242 pltneeded = 0;
1243 }
1244#endif
1245 }
1246 }
1247
1248#if defined(BB_USE_GOT_ENTRIES)
1249 if (got_offset) {
1250 struct obj_section* myrelsec = obj_find_section(f, ".got");
1251
1252 if (myrelsec) {
1253 obj_extend_section(myrelsec, got_offset);
1254 } else {
1255 myrelsec = obj_create_alloced_section(f, ".got",
1256 BB_GOT_ENTRY_SIZE,
1257 got_offset);
1258 assert(myrelsec);
1259 }
1260
1261 ifile->got = myrelsec;
1262 }
1263#endif
1264
1265#if defined(BB_USE_PLT_ENTRIES)
1266 if (plt_offset)
1267 ifile->plt = obj_create_alloced_section(f, ".plt",
1268 BB_PLT_ENTRY_SIZE,
1269 plt_offset);
1270#endif
1271#endif
1272 return 1;
1273}
1274
1275static int arch_init_module(struct obj_file *f, struct new_module *mod)
1276{
1277 return 1;
1278}
1279
1280
1281/*======================================================================*/
1282
1283/* Standard ELF hash function. */
1284static inline unsigned long obj_elf_hash_n(const char *name, unsigned long n)
1285{
1286 unsigned long h = 0;
1287 unsigned long g;
1288 unsigned char ch;
1289
1290 while (n > 0) {
1291 ch = *name++;
1292 h = (h << 4) + ch;
1293 if ((g = (h & 0xf0000000)) != 0) {
1294 h ^= g >> 24;
1295 h &= ~g;
1296 }
1297 n--;
1298 }
1299 return h;
1300}
1301
1302static unsigned long obj_elf_hash(const char *name)
1303{
1304 return obj_elf_hash_n(name, strlen(name));
1305}
1306
1307#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
1308/* String comparison for non-co-versioned kernel and module. */
1309
1310static int ncv_strcmp(const char *a, const char *b)
1311{
1312 size_t alen = strlen(a), blen = strlen(b);
1313
1314 if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R')
1315 return strncmp(a, b, alen);
1316 else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R')
1317 return strncmp(a, b, blen);
1318 else
1319 return strcmp(a, b);
1320}
1321
1322/* String hashing for non-co-versioned kernel and module. Here
1323 we are simply forced to drop the crc from the hash. */
1324
1325static unsigned long ncv_symbol_hash(const char *str)
1326{
1327 size_t len = strlen(str);
1328 if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R')
1329 len -= 10;
1330 return obj_elf_hash_n(str, len);
1331}
1332
1333static void
1334obj_set_symbol_compare(struct obj_file *f,
1335 int (*cmp) (const char *, const char *),
1336 unsigned long (*hash) (const char *))
1337{
1338 if (cmp)
1339 f->symbol_cmp = cmp;
1340 if (hash) {
1341 struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
1342 int i;
1343
1344 f->symbol_hash = hash;
1345
1346 memcpy(tmptab, f->symtab, sizeof(tmptab));
1347 memset(f->symtab, 0, sizeof(f->symtab));
1348
1349 for (i = 0; i < HASH_BUCKETS; ++i)
1350 for (sym = tmptab[i]; sym; sym = next) {
1351 unsigned long h = hash(sym->name) % HASH_BUCKETS;
1352 next = sym->next;
1353 sym->next = f->symtab[h];
1354 f->symtab[h] = sym;
1355 }
1356 }
1357}
1358
1359#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
1360
1361static struct obj_symbol *
1362obj_add_symbol(struct obj_file *f, const char *name,
1363 unsigned long symidx, int info,
1364 int secidx, ElfW(Addr) value,
1365 unsigned long size)
1366{
1367 struct obj_symbol *sym;
1368 unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
1369 int n_type = ELFW(ST_TYPE) (info);
1370 int n_binding = ELFW(ST_BIND) (info);
1371
1372 for (sym = f->symtab[hash]; sym; sym = sym->next)
1373 if (f->symbol_cmp(sym->name, name) == 0) {
1374 int o_secidx = sym->secidx;
1375 int o_info = sym->info;
1376 int o_type = ELFW(ST_TYPE) (o_info);
1377 int o_binding = ELFW(ST_BIND) (o_info);
1378
1379 /* A redefinition! Is it legal? */
1380
1381 if (secidx == SHN_UNDEF)
1382 return sym;
1383 else if (o_secidx == SHN_UNDEF)
1384 goto found;
1385 else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) {
1386 /* Cope with local and global symbols of the same name
1387 in the same object file, as might have been created
1388 by ld -r. The only reason locals are now seen at this
1389 level at all is so that we can do semi-sensible things
1390 with parameters. */
1391
1392 struct obj_symbol *nsym, **p;
1393
1394 nsym = arch_new_symbol();
1395 nsym->next = sym->next;
1396 nsym->ksymidx = -1;
1397
1398 /* Excise the old (local) symbol from the hash chain. */
1399 for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
1400 continue;
1401 *p = sym = nsym;
1402 goto found;
1403 } else if (n_binding == STB_LOCAL) {
1404 /* Another symbol of the same name has already been defined.
1405 Just add this to the local table. */
1406 sym = arch_new_symbol();
1407 sym->next = NULL;
1408 sym->ksymidx = -1;
1409 f->local_symtab[symidx] = sym;
1410 goto found;
1411 } else if (n_binding == STB_WEAK)
1412 return sym;
1413 else if (o_binding == STB_WEAK)
1414 goto found;
1415 /* Don't unify COMMON symbols with object types the programmer
1416 doesn't expect. */
1417 else if (secidx == SHN_COMMON
1418 && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
1419 return sym;
1420 else if (o_secidx == SHN_COMMON
1421 && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
1422 goto found;
1423 else {
1424 /* Don't report an error if the symbol is coming from
1425 the kernel or some external module. */
1426 if (secidx <= SHN_HIRESERVE)
1427 error_msg("%s multiply defined", name);
1428 return sym;
1429 }
1430 }
1431
1432 /* Completely new symbol. */
1433 sym = arch_new_symbol();
1434 sym->next = f->symtab[hash];
1435 f->symtab[hash] = sym;
1436 sym->ksymidx = -1;
1437
1438 if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) {
1439 if (symidx >= f->local_symtab_size)
1440 error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld",
1441 name, (long) symidx, (long) f->local_symtab_size);
1442 else
1443 f->local_symtab[symidx] = sym;
1444 }
1445
1446 found:
1447 sym->name = name;
1448 sym->value = value;
1449 sym->size = size;
1450 sym->secidx = secidx;
1451 sym->info = info;
1452
1453 return sym;
1454}
1455
1456static struct obj_symbol *
1457obj_find_symbol(struct obj_file *f, const char *name)
1458{
1459 struct obj_symbol *sym;
1460 unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
1461
1462 for (sym = f->symtab[hash]; sym; sym = sym->next)
1463 if (f->symbol_cmp(sym->name, name) == 0)
1464 return sym;
1465
1466 return NULL;
1467}
1468
1469static ElfW(Addr)
1470 obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym)
1471{
1472 if (sym) {
1473 if (sym->secidx >= SHN_LORESERVE)
1474 return sym->value;
1475
1476 return sym->value + f->sections[sym->secidx]->header.sh_addr;
1477 } else {
1478 /* As a special case, a NULL sym has value zero. */
1479 return 0;
1480 }
1481}
1482
1483static struct obj_section *obj_find_section(struct obj_file *f, const char *name)
1484{
1485 int i, n = f->header.e_shnum;
1486
1487 for (i = 0; i < n; ++i)
1488 if (strcmp(f->sections[i]->name, name) == 0)
1489 return f->sections[i];
1490
1491 return NULL;
1492}
1493
1494static int obj_load_order_prio(struct obj_section *a)
1495{
1496 unsigned long af, ac;
1497
1498 af = a->header.sh_flags;
1499
1500 ac = 0;
1501 if (a->name[0] != '.' || strlen(a->name) != 10 ||
1502 strcmp(a->name + 5, ".init"))
1503 ac |= 32;
1504 if (af & SHF_ALLOC)
1505 ac |= 16;
1506 if (!(af & SHF_WRITE))
1507 ac |= 8;
1508 if (af & SHF_EXECINSTR)
1509 ac |= 4;
1510 if (a->header.sh_type != SHT_NOBITS)
1511 ac |= 2;
1512
1513 return ac;
1514}
1515
1516static void
1517obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec)
1518{
1519 struct obj_section **p;
1520 int prio = obj_load_order_prio(sec);
1521 for (p = f->load_order_search_start; *p; p = &(*p)->load_next)
1522 if (obj_load_order_prio(*p) < prio)
1523 break;
1524 sec->load_next = *p;
1525 *p = sec;
1526}
1527
1528static struct obj_section *obj_create_alloced_section(struct obj_file *f,
1529 const char *name,
1530 unsigned long align,
1531 unsigned long size)
1532{
1533 int newidx = f->header.e_shnum++;
1534 struct obj_section *sec;
1535
1536 f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
1537 f->sections[newidx] = sec = arch_new_section();
1538
1539 memset(sec, 0, sizeof(*sec));
1540 sec->header.sh_type = SHT_PROGBITS;
1541 sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
1542 sec->header.sh_size = size;
1543 sec->header.sh_addralign = align;
1544 sec->name = name;
1545 sec->idx = newidx;
1546 if (size)
1547 sec->contents = xmalloc(size);
1548
1549 obj_insert_section_load_order(f, sec);
1550
1551 return sec;
1552}
1553
1554static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
1555 const char *name,
1556 unsigned long align,
1557 unsigned long size)
1558{
1559 int newidx = f->header.e_shnum++;
1560 struct obj_section *sec;
1561
1562 f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
1563 f->sections[newidx] = sec = arch_new_section();
1564
1565 memset(sec, 0, sizeof(*sec));
1566 sec->header.sh_type = SHT_PROGBITS;
1567 sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
1568 sec->header.sh_size = size;
1569 sec->header.sh_addralign = align;
1570 sec->name = name;
1571 sec->idx = newidx;
1572 if (size)
1573 sec->contents = xmalloc(size);
1574
1575 sec->load_next = f->load_order;
1576 f->load_order = sec;
1577 if (f->load_order_search_start == &f->load_order)
1578 f->load_order_search_start = &sec->load_next;
1579
1580 return sec;
1581}
1582
1583static void *obj_extend_section(struct obj_section *sec, unsigned long more)
1584{
1585 unsigned long oldsize = sec->header.sh_size;
1586 if (more) {
1587 sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
1588 }
1589 return sec->contents + oldsize;
1590}
1591
1592
1593/* Conditionally add the symbols from the given symbol set to the
1594 new module. */
1595
1596static int
1597add_symbols_from(
1598 struct obj_file *f,
1599 int idx, struct new_module_symbol *syms, size_t nsyms)
1600{
1601 struct new_module_symbol *s;
1602 size_t i;
1603 int used = 0;
1604
1605 for (i = 0, s = syms; i < nsyms; ++i, ++s) {
1606
1607 /* Only add symbols that are already marked external. If we
1608 override locals we may cause problems for argument initialization.
1609 We will also create a false dependency on the module. */
1610 struct obj_symbol *sym;
1611
1612 sym = obj_find_symbol(f, (char *) s->name);
1613 if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) {
1614 sym = obj_add_symbol(f, (char *) s->name, -1,
1615 ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
1616 idx, s->value, 0);
1617 /* Did our symbol just get installed? If so, mark the
1618 module as "used". */
1619 if (sym->secidx == idx)
1620 used = 1;
1621 }
1622 }
1623
1624 return used;
1625}
1626
1627static void add_kernel_symbols(struct obj_file *f)
1628{
1629 struct external_module *m;
1630 int i, nused = 0;
1631
1632 /* Add module symbols first. */
1633
1634 for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m)
1635 if (m->nsyms
1636 && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms,
1637 m->nsyms)) m->used = 1, ++nused;
1638
1639 n_ext_modules_used = nused;
1640
1641 /* And finally the symbols from the kernel proper. */
1642
1643 if (nksyms)
1644 add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
1645}
1646
1647static char *get_modinfo_value(struct obj_file *f, const char *key)
1648{
1649 struct obj_section *sec;
1650 char *p, *v, *n, *ep;
1651 size_t klen = strlen(key);
1652
1653 sec = obj_find_section(f, ".modinfo");
1654 if (sec == NULL)
1655 return NULL;
1656 p = sec->contents;
1657 ep = p + sec->header.sh_size;
1658 while (p < ep) {
1659 v = strchr(p, '=');
1660 n = strchr(p, '\0');
1661 if (v) {
1662 if (p + klen == v && strncmp(p, key, klen) == 0)
1663 return v + 1;
1664 } else {
1665 if (p + klen == n && strcmp(p, key) == 0)
1666 return n;
1667 }
1668 p = n + 1;
1669 }
1670
1671 return NULL;
1672}
1673
1674
1675/*======================================================================*/
1676/* Functions relating to module loading in pre 2.1 kernels. */
1677
1678static int
1679old_process_module_arguments(struct obj_file *f, int argc, char **argv)
1680{
1681 while (argc > 0) {
1682 char *p, *q;
1683 struct obj_symbol *sym;
1684 int *loc;
1685
1686 p = *argv;
1687 if ((q = strchr(p, '=')) == NULL) {
1688 argc--;
1689 continue;
1690 }
1691 *q++ = '\0';
1692
1693 sym = obj_find_symbol(f, p);
1694
1695 /* Also check that the parameter was not resolved from the kernel. */
1696 if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
1697 error_msg("symbol for parameter %s not found", p);
1698 return 0;
1699 }
1700
1701 loc = (int *) (f->sections[sym->secidx]->contents + sym->value);
1702
1703 /* Do C quoting if we begin with a ". */
1704 if (*q == '"') {
1705 char *r, *str;
1706
1707 str = alloca(strlen(q));
1708 for (r = str, q++; *q != '"'; ++q, ++r) {
1709 if (*q == '\0') {
1710 error_msg("improperly terminated string argument for %s", p);
1711 return 0;
1712 } else if (*q == '\\')
1713 switch (*++q) {
1714 case 'a':
1715 *r = '\a';
1716 break;
1717 case 'b':
1718 *r = '\b';
1719 break;
1720 case 'e':
1721 *r = '\033';
1722 break;
1723 case 'f':
1724 *r = '\f';
1725 break;
1726 case 'n':
1727 *r = '\n';
1728 break;
1729 case 'r':
1730 *r = '\r';
1731 break;
1732 case 't':
1733 *r = '\t';
1734 break;
1735
1736 case '0':
1737 case '1':
1738 case '2':
1739 case '3':
1740 case '4':
1741 case '5':
1742 case '6':
1743 case '7':
1744 {
1745 int c = *q - '0';
1746 if (q[1] >= '0' && q[1] <= '7') {
1747 c = (c * 8) + *++q - '0';
1748 if (q[1] >= '0' && q[1] <= '7')
1749 c = (c * 8) + *++q - '0';
1750 }
1751 *r = c;
1752 }
1753 break;
1754
1755 default:
1756 *r = *q;
1757 break;
1758 } else
1759 *r = *q;
1760 }
1761 *r = '\0';
1762 obj_string_patch(f, sym->secidx, sym->value, str);
1763 } else if (*q >= '0' && *q <= '9') {
1764 do
1765 *loc++ = strtoul(q, &q, 0);
1766 while (*q++ == ',');
1767 } else {
1768 char *contents = f->sections[sym->secidx]->contents;
1769 char *myloc = contents + sym->value;
1770 char *r; /* To search for commas */
1771
1772 /* Break the string with comas */
1773 while ((r = strchr(q, ',')) != (char *) NULL) {
1774 *r++ = '\0';
1775 obj_string_patch(f, sym->secidx, myloc - contents, q);
1776 myloc += sizeof(char *);
1777 q = r;
1778 }
1779
1780 /* last part */
1781 obj_string_patch(f, sym->secidx, myloc - contents, q);
1782 }
1783
1784 argc--, argv++;
1785 }
1786
1787 return 1;
1788}
1789
1790#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
1791static int old_is_module_checksummed(struct obj_file *f)
1792{
1793 return obj_find_symbol(f, "Using_Versions") != NULL;
1794}
1795/* Get the module's kernel version in the canonical integer form. */
1796
1797static int
1798old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
1799{
1800 struct obj_symbol *sym;
1801 char *p, *q;
1802 int a, b, c;
1803
1804 sym = obj_find_symbol(f, "kernel_version");
1805 if (sym == NULL)
1806 return -1;
1807
1808 p = f->sections[sym->secidx]->contents + sym->value;
1809 strncpy(str, p, STRVERSIONLEN);
1810
1811 a = strtoul(p, &p, 10);
1812 if (*p != '.')
1813 return -1;
1814 b = strtoul(p + 1, &p, 10);
1815 if (*p != '.')
1816 return -1;
1817 c = strtoul(p + 1, &q, 10);
1818 if (p + 1 == q)
1819 return -1;
1820
1821 return a << 16 | b << 8 | c;
1822}
1823
1824#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
1825
1826#ifdef BB_FEATURE_OLD_MODULE_INTERFACE
1827
1828/* Fetch all the symbols and divvy them up as appropriate for the modules. */
1829
1830static int old_get_kernel_symbols(const char *m_name)
1831{
1832 struct old_kernel_sym *ks, *k;
1833 struct new_module_symbol *s;
1834 struct external_module *mod;
1835 int nks, nms, nmod, i;
1836
1837 nks = get_kernel_syms(NULL);
1838 if (nks <= 0) {
1839 if (nks)
1840 perror_msg("get_kernel_syms: %s", m_name);
1841 else
1842 error_msg("No kernel symbols");
1843 return 0;
1844 }
1845
1846 ks = k = xmalloc(nks * sizeof(*ks));
1847
1848 if (get_kernel_syms(ks) != nks) {
1849 perror("inconsistency with get_kernel_syms -- is someone else "
1850 "playing with modules?");
1851 free(ks);
1852 return 0;
1853 }
1854
1855 /* Collect the module information. */
1856
1857 mod = NULL;
1858 nmod = -1;
1859
1860 while (k->name[0] == '#' && k->name[1]) {
1861 struct old_kernel_sym *k2;
1862
1863 /* Find out how many symbols this module has. */
1864 for (k2 = k + 1; k2->name[0] != '#'; ++k2)
1865 continue;
1866 nms = k2 - k - 1;
1867
1868 mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod));
1869 mod[nmod].name = k->name + 1;
1870 mod[nmod].addr = k->value;
1871 mod[nmod].used = 0;
1872 mod[nmod].nsyms = nms;
1873 mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
1874
1875 for (i = 0, ++k; i < nms; ++i, ++s, ++k) {
1876 s->name = (unsigned long) k->name;
1877 s->value = k->value;
1878 }
1879
1880 k = k2;
1881 }
1882
1883 ext_modules = mod;
1884 n_ext_modules = nmod + 1;
1885
1886 /* Now collect the symbols for the kernel proper. */
1887
1888 if (k->name[0] == '#')
1889 ++k;
1890
1891 nksyms = nms = nks - (k - ks);
1892 ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
1893
1894 for (i = 0; i < nms; ++i, ++s, ++k) {
1895 s->name = (unsigned long) k->name;
1896 s->value = k->value;
1897 }
1898
1899 return 1;
1900}
1901
1902/* Return the kernel symbol checksum version, or zero if not used. */
1903
1904static int old_is_kernel_checksummed(void)
1905{
1906 /* Using_Versions is the first symbol. */
1907 if (nksyms > 0
1908 && strcmp((char *) ksyms[0].name,
1909 "Using_Versions") == 0) return ksyms[0].value;
1910 else
1911 return 0;
1912}
1913
1914
1915static int old_create_mod_use_count(struct obj_file *f)
1916{
1917 struct obj_section *sec;
1918
1919 sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long),
1920 sizeof(long));
1921
1922 obj_add_symbol(f, "mod_use_count_", -1,
1923 ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
1924 sizeof(long));
1925
1926 return 1;
1927}
1928
1929static int
1930old_init_module(const char *m_name, struct obj_file *f,
1931 unsigned long m_size)
1932{
1933 char *image;
1934 struct old_mod_routines routines;
1935 struct old_symbol_table *symtab;
1936 int ret;
1937
1938 /* Create the symbol table */
1939 {
1940 int nsyms = 0, strsize = 0, total;
1941
1942 /* Size things first... */
1943 if (flag_export) {
1944 int i;
1945 for (i = 0; i < HASH_BUCKETS; ++i) {
1946 struct obj_symbol *sym;
1947 for (sym = f->symtab[i]; sym; sym = sym->next)
1948 if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
1949 && sym->secidx <= SHN_HIRESERVE)
1950 {
1951 sym->ksymidx = nsyms++;
1952 strsize += strlen(sym->name) + 1;
1953 }
1954 }
1955 }
1956
1957 total = (sizeof(struct old_symbol_table)
1958 + nsyms * sizeof(struct old_module_symbol)
1959 + n_ext_modules_used * sizeof(struct old_module_ref)
1960 + strsize);
1961 symtab = xmalloc(total);
1962 symtab->size = total;
1963 symtab->n_symbols = nsyms;
1964 symtab->n_refs = n_ext_modules_used;
1965
1966 if (flag_export && nsyms) {
1967 struct old_module_symbol *ksym;
1968 char *str;
1969 int i;
1970
1971 ksym = symtab->symbol;
1972 str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol)
1973 + n_ext_modules_used * sizeof(struct old_module_ref));
1974
1975 for (i = 0; i < HASH_BUCKETS; ++i) {
1976 struct obj_symbol *sym;
1977 for (sym = f->symtab[i]; sym; sym = sym->next)
1978 if (sym->ksymidx >= 0) {
1979 ksym->addr = obj_symbol_final_value(f, sym);
1980 ksym->name =
1981 (unsigned long) str - (unsigned long) symtab;
1982
1983 strcpy(str, sym->name);
1984 str += strlen(sym->name) + 1;
1985 ksym++;
1986 }
1987 }
1988 }
1989
1990 if (n_ext_modules_used) {
1991 struct old_module_ref *ref;
1992 int i;
1993
1994 ref = (struct old_module_ref *)
1995 ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol));
1996
1997 for (i = 0; i < n_ext_modules; ++i)
1998 if (ext_modules[i].used)
1999 ref++->module = ext_modules[i].addr;
2000 }
2001 }
2002
2003 /* Fill in routines. */
2004
2005 routines.init =
2006 obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
2007 routines.cleanup =
2008 obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
2009
2010 /* Whew! All of the initialization is complete. Collect the final
2011 module image and give it to the kernel. */
2012
2013 image = xmalloc(m_size);
2014 obj_create_image(f, image);
2015
2016 /* image holds the complete relocated module, accounting correctly for
2017 mod_use_count. However the old module kernel support assume that
2018 it is receiving something which does not contain mod_use_count. */
2019 ret = old_sys_init_module(m_name, image + sizeof(long),
2020 m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN
2021 : 0), &routines, symtab);
2022 if (ret)
2023 perror_msg("init_module: %s", m_name);
2024
2025 free(image);
2026 free(symtab);
2027
2028 return ret == 0;
2029}
2030
2031#else
2032
2033#define old_create_mod_use_count(x) TRUE
2034#define old_init_module(x, y, z) TRUE
2035
2036#endif /* BB_FEATURE_OLD_MODULE_INTERFACE */
2037
2038
2039
2040/*======================================================================*/
2041/* Functions relating to module loading after 2.1.18. */
2042
2043static int
2044new_process_module_arguments(struct obj_file *f, int argc, char **argv)
2045{
2046 while (argc > 0) {
2047 char *p, *q, *key;
2048 struct obj_symbol *sym;
2049 char *contents, *loc;
2050 int min, max, n;
2051
2052 p = *argv;
2053 if ((q = strchr(p, '=')) == NULL) {
2054 argc--;
2055 continue;
2056 }
2057
2058 key = alloca(q - p + 6);
2059 memcpy(key, "parm_", 5);
2060 memcpy(key + 5, p, q - p);
2061 key[q - p + 5] = 0;
2062
2063 p = get_modinfo_value(f, key);
2064 key += 5;
2065 if (p == NULL) {
2066 error_msg("invalid parameter %s", key);
2067 return 0;
2068 }
2069
2070 sym = obj_find_symbol(f, key);
2071
2072 /* Also check that the parameter was not resolved from the kernel. */
2073 if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
2074 error_msg("symbol for parameter %s not found", key);
2075 return 0;
2076 }
2077
2078 if (isdigit(*p)) {
2079 min = strtoul(p, &p, 10);
2080 if (*p == '-')
2081 max = strtoul(p + 1, &p, 10);
2082 else
2083 max = min;
2084 } else
2085 min = max = 1;
2086
2087 contents = f->sections[sym->secidx]->contents;
2088 loc = contents + sym->value;
2089 n = (*++q != '\0');
2090
2091 while (1) {
2092 if ((*p == 's') || (*p == 'c')) {
2093 char *str;
2094
2095 /* Do C quoting if we begin with a ", else slurp the lot. */
2096 if (*q == '"') {
2097 char *r;
2098
2099 str = alloca(strlen(q));
2100 for (r = str, q++; *q != '"'; ++q, ++r) {
2101 if (*q == '\0') {
2102 error_msg("improperly terminated string argument for %s",
2103 key);
2104 return 0;
2105 } else if (*q == '\\')
2106 switch (*++q) {
2107 case 'a':
2108 *r = '\a';
2109 break;
2110 case 'b':
2111 *r = '\b';
2112 break;
2113 case 'e':
2114 *r = '\033';
2115 break;
2116 case 'f':
2117 *r = '\f';
2118 break;
2119 case 'n':
2120 *r = '\n';
2121 break;
2122 case 'r':
2123 *r = '\r';
2124 break;
2125 case 't':
2126 *r = '\t';
2127 break;
2128
2129 case '0':
2130 case '1':
2131 case '2':
2132 case '3':
2133 case '4':
2134 case '5':
2135 case '6':
2136 case '7':
2137 {
2138 int c = *q - '0';
2139 if (q[1] >= '0' && q[1] <= '7') {
2140 c = (c * 8) + *++q - '0';
2141 if (q[1] >= '0' && q[1] <= '7')
2142 c = (c * 8) + *++q - '0';
2143 }
2144 *r = c;
2145 }
2146 break;
2147
2148 default:
2149 *r = *q;
2150 break;
2151 } else
2152 *r = *q;
2153 }
2154 *r = '\0';
2155 ++q;
2156 } else {
2157 char *r;
2158
2159 /* In this case, the string is not quoted. We will break
2160 it using the coma (like for ints). If the user wants to
2161 include comas in a string, he just has to quote it */
2162
2163 /* Search the next coma */
2164 r = strchr(q, ',');
2165
2166 /* Found ? */
2167 if (r != (char *) NULL) {
2168 /* Recopy the current field */
2169 str = alloca(r - q + 1);
2170 memcpy(str, q, r - q);
2171
2172 /* I don't know if it is usefull, as the previous case
2173 doesn't null terminate the string ??? */
2174 str[r - q] = '\0';
2175
2176 /* Keep next fields */
2177 q = r;
2178 } else {
2179 /* last string */
2180 str = q;
2181 q = "";
2182 }
2183 }
2184
2185 if (*p == 's') {
2186 /* Normal string */
2187 obj_string_patch(f, sym->secidx, loc - contents, str);
2188 loc += tgt_sizeof_char_p;
2189 } else {
2190 /* Array of chars (in fact, matrix !) */
2191 unsigned long charssize; /* size of each member */
2192
2193 /* Get the size of each member */
2194 /* Probably we should do that outside the loop ? */
2195 if (!isdigit(*(p + 1))) {
2196 error_msg("parameter type 'c' for %s must be followed by"
2197 " the maximum size", key);
2198 return 0;
2199 }
2200 charssize = strtoul(p + 1, (char **) NULL, 10);
2201
2202 /* Check length */
2203 if (strlen(str) >= charssize) {
2204 error_msg("string too long for %s (max %ld)", key,
2205 charssize - 1);
2206 return 0;
2207 }
2208
2209 /* Copy to location */
2210 strcpy((char *) loc, str);
2211 loc += charssize;
2212 }
2213 } else {
2214 long v = strtoul(q, &q, 0);
2215 switch (*p) {
2216 case 'b':
2217 *loc++ = v;
2218 break;
2219 case 'h':
2220 *(short *) loc = v;
2221 loc += tgt_sizeof_short;
2222 break;
2223 case 'i':
2224 *(int *) loc = v;
2225 loc += tgt_sizeof_int;
2226 break;
2227 case 'l':
2228 *(long *) loc = v;
2229 loc += tgt_sizeof_long;
2230 break;
2231
2232 default:
2233 error_msg("unknown parameter type '%c' for %s", *p, key);
2234 return 0;
2235 }
2236 }
2237
2238 retry_end_of_value:
2239 switch (*q) {
2240 case '\0':
2241 goto end_of_arg;
2242
2243 case ' ':
2244 case '\t':
2245 case '\n':
2246 case '\r':
2247 ++q;
2248 goto retry_end_of_value;
2249
2250 case ',':
2251 if (++n > max) {
2252 error_msg("too many values for %s (max %d)", key, max);
2253 return 0;
2254 }
2255 ++q;
2256 break;
2257
2258 default:
2259 error_msg("invalid argument syntax for %s", key);
2260 return 0;
2261 }
2262 }
2263
2264 end_of_arg:
2265 if (n < min) {
2266 error_msg("too few values for %s (min %d)", key, min);
2267 return 0;
2268 }
2269
2270 argc--, argv++;
2271 }
2272
2273 return 1;
2274}
2275
2276#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
2277static int new_is_module_checksummed(struct obj_file *f)
2278{
2279 const char *p = get_modinfo_value(f, "using_checksums");
2280 if (p)
2281 return atoi(p);
2282 else
2283 return 0;
2284}
2285
2286/* Get the module's kernel version in the canonical integer form. */
2287
2288static int
2289new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
2290{
2291 char *p, *q;
2292 int a, b, c;
2293
2294 p = get_modinfo_value(f, "kernel_version");
2295 if (p == NULL)
2296 return -1;
2297 strncpy(str, p, STRVERSIONLEN);
2298
2299 a = strtoul(p, &p, 10);
2300 if (*p != '.')
2301 return -1;
2302 b = strtoul(p + 1, &p, 10);
2303 if (*p != '.')
2304 return -1;
2305 c = strtoul(p + 1, &q, 10);
2306 if (p + 1 == q)
2307 return -1;
2308
2309 return a << 16 | b << 8 | c;
2310}
2311
2312#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
2313
2314
2315#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
2316
2317/* Fetch the loaded modules, and all currently exported symbols. */
2318
2319static int new_get_kernel_symbols(void)
2320{
2321 char *module_names, *mn;
2322 struct external_module *modules, *m;
2323 struct new_module_symbol *syms, *s;
2324 size_t ret, bufsize, nmod, nsyms, i, j;
2325
2326 /* Collect the loaded modules. */
2327
2328 module_names = xmalloc(bufsize = 256);
2329 retry_modules_load:
2330 if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
2331 if (errno == ENOSPC && bufsize < ret) {
2332 module_names = xrealloc(module_names, bufsize = ret);
2333 goto retry_modules_load;
2334 }
2335 perror_msg("QM_MODULES");
2336 return 0;
2337 }
2338
2339 n_ext_modules = nmod = ret;
2340
2341 /* Collect the modules' symbols. */
2342
2343 if (nmod){
2344 ext_modules = modules = xmalloc(nmod * sizeof(*modules));
2345 memset(modules, 0, nmod * sizeof(*modules));
2346 for (i = 0, mn = module_names, m = modules;
2347 i < nmod; ++i, ++m, mn += strlen(mn) + 1) {
2348 struct new_module_info info;
2349
2350 if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
2351 if (errno == ENOENT) {
2352 /* The module was removed out from underneath us. */
2353 continue;
2354 }
2355 perror_msg("query_module: QM_INFO: %s", mn);
2356 return 0;
2357 }
2358
2359 syms = xmalloc(bufsize = 1024);
2360 retry_mod_sym_load:
2361 if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
2362 switch (errno) {
2363 case ENOSPC:
2364 syms = xrealloc(syms, bufsize = ret);
2365 goto retry_mod_sym_load;
2366 case ENOENT:
2367 /* The module was removed out from underneath us. */
2368 continue;
2369 default:
2370 perror_msg("query_module: QM_SYMBOLS: %s", mn);
2371 return 0;
2372 }
2373 }
2374 nsyms = ret;
2375
2376 m->name = mn;
2377 m->addr = info.addr;
2378 m->nsyms = nsyms;
2379 m->syms = syms;
2380
2381 for (j = 0, s = syms; j < nsyms; ++j, ++s) {
2382 s->name += (unsigned long) syms;
2383 }
2384 }
2385 }
2386
2387 /* Collect the kernel's symbols. */
2388
2389 syms = xmalloc(bufsize = 16 * 1024);
2390 retry_kern_sym_load:
2391 if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
2392 if (errno == ENOSPC && bufsize < ret) {
2393 syms = xrealloc(syms, bufsize = ret);
2394 goto retry_kern_sym_load;
2395 }
2396 perror_msg("kernel: QM_SYMBOLS");
2397 return 0;
2398 }
2399 nksyms = nsyms = ret;
2400 ksyms = syms;
2401
2402 for (j = 0, s = syms; j < nsyms; ++j, ++s) {
2403 s->name += (unsigned long) syms;
2404 }
2405 return 1;
2406}
2407
2408
2409/* Return the kernel symbol checksum version, or zero if not used. */
2410
2411static int new_is_kernel_checksummed(void)
2412{
2413 struct new_module_symbol *s;
2414 size_t i;
2415
2416 /* Using_Versions is not the first symbol, but it should be in there. */
2417
2418 for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
2419 if (strcmp((char *) s->name, "Using_Versions") == 0)
2420 return s->value;
2421
2422 return 0;
2423}
2424
2425
2426static int new_create_this_module(struct obj_file *f, const char *m_name)
2427{
2428 struct obj_section *sec;
2429
2430 sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
2431 sizeof(struct new_module));
2432 memset(sec->contents, 0, sizeof(struct new_module));
2433
2434 obj_add_symbol(f, "__this_module", -1,
2435 ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
2436 sizeof(struct new_module));
2437
2438 obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
2439 m_name);
2440
2441 return 1;
2442}
2443
2444
2445static int new_create_module_ksymtab(struct obj_file *f)
2446{
2447 struct obj_section *sec;
2448 int i;
2449
2450 /* We must always add the module references. */
2451
2452 if (n_ext_modules_used) {
2453 struct new_module_ref *dep;
2454 struct obj_symbol *tm;
2455
2456 sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
2457 (sizeof(struct new_module_ref)
2458 * n_ext_modules_used));
2459 if (!sec)
2460 return 0;
2461
2462 tm = obj_find_symbol(f, "__this_module");
2463 dep = (struct new_module_ref *) sec->contents;
2464 for (i = 0; i < n_ext_modules; ++i)
2465 if (ext_modules[i].used) {
2466 dep->dep = ext_modules[i].addr;
2467 obj_symbol_patch(f, sec->idx,
2468 (char *) &dep->ref - sec->contents, tm);
2469 dep->next_ref = 0;
2470 ++dep;
2471 }
2472 }
2473
2474 if (flag_export && !obj_find_section(f, "__ksymtab")) {
2475 size_t nsyms;
2476 int *loaded;
2477
2478 sec =
2479 obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p,
2480 0);
2481
2482 /* We don't want to export symbols residing in sections that
2483 aren't loaded. There are a number of these created so that
2484 we make sure certain module options don't appear twice. */
2485
2486 loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
2487 while (--i >= 0)
2488 loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
2489
2490 for (nsyms = i = 0; i < HASH_BUCKETS; ++i) {
2491 struct obj_symbol *sym;
2492 for (sym = f->symtab[i]; sym; sym = sym->next)
2493 if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
2494 && sym->secidx <= SHN_HIRESERVE
2495 && (sym->secidx >= SHN_LORESERVE
2496 || loaded[sym->secidx])) {
2497 ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p;
2498
2499 obj_symbol_patch(f, sec->idx, ofs, sym);
2500 obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p,
2501 sym->name);
2502
2503 nsyms++;
2504 }
2505 }
2506
2507 obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p);
2508 }
2509
2510 return 1;
2511}
2512
2513
2514static int
2515new_init_module(const char *m_name, struct obj_file *f,
2516 unsigned long m_size)
2517{
2518 struct new_module *module;
2519 struct obj_section *sec;
2520 void *image;
2521 int ret;
2522 tgt_long m_addr;
2523
2524 sec = obj_find_section(f, ".this");
2525 if (!sec || !sec->contents) {
2526 perror_msg_and_die("corrupt module %s?",m_name);
2527 }
2528 module = (struct new_module *) sec->contents;
2529 m_addr = sec->header.sh_addr;
2530
2531 module->size_of_struct = sizeof(*module);
2532 module->size = m_size;
2533 module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
2534
2535 sec = obj_find_section(f, "__ksymtab");
2536 if (sec && sec->header.sh_size) {
2537 module->syms = sec->header.sh_addr;
2538 module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
2539 }
2540
2541 if (n_ext_modules_used) {
2542 sec = obj_find_section(f, ".kmodtab");
2543 module->deps = sec->header.sh_addr;
2544 module->ndeps = n_ext_modules_used;
2545 }
2546
2547 module->init =
2548 obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
2549 module->cleanup =
2550 obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
2551
2552 sec = obj_find_section(f, "__ex_table");
2553 if (sec) {
2554 module->ex_table_start = sec->header.sh_addr;
2555 module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
2556 }
2557
2558 sec = obj_find_section(f, ".text.init");
2559 if (sec) {
2560 module->runsize = sec->header.sh_addr - m_addr;
2561 }
2562 sec = obj_find_section(f, ".data.init");
2563 if (sec) {
2564 if (!module->runsize ||
2565 module->runsize > sec->header.sh_addr - m_addr)
2566 module->runsize = sec->header.sh_addr - m_addr;
2567 }
2568 sec = obj_find_section(f, ARCHDATA_SEC_NAME);
2569 if (sec && sec->header.sh_size) {
2570 module->archdata_start = (void*)sec->header.sh_addr;
2571 module->archdata_end = module->archdata_start + sec->header.sh_size;
2572 }
2573 sec = obj_find_section(f, KALLSYMS_SEC_NAME);
2574 if (sec && sec->header.sh_size) {
2575 module->kallsyms_start = (void*)sec->header.sh_addr;
2576 module->kallsyms_end = module->kallsyms_start + sec->header.sh_size;
2577 }
2578
2579 if (!arch_init_module(f, module))
2580 return 0;
2581
2582 /* Whew! All of the initialization is complete. Collect the final
2583 module image and give it to the kernel. */
2584
2585 image = xmalloc(m_size);
2586 obj_create_image(f, image);
2587
2588 ret = new_sys_init_module(m_name, (struct new_module *) image);
2589 if (ret)
2590 perror_msg("init_module: %s", m_name);
2591
2592 free(image);
2593
2594 return ret == 0;
2595}
2596
2597#else
2598
2599#define new_init_module(x, y, z) TRUE
2600#define new_create_this_module(x, y) 0
2601#define new_create_module_ksymtab(x)
2602#define query_module(v, w, x, y, z) -1
2603
2604#endif /* BB_FEATURE_NEW_MODULE_INTERFACE */
2605
2606
2607/*======================================================================*/
2608
2609static int
2610obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
2611 const char *string)
2612{
2613 struct obj_string_patch *p;
2614 struct obj_section *strsec;
2615 size_t len = strlen(string) + 1;
2616 char *loc;
2617
2618 p = xmalloc(sizeof(*p));
2619 p->next = f->string_patches;
2620 p->reloc_secidx = secidx;
2621 p->reloc_offset = offset;
2622 f->string_patches = p;
2623
2624 strsec = obj_find_section(f, ".kstrtab");
2625 if (strsec == NULL) {
2626 strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
2627 p->string_offset = 0;
2628 loc = strsec->contents;
2629 } else {
2630 p->string_offset = strsec->header.sh_size;
2631 loc = obj_extend_section(strsec, len);
2632 }
2633 memcpy(loc, string, len);
2634
2635 return 1;
2636}
2637
2638static int
2639obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
2640 struct obj_symbol *sym)
2641{
2642 struct obj_symbol_patch *p;
2643
2644 p = xmalloc(sizeof(*p));
2645 p->next = f->symbol_patches;
2646 p->reloc_secidx = secidx;
2647 p->reloc_offset = offset;
2648 p->sym = sym;
2649 f->symbol_patches = p;
2650
2651 return 1;
2652}
2653
2654static int obj_check_undefineds(struct obj_file *f)
2655{
2656 unsigned long i;
2657 int ret = 1;
2658
2659 for (i = 0; i < HASH_BUCKETS; ++i) {
2660 struct obj_symbol *sym;
2661 for (sym = f->symtab[i]; sym; sym = sym->next)
2662 if (sym->secidx == SHN_UNDEF) {
2663 if (ELFW(ST_BIND) (sym->info) == STB_WEAK) {
2664 sym->secidx = SHN_ABS;
2665 sym->value = 0;
2666 } else {
2667 error_msg("unresolved symbol %s", sym->name);
2668 ret = 0;
2669 }
2670 }
2671 }
2672
2673 return ret;
2674}
2675
2676static void obj_allocate_commons(struct obj_file *f)
2677{
2678 struct common_entry {
2679 struct common_entry *next;
2680 struct obj_symbol *sym;
2681 } *common_head = NULL;
2682
2683 unsigned long i;
2684
2685 for (i = 0; i < HASH_BUCKETS; ++i) {
2686 struct obj_symbol *sym;
2687 for (sym = f->symtab[i]; sym; sym = sym->next)
2688 if (sym->secidx == SHN_COMMON) {
2689 /* Collect all COMMON symbols and sort them by size so as to
2690 minimize space wasted by alignment requirements. */
2691 {
2692 struct common_entry **p, *n;
2693 for (p = &common_head; *p; p = &(*p)->next)
2694 if (sym->size <= (*p)->sym->size)
2695 break;
2696
2697 n = alloca(sizeof(*n));
2698 n->next = *p;
2699 n->sym = sym;
2700 *p = n;
2701 }
2702 }
2703 }
2704
2705 for (i = 1; i < f->local_symtab_size; ++i) {
2706 struct obj_symbol *sym = f->local_symtab[i];
2707 if (sym && sym->secidx == SHN_COMMON) {
2708 struct common_entry **p, *n;
2709 for (p = &common_head; *p; p = &(*p)->next)
2710 if (sym == (*p)->sym)
2711 break;
2712 else if (sym->size < (*p)->sym->size) {
2713 n = alloca(sizeof(*n));
2714 n->next = *p;
2715 n->sym = sym;
2716 *p = n;
2717 break;
2718 }
2719 }
2720 }
2721
2722 if (common_head) {
2723 /* Find the bss section. */
2724 for (i = 0; i < f->header.e_shnum; ++i)
2725 if (f->sections[i]->header.sh_type == SHT_NOBITS)
2726 break;
2727
2728 /* If for some reason there hadn't been one, create one. */
2729 if (i == f->header.e_shnum) {
2730 struct obj_section *sec;
2731
2732 f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec));
2733 f->sections[i] = sec = arch_new_section();
2734 f->header.e_shnum = i + 1;
2735
2736 memset(sec, 0, sizeof(*sec));
2737 sec->header.sh_type = SHT_PROGBITS;
2738 sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
2739 sec->name = ".bss";
2740 sec->idx = i;
2741 }
2742
2743 /* Allocate the COMMONS. */
2744 {
2745 ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
2746 ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
2747 struct common_entry *c;
2748
2749 for (c = common_head; c; c = c->next) {
2750 ElfW(Addr) align = c->sym->value;
2751
2752 if (align > max_align)
2753 max_align = align;
2754 if (bss_size & (align - 1))
2755 bss_size = (bss_size | (align - 1)) + 1;
2756
2757 c->sym->secidx = i;
2758 c->sym->value = bss_size;
2759
2760 bss_size += c->sym->size;
2761 }
2762
2763 f->sections[i]->header.sh_size = bss_size;
2764 f->sections[i]->header.sh_addralign = max_align;
2765 }
2766 }
2767
2768 /* For the sake of patch relocation and parameter initialization,
2769 allocate zeroed data for NOBITS sections now. Note that after
2770 this we cannot assume NOBITS are really empty. */
2771 for (i = 0; i < f->header.e_shnum; ++i) {
2772 struct obj_section *s = f->sections[i];
2773 if (s->header.sh_type == SHT_NOBITS) {
2774 if (s->header.sh_size != 0)
2775 s->contents = memset(xmalloc(s->header.sh_size),
2776 0, s->header.sh_size);
2777 else
2778 s->contents = NULL;
2779
2780 s->header.sh_type = SHT_PROGBITS;
2781 }
2782 }
2783}
2784
2785static unsigned long obj_load_size(struct obj_file *f)
2786{
2787 unsigned long dot = 0;
2788 struct obj_section *sec;
2789
2790 /* Finalize the positions of the sections relative to one another. */
2791
2792 for (sec = f->load_order; sec; sec = sec->load_next) {
2793 ElfW(Addr) align;
2794
2795 align = sec->header.sh_addralign;
2796 if (align && (dot & (align - 1)))
2797 dot = (dot | (align - 1)) + 1;
2798
2799 sec->header.sh_addr = dot;
2800 dot += sec->header.sh_size;
2801 }
2802
2803 return dot;
2804}
2805
2806static int obj_relocate(struct obj_file *f, ElfW(Addr) base)
2807{
2808 int i, n = f->header.e_shnum;
2809 int ret = 1;
2810
2811 /* Finalize the addresses of the sections. */
2812
2813 f->baseaddr = base;
2814 for (i = 0; i < n; ++i)
2815 f->sections[i]->header.sh_addr += base;
2816
2817 /* And iterate over all of the relocations. */
2818
2819 for (i = 0; i < n; ++i) {
2820 struct obj_section *relsec, *symsec, *targsec, *strsec;
2821 ElfW(RelM) * rel, *relend;
2822 ElfW(Sym) * symtab;
2823 const char *strtab;
2824
2825 relsec = f->sections[i];
2826 if (relsec->header.sh_type != SHT_RELM)
2827 continue;
2828
2829 symsec = f->sections[relsec->header.sh_link];
2830 targsec = f->sections[relsec->header.sh_info];
2831 strsec = f->sections[symsec->header.sh_link];
2832
2833 rel = (ElfW(RelM) *) relsec->contents;
2834 relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
2835 symtab = (ElfW(Sym) *) symsec->contents;
2836 strtab = (const char *) strsec->contents;
2837
2838 for (; rel < relend; ++rel) {
2839 ElfW(Addr) value = 0;
2840 struct obj_symbol *intsym = NULL;
2841 unsigned long symndx;
2842 ElfW(Sym) * extsym = 0;
2843 const char *errmsg;
2844
2845 /* Attempt to find a value to use for this relocation. */
2846
2847 symndx = ELFW(R_SYM) (rel->r_info);
2848 if (symndx) {
2849 /* Note we've already checked for undefined symbols. */
2850
2851 extsym = &symtab[symndx];
2852 if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) {
2853 /* Local symbols we look up in the local table to be sure
2854 we get the one that is really intended. */
2855 intsym = f->local_symtab[symndx];
2856 } else {
2857 /* Others we look up in the hash table. */
2858 const char *name;
2859 if (extsym->st_name)
2860 name = strtab + extsym->st_name;
2861 else
2862 name = f->sections[extsym->st_shndx]->name;
2863 intsym = obj_find_symbol(f, name);
2864 }
2865
2866 value = obj_symbol_final_value(f, intsym);
2867 intsym->referenced = 1;
2868 }
2869#if SHT_RELM == SHT_RELA
2870#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
2871 /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */
2872 if (!extsym || !extsym->st_name ||
2873 ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL)
2874#endif
2875 value += rel->r_addend;
2876#endif
2877
2878 /* Do it! */
2879 switch (arch_apply_relocation
2880 (f, targsec, symsec, intsym, rel, value)) {
2881 case obj_reloc_ok:
2882 break;
2883
2884 case obj_reloc_overflow:
2885 errmsg = "Relocation overflow";
2886 goto bad_reloc;
2887 case obj_reloc_dangerous:
2888 errmsg = "Dangerous relocation";
2889 goto bad_reloc;
2890 case obj_reloc_unhandled:
2891 errmsg = "Unhandled relocation";
2892 bad_reloc:
2893 if (extsym) {
2894 error_msg("%s of type %ld for %s", errmsg,
2895 (long) ELFW(R_TYPE) (rel->r_info),
2896 strtab + extsym->st_name);
2897 } else {
2898 error_msg("%s of type %ld", errmsg,
2899 (long) ELFW(R_TYPE) (rel->r_info));
2900 }
2901 ret = 0;
2902 break;
2903 }
2904 }
2905 }
2906
2907 /* Finally, take care of the patches. */
2908
2909 if (f->string_patches) {
2910 struct obj_string_patch *p;
2911 struct obj_section *strsec;
2912 ElfW(Addr) strsec_base;
2913 strsec = obj_find_section(f, ".kstrtab");
2914 strsec_base = strsec->header.sh_addr;
2915
2916 for (p = f->string_patches; p; p = p->next) {
2917 struct obj_section *targsec = f->sections[p->reloc_secidx];
2918 *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
2919 = strsec_base + p->string_offset;
2920 }
2921 }
2922
2923 if (f->symbol_patches) {
2924 struct obj_symbol_patch *p;
2925
2926 for (p = f->symbol_patches; p; p = p->next) {
2927 struct obj_section *targsec = f->sections[p->reloc_secidx];
2928 *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
2929 = obj_symbol_final_value(f, p->sym);
2930 }
2931 }
2932
2933 return ret;
2934}
2935
2936static int obj_create_image(struct obj_file *f, char *image)
2937{
2938 struct obj_section *sec;
2939 ElfW(Addr) base = f->baseaddr;
2940
2941 for (sec = f->load_order; sec; sec = sec->load_next) {
2942 char *secimg;
2943
2944 if (sec->contents == 0 || sec->header.sh_size == 0)
2945 continue;
2946
2947 secimg = image + (sec->header.sh_addr - base);
2948
2949 /* Note that we allocated data for NOBITS sections earlier. */
2950 memcpy(secimg, sec->contents, sec->header.sh_size);
2951 }
2952
2953 return 1;
2954}
2955
2956/*======================================================================*/
2957
2958static struct obj_file *obj_load(FILE * fp, int loadprogbits)
2959{
2960 struct obj_file *f;
2961 ElfW(Shdr) * section_headers;
2962 int shnum, i;
2963 char *shstrtab;
2964
2965 /* Read the file header. */
2966
2967 f = arch_new_file();
2968 memset(f, 0, sizeof(*f));
2969 f->symbol_cmp = strcmp;
2970 f->symbol_hash = obj_elf_hash;
2971 f->load_order_search_start = &f->load_order;
2972
2973 fseek(fp, 0, SEEK_SET);
2974 if (fread(&f->header, sizeof(f->header), 1, fp) != 1) {
2975 perror_msg("error reading ELF header");
2976 return NULL;
2977 }
2978
2979 if (f->header.e_ident[EI_MAG0] != ELFMAG0
2980 || f->header.e_ident[EI_MAG1] != ELFMAG1
2981 || f->header.e_ident[EI_MAG2] != ELFMAG2
2982 || f->header.e_ident[EI_MAG3] != ELFMAG3) {
2983 error_msg("not an ELF file");
2984 return NULL;
2985 }
2986 if (f->header.e_ident[EI_CLASS] != ELFCLASSM
2987 || f->header.e_ident[EI_DATA] != ELFDATAM
2988 || f->header.e_ident[EI_VERSION] != EV_CURRENT
2989 || !MATCH_MACHINE(f->header.e_machine)) {
2990 error_msg("ELF file not for this architecture");
2991 return NULL;
2992 }
2993 if (f->header.e_type != ET_REL) {
2994 error_msg("ELF file not a relocatable object");
2995 return NULL;
2996 }
2997
2998 /* Read the section headers. */
2999
3000 if (f->header.e_shentsize != sizeof(ElfW(Shdr))) {
3001 error_msg("section header size mismatch: %lu != %lu",
3002 (unsigned long) f->header.e_shentsize,
3003 (unsigned long) sizeof(ElfW(Shdr)));
3004 return NULL;
3005 }
3006
3007 shnum = f->header.e_shnum;
3008 f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
3009 memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
3010
3011 section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
3012 fseek(fp, f->header.e_shoff, SEEK_SET);
3013 if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) {
3014 perror_msg("error reading ELF section headers");
3015 return NULL;
3016 }
3017
3018 /* Read the section data. */
3019
3020 for (i = 0; i < shnum; ++i) {
3021 struct obj_section *sec;
3022
3023 f->sections[i] = sec = arch_new_section();
3024 memset(sec, 0, sizeof(*sec));
3025
3026 sec->header = section_headers[i];
3027 sec->idx = i;
3028
3029 if(sec->header.sh_size) switch (sec->header.sh_type) {
3030 case SHT_NULL:
3031 case SHT_NOTE:
3032 case SHT_NOBITS:
3033 /* ignore */
3034 break;
3035
3036 case SHT_PROGBITS:
3037#if LOADBITS
3038 if (!loadprogbits) {
3039 sec->contents = NULL;
3040 break;
3041 }
3042#endif
3043 case SHT_SYMTAB:
3044 case SHT_STRTAB:
3045 case SHT_RELM:
3046 if (sec->header.sh_size > 0) {
3047 sec->contents = xmalloc(sec->header.sh_size);
3048 fseek(fp, sec->header.sh_offset, SEEK_SET);
3049 if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
3050 perror_msg("error reading ELF section data");
3051 return NULL;
3052 }
3053 } else {
3054 sec->contents = NULL;
3055 }
3056 break;
3057
3058#if SHT_RELM == SHT_REL
3059 case SHT_RELA:
3060 error_msg("RELA relocations not supported on this architecture");
3061 return NULL;
3062#else
3063 case SHT_REL:
3064 error_msg("REL relocations not supported on this architecture");
3065 return NULL;
3066#endif
3067
3068 default:
3069 if (sec->header.sh_type >= SHT_LOPROC) {
3070 /* Assume processor specific section types are debug
3071 info and can safely be ignored. If this is ever not
3072 the case (Hello MIPS?), don't put ifdefs here but
3073 create an arch_load_proc_section(). */
3074 break;
3075 }
3076
3077 error_msg("can't handle sections of type %ld",
3078 (long) sec->header.sh_type);
3079 return NULL;
3080 }
3081 }
3082
3083 /* Do what sort of interpretation as needed by each section. */
3084
3085 shstrtab = f->sections[f->header.e_shstrndx]->contents;
3086
3087 for (i = 0; i < shnum; ++i) {
3088 struct obj_section *sec = f->sections[i];
3089 sec->name = shstrtab + sec->header.sh_name;
3090 }
3091
3092 for (i = 0; i < shnum; ++i) {
3093 struct obj_section *sec = f->sections[i];
3094
3095 /* .modinfo should be contents only but gcc has no attribute for that.
3096 * The kernel may have marked .modinfo as ALLOC, ignore this bit.
3097 */
3098 if (strcmp(sec->name, ".modinfo") == 0)
3099 sec->header.sh_flags &= ~SHF_ALLOC;
3100
3101 if (sec->header.sh_flags & SHF_ALLOC)
3102 obj_insert_section_load_order(f, sec);
3103
3104 switch (sec->header.sh_type) {
3105 case SHT_SYMTAB:
3106 {
3107 unsigned long nsym, j;
3108 char *strtab;
3109 ElfW(Sym) * sym;
3110
3111 if (sec->header.sh_entsize != sizeof(ElfW(Sym))) {
3112 error_msg("symbol size mismatch: %lu != %lu",
3113 (unsigned long) sec->header.sh_entsize,
3114 (unsigned long) sizeof(ElfW(Sym)));
3115 return NULL;
3116 }
3117
3118 nsym = sec->header.sh_size / sizeof(ElfW(Sym));
3119 strtab = f->sections[sec->header.sh_link]->contents;
3120 sym = (ElfW(Sym) *) sec->contents;
3121
3122 /* Allocate space for a table of local symbols. */
3123 j = f->local_symtab_size = sec->header.sh_info;
3124 f->local_symtab = xcalloc(j, sizeof(struct obj_symbol *));
3125
3126 /* Insert all symbols into the hash table. */
3127 for (j = 1, ++sym; j < nsym; ++j, ++sym) {
3128 const char *name;
3129 if (sym->st_name)
3130 name = strtab + sym->st_name;
3131 else
3132 name = f->sections[sym->st_shndx]->name;
3133
3134 obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
3135 sym->st_value, sym->st_size);
3136 }
3137 }
3138 break;
3139
3140 case SHT_RELM:
3141 if (sec->header.sh_entsize != sizeof(ElfW(RelM))) {
3142 error_msg("relocation entry size mismatch: %lu != %lu",
3143 (unsigned long) sec->header.sh_entsize,
3144 (unsigned long) sizeof(ElfW(RelM)));
3145 return NULL;
3146 }
3147 break;
3148 /* XXX Relocation code from modutils-2.3.19 is not here.
3149 * Why? That's about 20 lines of code from obj/obj_load.c,
3150 * which gets done in a second pass through the sections.
3151 * This BusyBox insmod does similar work in obj_relocate(). */
3152 }
3153 }
3154
3155 return f;
3156}
3157
3158#ifdef BB_FEATURE_INSMOD_LOADINKMEM
3159/*
3160 * load the unloaded sections directly into the memory allocated by
3161 * kernel for the module
3162 */
3163
3164static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase)
3165{
3166 ElfW(Addr) base = f->baseaddr;
3167 struct obj_section* sec;
3168
3169 for (sec = f->load_order; sec; sec = sec->load_next) {
3170
3171 /* section already loaded? */
3172 if (sec->contents != NULL)
3173 continue;
3174
3175 if (sec->header.sh_size == 0)
3176 continue;
3177
3178 sec->contents = imagebase + (sec->header.sh_addr - base);
3179 fseek(fp, sec->header.sh_offset, SEEK_SET);
3180 if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
3181 error_msg("error reading ELF section data: %s\n", strerror(errno));
3182 return 0;
3183 }
3184
3185 }
3186 return 1;
3187}
3188#endif
3189
3190static void hide_special_symbols(struct obj_file *f)
3191{
3192 static const char *const specials[] = {
3193 "cleanup_module",
3194 "init_module",
3195 "kernel_version",
3196 NULL
3197 };
3198
3199 struct obj_symbol *sym;
3200 const char *const *p;
3201
3202 for (p = specials; *p; ++p)
3203 if ((sym = obj_find_symbol(f, *p)) != NULL)
3204 sym->info =
3205 ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info));
3206}
3207
3208
3209
3210extern int insmod_main( int argc, char **argv)
3211{
3212 int opt;
3213 int k_crcs;
3214 int k_new_syscalls;
3215 int len;
3216 char *tmp;
3217 unsigned long m_size;
3218 ElfW(Addr) m_addr;
3219 FILE *fp;
3220 struct obj_file *f;
3221 struct stat st;
3222 char m_name[FILENAME_MAX + 1] = "\0";
3223 int exit_status = EXIT_FAILURE;
3224 int m_has_modinfo;
3225#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
3226 struct utsname uts_info;
3227 char m_strversion[STRVERSIONLEN];
3228 int m_version;
3229 int m_crcs;
3230#endif
3231
3232 /* Parse any options */
3233 while ((opt = getopt(argc, argv, "fkvxLo:")) > 0) {
3234 switch (opt) {
3235 case 'f': /* force loading */
3236 flag_force_load = 1;
3237 break;
3238 case 'k': /* module loaded by kerneld, auto-cleanable */
3239 flag_autoclean = 1;
3240 break;
3241 case 'v': /* verbose output */
3242 flag_verbose = 1;
3243 break;
3244 case 'x': /* do not export externs */
3245 flag_export = 0;
3246 break;
3247 case 'o': /* name the output module */
3248 strncpy(m_name, optarg, FILENAME_MAX);
3249 break;
3250 case 'L': /* Stub warning */
3251 /* This is needed for compatibility with modprobe.
3252 * In theory, this does locking, but we don't do
3253 * that. So be careful and plan your life around not
3254 * loading the same module 50 times concurrently. */
3255 break;
3256 default:
3257 show_usage();
3258 }
3259 }
3260
3261 if (argv[optind] == NULL) {
3262 show_usage();
3263 }
3264
3265 /* Grab the module name */
3266 if ((tmp = strrchr(argv[optind], '/')) != NULL) {
3267 tmp++;
3268 } else {
3269 tmp = argv[optind];
3270 }
3271 len = strlen(tmp);
3272
3273 if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o')
3274 len -= 2;
3275 memcpy(m_fullName, tmp, len);
3276 m_fullName[len]='\0';
3277 if (*m_name == '\0') {
3278 strcpy(m_name, m_fullName);
3279 }
3280 strcat(m_fullName, ".o");
3281
3282 /* Get a filedesc for the module. Check we we have a complete path */
3283 if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) ||
3284 (fp = fopen(argv[optind], "r")) == NULL) {
3285 struct utsname myuname;
3286
3287 /* Hmm. Could not open it. First search under /lib/modules/`uname -r`,
3288 * but do not error out yet if we fail to find it... */
3289 if (uname(&myuname) == 0) {
3290 char module_dir[FILENAME_MAX];
3291 char real_module_dir[FILENAME_MAX];
3292 snprintf (module_dir, sizeof(module_dir), "%s/%s",
3293 _PATH_MODULES, myuname.release);
3294 /* Jump through hoops in case /lib/modules/`uname -r`
3295 * is a symlink. We do not want recursive_action to
3296 * follow symlinks, but we do want to follow the
3297 * /lib/modules/`uname -r` dir, So resolve it ourselves
3298 * if it is a link... */
3299 if (realpath (module_dir, real_module_dir) == NULL)
3300 strcpy(real_module_dir, module_dir);
3301 recursive_action(real_module_dir, TRUE, FALSE, FALSE,
3302 check_module_name_match, 0, m_fullName);
3303 }
3304
3305 /* Check if we have found anything yet */
3306 if (m_filename[0] == '\0' || ((fp = fopen(m_filename, "r")) == NULL))
3307 {
3308 char module_dir[FILENAME_MAX];
3309 if (realpath (_PATH_MODULES, module_dir) == NULL)
3310 strcpy(module_dir, _PATH_MODULES);
3311 /* No module found under /lib/modules/`uname -r`, this
3312 * time cast the net a bit wider. Search /lib/modules/ */
3313 if (recursive_action(module_dir, TRUE, FALSE, FALSE,
3314 check_module_name_match, 0, m_fullName) == FALSE)
3315 {
3316 if (m_filename[0] == '\0'
3317 || ((fp = fopen(m_filename, "r")) == NULL))
3318 {
3319 error_msg("%s: no module by that name found", m_fullName);
3320 return EXIT_FAILURE;
3321 }
3322 } else
3323 error_msg_and_die("%s: no module by that name found", m_fullName);
3324 }
3325 } else
3326 safe_strncpy(m_filename, argv[optind], sizeof(m_filename));
3327
3328 printf("Using %s\n", m_filename);
3329
3330 if ((f = obj_load(fp, LOADBITS)) == NULL)
3331 perror_msg_and_die("Could not load the module");
3332
3333 if (get_modinfo_value(f, "kernel_version") == NULL)
3334 m_has_modinfo = 0;
3335 else
3336 m_has_modinfo = 1;
3337
3338#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
3339 /* Version correspondence? */
3340
3341 if (uname(&uts_info) < 0)
3342 uts_info.release[0] = '\0';
3343 if (m_has_modinfo) {
3344 m_version = new_get_module_version(f, m_strversion);
3345 } else {
3346 m_version = old_get_module_version(f, m_strversion);
3347 if (m_version == -1) {
3348 error_msg("couldn't find the kernel version the module was "
3349 "compiled for");
3350 goto out;
3351 }
3352 }
3353
3354 if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) {
3355 if (flag_force_load) {
3356 error_msg("Warning: kernel-module version mismatch\n"
3357 "\t%s was compiled for kernel version %s\n"
3358 "\twhile this kernel is version %s",
3359 m_filename, m_strversion, uts_info.release);
3360 } else {
3361 error_msg("kernel-module version mismatch\n"
3362 "\t%s was compiled for kernel version %s\n"
3363 "\twhile this kernel is version %s.",
3364 m_filename, m_strversion, uts_info.release);
3365 goto out;
3366 }
3367 }
3368 k_crcs = 0;
3369#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
3370
3371 k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL);
3372
3373 if (k_new_syscalls) {
3374#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
3375 if (!new_get_kernel_symbols())
3376 goto out;
3377 k_crcs = new_is_kernel_checksummed();
3378#else
3379 error_msg("Not configured to support new kernels");
3380 goto out;
3381#endif
3382 } else {
3383#ifdef BB_FEATURE_OLD_MODULE_INTERFACE
3384 if (!old_get_kernel_symbols(m_name))
3385 goto out;
3386 k_crcs = old_is_kernel_checksummed();
3387#else
3388 error_msg("Not configured to support old kernels");
3389 goto out;
3390#endif
3391 }
3392
3393#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
3394 if (m_has_modinfo)
3395 m_crcs = new_is_module_checksummed(f);
3396 else
3397 m_crcs = old_is_module_checksummed(f);
3398
3399 if (m_crcs != k_crcs)
3400 obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
3401#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
3402
3403 /* Let the module know about the kernel symbols. */
3404 add_kernel_symbols(f);
3405
3406 /* Allocate common symbols, symbol tables, and string tables. */
3407
3408 if (k_new_syscalls
3409 ? !new_create_this_module(f, m_name)
3410 : !old_create_mod_use_count(f))
3411 {
3412 goto out;
3413 }
3414
3415 if (!obj_check_undefineds(f)) {
3416 goto out;
3417 }
3418 obj_allocate_commons(f);
3419
3420 /* done with the module name, on to the optional var=value arguments */
3421 ++optind;
3422
3423 if (optind < argc) {
3424 if (m_has_modinfo
3425 ? !new_process_module_arguments(f, argc - optind, argv + optind)
3426 : !old_process_module_arguments(f, argc - optind, argv + optind))
3427 {
3428 goto out;
3429 }
3430 }
3431
3432 arch_create_got(f);
3433 hide_special_symbols(f);
3434
3435 if (k_new_syscalls)
3436 new_create_module_ksymtab(f);
3437
3438 /* Find current size of the module */
3439 m_size = obj_load_size(f);
3440
3441
3442 m_addr = create_module(m_name, m_size);
3443 if (m_addr==-1) switch (errno) {
3444 case EEXIST:
3445 error_msg("A module named %s already exists", m_name);
3446 goto out;
3447 case ENOMEM:
3448 error_msg("Can't allocate kernel memory for module; needed %lu bytes",
3449 m_size);
3450 goto out;
3451 default:
3452 perror_msg("create_module: %s", m_name);
3453 goto out;
3454 }
3455
3456#if !LOADBITS
3457 /*
3458 * the PROGBITS section was not loaded by the obj_load
3459 * now we can load them directly into the kernel memory
3460 */
3461 if (!obj_load_progbits(fp, f, (char*)m_addr)) {
3462 delete_module(m_name);
3463 goto out;
3464 }
3465#endif
3466
3467 if (!obj_relocate(f, m_addr)) {
3468 delete_module(m_name);
3469 goto out;
3470 }
3471
3472 if (k_new_syscalls
3473 ? !new_init_module(m_name, f, m_size)
3474 : !old_init_module(m_name, f, m_size))
3475 {
3476 delete_module(m_name);
3477 goto out;
3478 }
3479
3480 exit_status = EXIT_SUCCESS;
3481
3482out:
3483 fclose(fp);
3484 return(exit_status);
3485}
diff --git a/install.sh b/install.sh
deleted file mode 100755
index d163a2ef8..000000000
--- a/install.sh
+++ /dev/null
@@ -1,52 +0,0 @@
1#!/bin/sh
2
3export LC_ALL=POSIX
4export LC_CTYPE=POSIX
5
6prefix=$1
7if [ "$prefix" = "" ]; then
8 echo "No installation directory, aborting."
9 exit 1;
10fi
11if [ "$2" = "--hardlinks" ]; then
12 linkopts="-f"
13else
14 linkopts="-fs"
15fi
16h=`sort busybox.links | uniq`
17
18
19rm -f $prefix/bin/busybox || exit 1
20mkdir -p $prefix/bin || exit 1
21install -m 755 busybox $prefix/bin/busybox || exit 1
22
23for i in $h ; do
24 appdir=`dirname $i`
25 mkdir -p $prefix/$appdir || exit 1
26 if [ "$2" = "--hardlinks" ]; then
27 bb_path="$prefix/bin/busybox"
28 else
29 case "$appdir" in
30 /)
31 bb_path="bin/busybox"
32 ;;
33 /bin)
34 bb_path="busybox"
35 ;;
36 /sbin)
37 bb_path="../bin/busybox"
38 ;;
39 /usr/bin|/usr/sbin)
40 bb_path="../../bin/busybox"
41 ;;
42 *)
43 echo "Unknown installation directory: $appdir"
44 exit 1
45 ;;
46 esac
47 fi
48 echo " $prefix$i -> $bb_path"
49 ln $linkopts $bb_path $prefix$i || exit 1
50done
51
52exit 0
diff --git a/kill.c b/kill.c
deleted file mode 100644
index 3884ebdf4..000000000
--- a/kill.c
+++ /dev/null
@@ -1,142 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini kill/killall implementation for busybox
4 *
5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <unistd.h>
28#include <signal.h>
29#include <ctype.h>
30#include <string.h>
31#include <unistd.h>
32#include "busybox.h"
33
34static const int KILL = 0;
35static const int KILLALL = 1;
36
37
38extern int kill_main(int argc, char **argv)
39{
40 int whichApp, sig = SIGTERM;
41 const char *name;
42
43#ifdef BB_KILLALL
44 /* Figure out what we are trying to do here */
45 whichApp = (strcmp(applet_name, "killall") == 0)? KILLALL : KILL;
46#else
47 whichApp = KILL;
48#endif
49
50 argc--;
51 argv++;
52 /* Parse any options */
53 if (argc < 1)
54 show_usage();
55
56 while (argc > 0 && **argv == '-') {
57 while (*++(*argv)) {
58 switch (**argv) {
59 case 'l':
60 if(argc>1) {
61 for(argv++; *argv; argv++) {
62 name = u_signal_names(*argv, &sig, -1);
63 if(name!=NULL)
64 printf("%s\n", name);
65 }
66 } else {
67 int col = 0;
68 for(sig=1; sig < NSIG; sig++) {
69 name = u_signal_names(0, &sig, 1);
70 if(name==NULL) /* unnamed */
71 continue;
72 col += printf("%2d) %-16s", sig, name);
73 if (col > 60) {
74 printf("\n");
75 col = 0;
76 }
77 }
78 printf("\n");
79 }
80 return EXIT_SUCCESS;
81 case '-':
82 show_usage();
83 default:
84 name = u_signal_names(*argv, &sig, 0);
85 if(name==NULL)
86 error_msg_and_die( "bad signal name: %s", *argv);
87 argc--;
88 argv++;
89 goto do_it_now;
90 }
91 argc--;
92 argv++;
93 }
94 }
95
96 do_it_now:
97
98 if (whichApp == KILL) {
99 /* Looks like they want to do a kill. Do that */
100 while (--argc >= 0) {
101 int pid;
102
103 if (!isdigit(**argv))
104 perror_msg_and_die( "Bad PID");
105 pid = strtol(*argv, NULL, 0);
106 if (kill(pid, sig) != 0)
107 perror_msg_and_die( "Could not kill pid '%d'", pid);
108 argv++;
109 }
110 }
111#ifdef BB_KILLALL
112 else {
113 int all_found = TRUE;
114 pid_t myPid=getpid();
115 /* Looks like they want to do a killall. Do that */
116 while (--argc >= 0) {
117 pid_t* pidList;
118
119 pidList = find_pid_by_name( *argv);
120 if (!pidList || *pidList<=0) {
121 all_found = FALSE;
122 error_msg_and_die( "%s: no process killed", *argv);
123 }
124
125 for(; pidList && *pidList!=0; pidList++) {
126 if (*pidList==myPid)
127 continue;
128 if (kill(*pidList, sig) != 0)
129 perror_msg_and_die( "Could not kill pid '%d'", *pidList);
130 }
131 /* Note that we don't bother to free the memory
132 * allocated in find_pid_by_name(). It will be freed
133 * upon exit, so we can save a byte or two */
134 argv++;
135 }
136 if (all_found == FALSE)
137 return EXIT_FAILURE;
138 }
139#endif
140
141 return EXIT_SUCCESS;
142}
diff --git a/klogd.c b/klogd.c
deleted file mode 100644
index d7b54e9c8..000000000
--- a/klogd.c
+++ /dev/null
@@ -1,153 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini klogd implementation for busybox
4 *
5 * Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>.
6 * Changes: Made this a standalone busybox module which uses standalone
7 * syslog() client interface.
8 *
9 * Copyright (C) 1999,2000,2001 by Lineo, inc.
10 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
11 *
12 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
13 *
14 * "circular buffer" Copyright (C) 2000 by Gennady Feldman <gfeldman@mail.com>
15 *
16 * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 *
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <signal.h> /* for our signal() handlers */
37#include <string.h> /* strncpy() */
38#include <errno.h> /* errno and friends */
39#include <unistd.h>
40#include <ctype.h>
41#include <sys/syslog.h>
42
43#if __GNU_LIBRARY__ < 5
44# ifdef __alpha__
45# define klogctl syslog
46# endif
47#else
48# include <sys/klog.h>
49#endif
50
51#include "busybox.h"
52
53static void klogd_signal(int sig)
54{
55 klogctl(7, NULL, 0);
56 klogctl(0, 0, 0);
57 //logMessage(0, "Kernel log daemon exiting.");
58 syslog_msg(LOG_DAEMON, 0, "Kernel log daemon exiting.");
59 exit(TRUE);
60}
61
62static void doKlogd (void) __attribute__ ((noreturn));
63static void doKlogd (void)
64{
65 int priority = LOG_INFO;
66 char log_buffer[4096];
67 int i, n, lastc;
68 char *start;
69
70 /* Set up sig handlers */
71 signal(SIGINT, klogd_signal);
72 signal(SIGKILL, klogd_signal);
73 signal(SIGTERM, klogd_signal);
74 signal(SIGHUP, SIG_IGN);
75
76 /* "Open the log. Currently a NOP." */
77 klogctl(1, NULL, 0);
78
79 syslog_msg(LOG_DAEMON, 0, "klogd started: " BB_BANNER);
80
81 while (1) {
82 /* Use kernel syscalls */
83 memset(log_buffer, '\0', sizeof(log_buffer));
84 n = klogctl(2, log_buffer, sizeof(log_buffer));
85 if (n < 0) {
86 char message[80];
87
88 if (errno == EINTR)
89 continue;
90 snprintf(message, 79, "klogd: Error return from sys_sycall: %d - %s.\n",
91 errno, strerror(errno));
92 syslog_msg(LOG_DAEMON, LOG_SYSLOG | LOG_ERR, message);
93 exit(1);
94 }
95
96 /* klogctl buffer parsing modelled after code in dmesg.c */
97 start=&log_buffer[0];
98 lastc='\0';
99 for (i=0; i<n; i++) {
100 if (lastc == '\0' && log_buffer[i] == '<') {
101 priority = 0;
102 i++;
103 while (isdigit(log_buffer[i])) {
104 priority = priority*10+(log_buffer[i]-'0');
105 i++;
106 }
107 if (log_buffer[i] == '>') i++;
108 start = &log_buffer[i];
109 }
110 if (log_buffer[i] == '\n') {
111 log_buffer[i] = '\0'; /* zero terminate this message */
112 syslog_msg(LOG_DAEMON, LOG_KERN | priority, start);
113 start = &log_buffer[i+1];
114 priority = LOG_INFO;
115 }
116 lastc = log_buffer[i];
117 }
118 }
119}
120
121extern int klogd_main(int argc, char **argv)
122{
123 /* no options, no getopt */
124 int opt;
125 int doFork = TRUE;
126
127 /* do normal option parsing */
128 while ((opt = getopt(argc, argv, "n")) > 0) {
129 switch (opt) {
130 case 'n':
131 doFork = FALSE;
132 break;
133 default:
134 show_usage();
135 }
136 }
137
138 if (doFork == TRUE) {
139 if (daemon(0, 1) < 0)
140 perror_msg_and_die("daemon");
141 }
142 doKlogd();
143
144 return EXIT_SUCCESS;
145}
146
147/*
148Local Variables
149c-file-style: "linux"
150c-basic-offset: 4
151tab-width: 4
152End:
153*/
diff --git a/lash.c b/lash.c
deleted file mode 100644
index ffdec8781..000000000
--- a/lash.c
+++ /dev/null
@@ -1,1640 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * lash -- the BusyBox Lame-Ass SHell
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is
9 * under the following liberal license: "We have placed this source code in the
10 * public domain. Use it in any project, free or commercial."
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 */
27
28/* This shell's parsing engine is officially at a dead-end.
29 * Future work shell work should be done using hush.c
30 */
31
32//For debugging/development on the shell only...
33//#define DEBUG_SHELL
34
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <ctype.h>
39#include <errno.h>
40#include <fcntl.h>
41#include <signal.h>
42#include <string.h>
43#include <sys/ioctl.h>
44#include <sys/wait.h>
45#include <unistd.h>
46#include <getopt.h>
47#include <termios.h>
48#include "busybox.h"
49#include "cmdedit.h"
50
51#ifdef BB_LOCALE_SUPPORT
52#include <locale.h>
53#endif
54
55#include <glob.h>
56#define expand_t glob_t
57
58
59static const int MAX_READ = 128; /* size of input buffer for `read' builtin */
60#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
61
62
63enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
64 REDIRECT_APPEND
65};
66
67static const unsigned int DEFAULT_CONTEXT=0x1;
68static const unsigned int IF_TRUE_CONTEXT=0x2;
69static const unsigned int IF_FALSE_CONTEXT=0x4;
70static const unsigned int THEN_EXP_CONTEXT=0x8;
71static const unsigned int ELSE_EXP_CONTEXT=0x10;
72
73
74struct jobset {
75 struct job *head; /* head of list of running jobs */
76 struct job *fg; /* current foreground job */
77};
78
79struct redir_struct {
80 enum redir_type type; /* type of redirection */
81 int fd; /* file descriptor being redirected */
82 char *filename; /* file to redirect fd to */
83};
84
85struct child_prog {
86 pid_t pid; /* 0 if exited */
87 char **argv; /* program name and arguments */
88 int num_redirects; /* elements in redirection array */
89 struct redir_struct *redirects; /* I/O redirects */
90 int is_stopped; /* is the program currently running? */
91 struct job *family; /* pointer back to the child's parent job */
92};
93
94struct job {
95 int jobid; /* job number */
96 int num_progs; /* total number of programs in job */
97 int running_progs; /* number of programs running */
98 char *text; /* name of job */
99 char *cmdbuf; /* buffer various argv's point into */
100 pid_t pgrp; /* process group ID for the job */
101 struct child_prog *progs; /* array of programs in job */
102 struct job *next; /* to track background commands */
103 int stopped_progs; /* number of programs alive, but stopped */
104 unsigned int job_context; /* bitmask defining current context */
105 struct jobset *job_list;
106};
107
108struct built_in_command {
109 char *cmd; /* name */
110 char *descr; /* description */
111 int (*function) (struct child_prog *); /* function ptr */
112};
113
114struct close_me {
115 int fd;
116 struct close_me *next;
117};
118
119/* function prototypes for builtins */
120static int builtin_cd(struct child_prog *cmd);
121static int builtin_exec(struct child_prog *cmd);
122static int builtin_exit(struct child_prog *cmd);
123static int builtin_fg_bg(struct child_prog *cmd);
124static int builtin_help(struct child_prog *cmd);
125static int builtin_jobs(struct child_prog *dummy);
126static int builtin_pwd(struct child_prog *dummy);
127static int builtin_export(struct child_prog *cmd);
128static int builtin_source(struct child_prog *cmd);
129static int builtin_unset(struct child_prog *cmd);
130static int builtin_read(struct child_prog *cmd);
131
132
133/* function prototypes for shell stuff */
134static void mark_open(int fd);
135static void mark_closed(int fd);
136static void close_all(void);
137static void checkjobs(struct jobset *job_list);
138static void remove_job(struct jobset *j_list, struct job *job);
139static int get_command(FILE * source, char *command);
140static int parse_command(char **command_ptr, struct job *job, int *inbg);
141static int run_command(struct job *newjob, int inbg, int outpipe[2]);
142static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn));
143static int busy_loop(FILE * input);
144
145
146/* Table of built-in functions (these are non-forking builtins, meaning they
147 * can change global variables in the parent shell process but they will not
148 * work with pipes and redirects; 'unset foo | whatever' will not work) */
149static struct built_in_command bltins[] = {
150 {"bg", "Resume a job in the background", builtin_fg_bg},
151 {"cd", "Change working directory", builtin_cd},
152 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
153 {"exit", "Exit from shell()", builtin_exit},
154 {"fg", "Bring job into the foreground", builtin_fg_bg},
155 {"jobs", "Lists the active jobs", builtin_jobs},
156 {"export", "Set environment variable", builtin_export},
157 {"unset", "Unset environment variable", builtin_unset},
158 {"read", "Input environment variable", builtin_read},
159 {".", "Source-in and run commands in a file", builtin_source},
160 /* to do: add ulimit */
161 {NULL, NULL, NULL}
162};
163
164/* Table of forking built-in functions (things that fork cannot change global
165 * variables in the parent process, such as the current working directory) */
166static struct built_in_command bltins_forking[] = {
167 {"pwd", "Print current directory", builtin_pwd},
168 {"help", "List shell built-in commands", builtin_help},
169 {NULL, NULL, NULL}
170};
171
172
173static int shell_context; /* Type prompt trigger (PS1 or PS2) */
174
175
176/* Globals that are static to this file */
177static const char *cwd;
178static char *local_pending_command = NULL;
179static struct jobset job_list = { NULL, NULL };
180static int argc;
181static char **argv;
182static struct close_me *close_me_head;
183static int last_return_code;
184static int last_bg_pid;
185static unsigned int last_jobid;
186static int shell_terminal;
187static pid_t shell_pgrp;
188static char *PS1;
189static char *PS2 = "> ";
190
191
192#ifdef DEBUG_SHELL
193static inline void debug_printf(const char *format, ...)
194{
195 va_list args;
196 va_start(args, format);
197 vfprintf(stderr, format, args);
198 va_end(args);
199}
200#else
201static inline void debug_printf(const char *format, ...) { }
202#endif
203
204/*
205 Most builtins need access to the struct child_prog that has
206 their arguments, previously coded as cmd->progs[0]. That coding
207 can exhibit a bug, if the builtin is not the first command in
208 a pipeline: "echo foo | exec sort" will attempt to exec foo.
209
210builtin previous use notes
211------ ----------------- ---------
212cd cmd->progs[0]
213exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins
214exit cmd->progs[0]
215fg_bg cmd->progs[0], job_list->head, job_list->fg
216help 0
217jobs job_list->head
218pwd 0
219export cmd->progs[0]
220source cmd->progs[0]
221unset cmd->progs[0]
222read cmd->progs[0]
223
224I added "struct job *family;" to struct child_prog,
225and switched API to builtin_foo(struct child_prog *child);
226So cmd->text becomes child->family->text
227 cmd->job_context becomes child->family->job_context
228 cmd->progs[0] becomes *child
229 job_list becomes child->family->job_list
230 */
231
232/* built-in 'cd <path>' handler */
233static int builtin_cd(struct child_prog *child)
234{
235 char *newdir;
236
237 if (child->argv[1] == NULL)
238 newdir = getenv("HOME");
239 else
240 newdir = child->argv[1];
241 if (chdir(newdir)) {
242 printf("cd: %s: %m\n", newdir);
243 return EXIT_FAILURE;
244 }
245 cwd = xgetcwd((char *)cwd);
246 if (!cwd)
247 cwd = unknown;
248 return EXIT_SUCCESS;
249}
250
251/* built-in 'exec' handler */
252static int builtin_exec(struct child_prog *child)
253{
254 if (child->argv[1] == NULL)
255 return EXIT_SUCCESS; /* Really? */
256 child->argv++;
257 close_all();
258 pseudo_exec(child);
259 /* never returns */
260}
261
262/* built-in 'exit' handler */
263static int builtin_exit(struct child_prog *child)
264{
265 if (child->argv[1] == NULL)
266 exit(EXIT_SUCCESS);
267
268 exit (atoi(child->argv[1]));
269}
270
271/* built-in 'fg' and 'bg' handler */
272static int builtin_fg_bg(struct child_prog *child)
273{
274 int i, jobnum;
275 struct job *job=NULL;
276
277 /* If they gave us no args, assume they want the last backgrounded task */
278 if (!child->argv[1]) {
279 for (job = child->family->job_list->head; job; job = job->next) {
280 if (job->jobid == last_jobid) {
281 break;
282 }
283 }
284 if (!job) {
285 error_msg("%s: no current job", child->argv[0]);
286 return EXIT_FAILURE;
287 }
288 } else {
289 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
290 error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
291 return EXIT_FAILURE;
292 }
293 for (job = child->family->job_list->head; job; job = job->next) {
294 if (job->jobid == jobnum) {
295 break;
296 }
297 }
298 if (!job) {
299 error_msg("%s: %d: no such job", child->argv[0], jobnum);
300 return EXIT_FAILURE;
301 }
302 }
303
304 if (*child->argv[0] == 'f') {
305 /* Put the job into the foreground. */
306 tcsetpgrp(shell_terminal, job->pgrp);
307
308 child->family->job_list->fg = job;
309 }
310
311 /* Restart the processes in the job */
312 for (i = 0; i < job->num_progs; i++)
313 job->progs[i].is_stopped = 0;
314
315 job->stopped_progs = 0;
316
317 if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
318 if (i == ESRCH) {
319 remove_job(&job_list, job);
320 } else {
321 perror_msg("kill (SIGCONT)");
322 }
323 }
324
325 return EXIT_SUCCESS;
326}
327
328/* built-in 'help' handler */
329static int builtin_help(struct child_prog *dummy)
330{
331 struct built_in_command *x;
332
333 printf("\nBuilt-in commands:\n");
334 printf("-------------------\n");
335 for (x = bltins; x->cmd; x++) {
336 if (x->descr==NULL)
337 continue;
338 printf("%s\t%s\n", x->cmd, x->descr);
339 }
340 for (x = bltins_forking; x->cmd; x++) {
341 if (x->descr==NULL)
342 continue;
343 printf("%s\t%s\n", x->cmd, x->descr);
344 }
345 printf("\n\n");
346 return EXIT_SUCCESS;
347}
348
349/* built-in 'jobs' handler */
350static int builtin_jobs(struct child_prog *child)
351{
352 struct job *job;
353 char *status_string;
354
355 for (job = child->family->job_list->head; job; job = job->next) {
356 if (job->running_progs == job->stopped_progs)
357 status_string = "Stopped";
358 else
359 status_string = "Running";
360
361 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
362 }
363 return EXIT_SUCCESS;
364}
365
366
367/* built-in 'pwd' handler */
368static int builtin_pwd(struct child_prog *dummy)
369{
370 cwd = xgetcwd((char *)cwd);
371 if (!cwd)
372 cwd = unknown;
373 puts(cwd);
374 return EXIT_SUCCESS;
375}
376
377/* built-in 'export VAR=value' handler */
378static int builtin_export(struct child_prog *child)
379{
380 int res;
381 char *v = child->argv[1];
382
383 if (v == NULL) {
384 char **e;
385 for (e = environ; *e; e++) {
386 puts(*e);
387 }
388 return 0;
389 }
390 res = putenv(v);
391 if (res)
392 fprintf(stderr, "export: %m\n");
393#ifdef BB_FEATURE_SH_FANCY_PROMPT
394 if (strncmp(v, "PS1=", 4)==0)
395 PS1 = getenv("PS1");
396#endif
397
398#ifdef BB_LOCALE_SUPPORT
399 if(strncmp(v, "LC_ALL=", 7)==0)
400 setlocale(LC_ALL, getenv("LC_ALL"));
401 if(strncmp(v, "LC_CTYPE=", 9)==0)
402 setlocale(LC_CTYPE, getenv("LC_CTYPE"));
403#endif
404
405 return (res);
406}
407
408/* built-in 'read VAR' handler */
409static int builtin_read(struct child_prog *child)
410{
411 int res = 0, len, newlen;
412 char *s;
413 char string[MAX_READ];
414
415 if (child->argv[1]) {
416 /* argument (VAR) given: put "VAR=" into buffer */
417 strcpy(string, child->argv[1]);
418 len = strlen(string);
419 string[len++] = '=';
420 string[len] = '\0';
421 fgets(&string[len], sizeof(string) - len, stdin); /* read string */
422 newlen = strlen(string);
423 if(newlen > len)
424 string[--newlen] = '\0'; /* chomp trailing newline */
425 /*
426 ** string should now contain "VAR=<value>"
427 ** copy it (putenv() won't do that, so we must make sure
428 ** the string resides in a static buffer!)
429 */
430 res = -1;
431 if((s = strdup(string)))
432 res = putenv(s);
433 if (res)
434 fprintf(stderr, "read: %m\n");
435 }
436 else
437 fgets(string, sizeof(string), stdin);
438
439 return (res);
440}
441
442/* Built-in '.' handler (read-in and execute commands from file) */
443static int builtin_source(struct child_prog *child)
444{
445 FILE *input;
446 int status;
447 int fd;
448
449 if (child->argv[1] == NULL)
450 return EXIT_FAILURE;
451
452 input = fopen(child->argv[1], "r");
453 if (!input) {
454 printf( "Couldn't open file '%s'\n", child->argv[1]);
455 return EXIT_FAILURE;
456 }
457
458 fd=fileno(input);
459 mark_open(fd);
460 /* Now run the file */
461 status = busy_loop(input);
462 fclose(input);
463 mark_closed(fd);
464 return (status);
465}
466
467/* built-in 'unset VAR' handler */
468static int builtin_unset(struct child_prog *child)
469{
470 if (child->argv[1] == NULL) {
471 printf( "unset: parameter required.\n");
472 return EXIT_FAILURE;
473 }
474 unsetenv(child->argv[1]);
475 return EXIT_SUCCESS;
476}
477
478static void mark_open(int fd)
479{
480 struct close_me *new = xmalloc(sizeof(struct close_me));
481 new->fd = fd;
482 new->next = close_me_head;
483 close_me_head = new;
484}
485
486static void mark_closed(int fd)
487{
488 struct close_me *tmp;
489 if (close_me_head == NULL || close_me_head->fd != fd)
490 error_msg_and_die("corrupt close_me");
491 tmp = close_me_head;
492 close_me_head = close_me_head->next;
493 free(tmp);
494}
495
496static void close_all()
497{
498 struct close_me *c, *tmp;
499 for (c=close_me_head; c; c=tmp) {
500 close(c->fd);
501 tmp=c->next;
502 free(c);
503 }
504 close_me_head = NULL;
505}
506
507
508/* free up all memory from a job */
509static void free_job(struct job *cmd)
510{
511 int i;
512 struct jobset *keep;
513
514 for (i = 0; i < cmd->num_progs; i++) {
515 free(cmd->progs[i].argv);
516 if (cmd->progs[i].redirects)
517 free(cmd->progs[i].redirects);
518 }
519 if (cmd->progs)
520 free(cmd->progs);
521 if (cmd->text)
522 free(cmd->text);
523 if (cmd->cmdbuf)
524 free(cmd->cmdbuf);
525 keep = cmd->job_list;
526 memset(cmd, 0, sizeof(struct job));
527 cmd->job_list = keep;
528}
529
530/* remove a job from a jobset */
531static void remove_job(struct jobset *j_list, struct job *job)
532{
533 struct job *prevjob;
534
535 free_job(job);
536 if (job == j_list->head) {
537 j_list->head = job->next;
538 } else {
539 prevjob = j_list->head;
540 while (prevjob->next != job)
541 prevjob = prevjob->next;
542 prevjob->next = job->next;
543 }
544
545 if (j_list->head)
546 last_jobid = j_list->head->jobid;
547 else
548 last_jobid = 0;
549
550 free(job);
551}
552
553/* Checks to see if any background processes have exited -- if they
554 have, figure out why and see if a job has completed */
555static void checkjobs(struct jobset *j_list)
556{
557 struct job *job;
558 pid_t childpid;
559 int status;
560 int prognum = 0;
561
562 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
563 for (job = j_list->head; job; job = job->next) {
564 prognum = 0;
565 while (prognum < job->num_progs &&
566 job->progs[prognum].pid != childpid) prognum++;
567 if (prognum < job->num_progs)
568 break;
569 }
570
571 /* This happens on backticked commands */
572 if(job==NULL)
573 return;
574
575 if (WIFEXITED(status) || WIFSIGNALED(status)) {
576 /* child exited */
577 job->running_progs--;
578 job->progs[prognum].pid = 0;
579
580 if (!job->running_progs) {
581 printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
582 last_jobid=0;
583 remove_job(j_list, job);
584 }
585 } else {
586 /* child stopped */
587 job->stopped_progs++;
588 job->progs[prognum].is_stopped = 1;
589
590#if 0
591 /* Printing this stuff is a pain, since it tends to
592 * overwrite the prompt an inconveinient moments. So
593 * don't do that. */
594 if (job->stopped_progs == job->num_progs) {
595 printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
596 job->text);
597 }
598#endif
599 }
600 }
601
602 if (childpid == -1 && errno != ECHILD)
603 perror_msg("waitpid");
604}
605
606/* squirrel != NULL means we squirrel away copies of stdin, stdout,
607 * and stderr if they are redirected. */
608static int setup_redirects(struct child_prog *prog, int squirrel[])
609{
610 int i;
611 int openfd;
612 int mode = O_RDONLY;
613 struct redir_struct *redir = prog->redirects;
614
615 for (i = 0; i < prog->num_redirects; i++, redir++) {
616 switch (redir->type) {
617 case REDIRECT_INPUT:
618 mode = O_RDONLY;
619 break;
620 case REDIRECT_OVERWRITE:
621 mode = O_WRONLY | O_CREAT | O_TRUNC;
622 break;
623 case REDIRECT_APPEND:
624 mode = O_WRONLY | O_CREAT | O_APPEND;
625 break;
626 }
627
628 openfd = open(redir->filename, mode, 0666);
629 if (openfd < 0) {
630 /* this could get lost if stderr has been redirected, but
631 bash and ash both lose it as well (though zsh doesn't!) */
632 perror_msg("error opening %s", redir->filename);
633 return 1;
634 }
635
636 if (openfd != redir->fd) {
637 if (squirrel && redir->fd < 3) {
638 squirrel[redir->fd] = dup(redir->fd);
639 }
640 dup2(openfd, redir->fd);
641 close(openfd);
642 }
643 }
644
645 return 0;
646}
647
648static void restore_redirects(int squirrel[])
649{
650 int i, fd;
651 for (i=0; i<3; i++) {
652 fd = squirrel[i];
653 if (fd != -1) {
654 /* No error checking. I sure wouldn't know what
655 * to do with an error if I found one! */
656 dup2(fd, i);
657 close(fd);
658 }
659 }
660}
661
662static inline void cmdedit_set_initial_prompt(void)
663{
664#ifndef BB_FEATURE_SH_FANCY_PROMPT
665 PS1 = NULL;
666#else
667 PS1 = getenv("PS1");
668 if(PS1==0)
669 PS1 = "\\w \\$ ";
670#endif
671}
672
673static inline void setup_prompt_string(char **prompt_str)
674{
675#ifndef BB_FEATURE_SH_FANCY_PROMPT
676 /* Set up the prompt */
677 if (shell_context == 0) {
678 if (PS1)
679 free(PS1);
680 PS1=xmalloc(strlen(cwd)+4);
681 sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# ");
682 *prompt_str = PS1;
683 } else {
684 *prompt_str = PS2;
685 }
686#else
687 *prompt_str = (shell_context==0)? PS1 : PS2;
688#endif
689}
690
691static int get_command(FILE * source, char *command)
692{
693 char *prompt_str;
694
695 if (source == NULL) {
696 if (local_pending_command) {
697 /* a command specified (-c option): return it & mark it done */
698 strcpy(command, local_pending_command);
699 free(local_pending_command);
700 local_pending_command = NULL;
701 return 0;
702 }
703 return 1;
704 }
705
706 if (source == stdin) {
707 setup_prompt_string(&prompt_str);
708
709#ifdef BB_FEATURE_COMMAND_EDITING
710 /*
711 ** enable command line editing only while a command line
712 ** is actually being read; otherwise, we'll end up bequeathing
713 ** atexit() handlers and other unwanted stuff to our
714 ** child processes (rob@sysgo.de)
715 */
716 cmdedit_read_input(prompt_str, command);
717 return 0;
718#else
719 fputs(prompt_str, stdout);
720#endif
721 }
722
723 if (!fgets(command, BUFSIZ - 2, source)) {
724 if (source == stdin)
725 printf("\n");
726 return 1;
727 }
728
729 return 0;
730}
731
732static char* itoa(register int i)
733{
734 static char a[7]; /* Max 7 ints */
735 register char *b = a + sizeof(a) - 1;
736 int sign = (i < 0);
737
738 if (sign)
739 i = -i;
740 *b = 0;
741 do
742 {
743 *--b = '0' + (i % 10);
744 i /= 10;
745 }
746 while (i);
747 if (sign)
748 *--b = '-';
749 return b;
750}
751
752char * strsep_space( char *string, int * ix)
753{
754 char *token, *begin;
755
756 begin = string;
757
758 /* Short circuit the trivial case */
759 if ( !string || ! string[*ix])
760 return NULL;
761
762 /* Find the end of the token. */
763 while( string && string[*ix] && !isspace(string[*ix]) ) {
764 (*ix)++;
765 }
766
767 /* Find the end of any whitespace trailing behind
768 * the token and let that be part of the token */
769 while( string && string[*ix] && isspace(string[*ix]) ) {
770 (*ix)++;
771 }
772
773 if (! string && *ix==0) {
774 /* Nothing useful was found */
775 return NULL;
776 }
777
778 token = xmalloc(*ix+1);
779 token[*ix] = '\0';
780 strncpy(token, string, *ix);
781
782 return token;
783}
784
785static int expand_arguments(char *command)
786{
787 int total_length=0, length, i, retval, ix = 0;
788 expand_t expand_result;
789 char *tmpcmd, *cmd, *cmd_copy;
790 char *src, *dst, *var;
791 const char *out_of_space = "out of space during expansion";
792 int flags = GLOB_NOCHECK
793#ifdef GLOB_BRACE
794 | GLOB_BRACE
795#endif
796#ifdef GLOB_TILDE
797 | GLOB_TILDE
798#endif
799 ;
800
801 /* get rid of the terminating \n */
802 chomp(command);
803
804 /* Fix up escape sequences to be the Real Thing(tm) */
805 while( command && command[ix]) {
806 if (command[ix] == '\\') {
807 const char *tmp = command+ix+1;
808 command[ix] = process_escape_sequence( &tmp );
809 memmove(command+ix + 1, tmp, strlen(tmp)+1);
810 }
811 ix++;
812 }
813 /* Use glob and then fixup environment variables and such */
814
815 /* It turns out that glob is very stupid. We have to feed it one word at a
816 * time since it can't cope with a full string. Here we convert command
817 * (char*) into cmd (char**, one word per string) */
818
819 /* We need a clean copy, so strsep can mess up the copy while
820 * we write stuff into the original (in a minute) */
821 cmd = cmd_copy = strdup(command);
822 *command = '\0';
823 for (ix = 0, tmpcmd = cmd;
824 (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
825 if (*tmpcmd == '\0')
826 break;
827 /* we need to trim() the result for glob! */
828 trim(tmpcmd);
829 retval = glob(tmpcmd, flags, NULL, &expand_result);
830 free(tmpcmd); /* Free mem allocated by strsep_space */
831 if (retval == GLOB_NOSPACE) {
832 /* Mem may have been allocated... */
833 globfree (&expand_result);
834 error_msg(out_of_space);
835 return FALSE;
836 } else if (retval != 0) {
837 /* Some other error. GLOB_NOMATCH shouldn't
838 * happen because of the GLOB_NOCHECK flag in
839 * the glob call. */
840 error_msg("syntax error");
841 return FALSE;
842 } else {
843 /* Convert from char** (one word per string) to a simple char*,
844 * but don't overflow command which is BUFSIZ in length */
845 for (i=0; i < expand_result.gl_pathc; i++) {
846 length=strlen(expand_result.gl_pathv[i]);
847 if (total_length+length+1 >= BUFSIZ) {
848 error_msg(out_of_space);
849 return FALSE;
850 }
851 strcat(command+total_length, " ");
852 total_length+=1;
853 strcat(command+total_length, expand_result.gl_pathv[i]);
854 total_length+=length;
855 }
856 globfree (&expand_result);
857 }
858 }
859 free(cmd_copy);
860 trim(command);
861
862 /* Now do the shell variable substitutions which
863 * wordexp can't do for us, namely $? and $! */
864 src = command;
865 while((dst = strchr(src,'$')) != NULL){
866 var = NULL;
867 switch(*(dst+1)) {
868 case '?':
869 var = itoa(last_return_code);
870 break;
871 case '!':
872 if (last_bg_pid==-1)
873 *(var)='\0';
874 else
875 var = itoa(last_bg_pid);
876 break;
877 /* Everything else like $$, $#, $[0-9], etc. should all be
878 * expanded by wordexp(), so we can in theory skip that stuff
879 * here, but just to be on the safe side (i.e., since uClibc
880 * wordexp doesn't do this stuff yet), lets leave it in for
881 * now. */
882 case '$':
883 var = itoa(getpid());
884 break;
885 case '#':
886 var = itoa(argc-1);
887 break;
888 case '0':case '1':case '2':case '3':case '4':
889 case '5':case '6':case '7':case '8':case '9':
890 {
891 int ixx=*(dst + 1)-48;
892 if (ixx >= argc) {
893 var='\0';
894 } else {
895 var = argv[ixx];
896 }
897 }
898 break;
899
900 }
901 if (var) {
902 /* a single character construction was found, and
903 * already handled in the case statement */
904 src=dst+2;
905 } else {
906 /* Looks like an environment variable */
907 char delim_hold;
908 int num_skip_chars=0;
909 int dstlen = strlen(dst);
910 /* Is this a ${foo} type variable? */
911 if (dstlen >=2 && *(dst+1) == '{') {
912 src=strchr(dst+1, '}');
913 num_skip_chars=1;
914 } else {
915 src=dst+1;
916 while(isalnum(*src) || *src=='_') src++;
917 }
918 if (src == NULL) {
919 src = dst+dstlen;
920 }
921 delim_hold=*src;
922 *src='\0'; /* temporary */
923 var = getenv(dst + 1 + num_skip_chars);
924 *src=delim_hold;
925 src += num_skip_chars;
926 }
927 if (var == NULL) {
928 /* Seems we got an un-expandable variable. So delete it. */
929 var = "";
930 }
931 {
932 int subst_len = strlen(var);
933 int trail_len = strlen(src);
934 if (dst+subst_len+trail_len >= command+BUFSIZ) {
935 error_msg(out_of_space);
936 return FALSE;
937 }
938 /* Move stuff to the end of the string to accommodate
939 * filling the created gap with the new stuff */
940 memmove(dst+subst_len, src, trail_len+1);
941 /* Now copy in the new stuff */
942 memcpy(dst, var, subst_len);
943 src = dst+subst_len;
944 }
945 }
946
947 return TRUE;
948}
949
950/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
951 line). If a valid command is found, command_ptr is set to point to
952 the beginning of the next command (if the original command had more
953 then one job associated with it) or NULL if no more commands are
954 present. */
955static int parse_command(char **command_ptr, struct job *job, int *inbg)
956{
957 char *command;
958 char *return_command = NULL;
959 char *src, *buf, *chptr;
960 int argc_l = 0;
961 int done = 0;
962 int argv_alloced;
963 int i, saw_quote = 0;
964 char quote = '\0';
965 int count;
966 struct child_prog *prog;
967
968 /* skip leading white space */
969 while (**command_ptr && isspace(**command_ptr))
970 (*command_ptr)++;
971
972 /* this handles empty lines or leading '#' characters */
973 if (!**command_ptr || (**command_ptr == '#')) {
974 job->num_progs=0;
975 return 0;
976 }
977
978 *inbg = 0;
979 job->num_progs = 1;
980 job->progs = xmalloc(sizeof(*job->progs));
981
982 /* We set the argv elements to point inside of this string. The
983 memory is freed by free_job(). Allocate twice the original
984 length in case we need to quote every single character.
985
986 Getting clean memory relieves us of the task of NULL
987 terminating things and makes the rest of this look a bit
988 cleaner (though it is, admittedly, a tad less efficient) */
989 job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char));
990 job->text = NULL;
991
992 prog = job->progs;
993 prog->num_redirects = 0;
994 prog->redirects = NULL;
995 prog->is_stopped = 0;
996 prog->family = job;
997
998 argv_alloced = 5;
999 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
1000 prog->argv[0] = job->cmdbuf;
1001
1002 buf = command;
1003 src = *command_ptr;
1004 while (*src && !done) {
1005 if (quote == *src) {
1006 quote = '\0';
1007 } else if (quote) {
1008 if (*src == '\\') {
1009 src++;
1010 if (!*src) {
1011 error_msg("character expected after \\");
1012 free_job(job);
1013 return 1;
1014 }
1015
1016 /* in shell, "\'" should yield \' */
1017 if (*src != quote) {
1018 *buf++ = '\\';
1019 *buf++ = '\\';
1020 }
1021 } else if (*src == '*' || *src == '?' || *src == '[' ||
1022 *src == ']') *buf++ = '\\';
1023 *buf++ = *src;
1024 } else if (isspace(*src)) {
1025 if (*prog->argv[argc_l] || saw_quote) {
1026 buf++, argc_l++;
1027 /* +1 here leaves room for the NULL which ends argv */
1028 if ((argc_l + 1) == argv_alloced) {
1029 argv_alloced += 5;
1030 prog->argv = xrealloc(prog->argv,
1031 sizeof(*prog->argv) *
1032 argv_alloced);
1033 }
1034 prog->argv[argc_l] = buf;
1035 saw_quote = 0;
1036 }
1037 } else
1038 switch (*src) {
1039 case '"':
1040 case '\'':
1041 quote = *src;
1042 saw_quote = 1;
1043 break;
1044
1045 case '#': /* comment */
1046 if (*(src-1)== '$')
1047 *buf++ = *src;
1048 else
1049 done = 1;
1050 break;
1051
1052 case '>': /* redirects */
1053 case '<':
1054 i = prog->num_redirects++;
1055 prog->redirects = xrealloc(prog->redirects,
1056 sizeof(*prog->redirects) *
1057 (i + 1));
1058
1059 prog->redirects[i].fd = -1;
1060 if (buf != prog->argv[argc_l]) {
1061 /* the stuff before this character may be the file number
1062 being redirected */
1063 prog->redirects[i].fd =
1064 strtol(prog->argv[argc_l], &chptr, 10);
1065
1066 if (*chptr && *prog->argv[argc_l]) {
1067 buf++, argc_l++;
1068 prog->argv[argc_l] = buf;
1069 }
1070 }
1071
1072 if (prog->redirects[i].fd == -1) {
1073 if (*src == '>')
1074 prog->redirects[i].fd = 1;
1075 else
1076 prog->redirects[i].fd = 0;
1077 }
1078
1079 if (*src++ == '>') {
1080 if (*src == '>')
1081 prog->redirects[i].type =
1082 REDIRECT_APPEND, src++;
1083 else
1084 prog->redirects[i].type = REDIRECT_OVERWRITE;
1085 } else {
1086 prog->redirects[i].type = REDIRECT_INPUT;
1087 }
1088
1089 /* This isn't POSIX sh compliant. Oh well. */
1090 chptr = src;
1091 while (isspace(*chptr))
1092 chptr++;
1093
1094 if (!*chptr) {
1095 error_msg("file name expected after %c", *(src-1));
1096 free_job(job);
1097 job->num_progs=0;
1098 return 1;
1099 }
1100
1101 prog->redirects[i].filename = buf;
1102 while (*chptr && !isspace(*chptr))
1103 *buf++ = *chptr++;
1104
1105 src = chptr - 1; /* we src++ later */
1106 prog->argv[argc_l] = ++buf;
1107 break;
1108
1109 case '|': /* pipe */
1110 /* finish this command */
1111 if (*prog->argv[argc_l] || saw_quote)
1112 argc_l++;
1113 if (!argc_l) {
1114 error_msg("empty command in pipe");
1115 free_job(job);
1116 job->num_progs=0;
1117 return 1;
1118 }
1119 prog->argv[argc_l] = NULL;
1120
1121 /* and start the next */
1122 job->num_progs++;
1123 job->progs = xrealloc(job->progs,
1124 sizeof(*job->progs) * job->num_progs);
1125 prog = job->progs + (job->num_progs - 1);
1126 prog->num_redirects = 0;
1127 prog->redirects = NULL;
1128 prog->is_stopped = 0;
1129 prog->family = job;
1130 argc_l = 0;
1131
1132 argv_alloced = 5;
1133 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
1134 prog->argv[0] = ++buf;
1135
1136 src++;
1137 while (*src && isspace(*src))
1138 src++;
1139
1140 if (!*src) {
1141 error_msg("empty command in pipe");
1142 free_job(job);
1143 job->num_progs=0;
1144 return 1;
1145 }
1146 src--; /* we'll ++ it at the end of the loop */
1147
1148 break;
1149
1150 case '&': /* background */
1151 *inbg = 1;
1152 case ';': /* multiple commands */
1153 done = 1;
1154 return_command = *command_ptr + (src - *command_ptr) + 1;
1155 break;
1156
1157 case '\\':
1158 src++;
1159 if (!*src) {
1160 error_msg("character expected after \\");
1161 free_job(job);
1162 return 1;
1163 }
1164 if (*src == '*' || *src == '[' || *src == ']'
1165 || *src == '?') *buf++ = '\\';
1166 /* fallthrough */
1167 default:
1168 *buf++ = *src;
1169 }
1170
1171 src++;
1172 }
1173
1174 if (*prog->argv[argc_l] || saw_quote) {
1175 argc_l++;
1176 }
1177 if (!argc_l) {
1178 free_job(job);
1179 return 0;
1180 }
1181 prog->argv[argc_l] = NULL;
1182
1183 if (!return_command) {
1184 job->text = xmalloc(strlen(*command_ptr) + 1);
1185 strcpy(job->text, *command_ptr);
1186 } else {
1187 /* This leaves any trailing spaces, which is a bit sloppy */
1188 count = return_command - *command_ptr;
1189 job->text = xmalloc(count + 1);
1190 strncpy(job->text, *command_ptr, count);
1191 job->text[count] = '\0';
1192 }
1193
1194 *command_ptr = return_command;
1195
1196 return 0;
1197}
1198
1199/* Run the child_prog, no matter what kind of command it uses.
1200 */
1201static int pseudo_exec(struct child_prog *child)
1202{
1203 struct built_in_command *x;
1204#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1205 char *name;
1206#endif
1207
1208 /* Check if the command matches any of the non-forking builtins.
1209 * Depending on context, this might be redundant. But it's
1210 * easier to waste a few CPU cycles than it is to figure out
1211 * if this is one of those cases.
1212 */
1213 for (x = bltins; x->cmd; x++) {
1214 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1215 exit(x->function(child));
1216 }
1217 }
1218
1219 /* Check if the command matches any of the forking builtins. */
1220 for (x = bltins_forking; x->cmd; x++) {
1221 if (strcmp(child->argv[0], x->cmd) == 0) {
1222 applet_name=x->cmd;
1223 exit (x->function(child));
1224 }
1225 }
1226#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1227 /* Check if the command matches any busybox internal
1228 * commands ("applets") here. Following discussions from
1229 * November 2000 on busybox@opensource.lineo.com, don't use
1230 * get_last_path_component(). This way explicit (with
1231 * slashes) filenames will never be interpreted as an
1232 * applet, just like with builtins. This way the user can
1233 * override an applet with an explicit filename reference.
1234 * The only downside to this change is that an explicit
1235 * /bin/foo invocation will fork and exec /bin/foo, even if
1236 * /bin/foo is a symlink to busybox.
1237 */
1238 name = child->argv[0];
1239
1240#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
1241 /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
1242 * if you run /bin/cat, it will use BusyBox cat even if
1243 * /bin/cat exists on the filesystem and is _not_ busybox.
1244 * Some systems want this, others do not. Choose wisely. :-)
1245 */
1246 name = get_last_path_component(name);
1247#endif
1248
1249 {
1250 char** argv_l=child->argv;
1251 int argc_l;
1252 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
1253 optind = 1;
1254 run_applet_by_name(name, argc_l, child->argv);
1255 }
1256#endif
1257
1258 execvp(child->argv[0], child->argv);
1259 perror_msg_and_die("%s", child->argv[0]);
1260}
1261
1262static void insert_job(struct job *newjob, int inbg)
1263{
1264 struct job *thejob;
1265 struct jobset *j_list=newjob->job_list;
1266
1267 /* find the ID for thejob to use */
1268 newjob->jobid = 1;
1269 for (thejob = j_list->head; thejob; thejob = thejob->next)
1270 if (thejob->jobid >= newjob->jobid)
1271 newjob->jobid = thejob->jobid + 1;
1272
1273 /* add thejob to the list of running jobs */
1274 if (!j_list->head) {
1275 thejob = j_list->head = xmalloc(sizeof(*thejob));
1276 } else {
1277 for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */;
1278 thejob->next = xmalloc(sizeof(*thejob));
1279 thejob = thejob->next;
1280 }
1281
1282 *thejob = *newjob; /* physically copy the struct job */
1283 thejob->next = NULL;
1284 thejob->running_progs = thejob->num_progs;
1285 thejob->stopped_progs = 0;
1286
1287 if (inbg) {
1288 /* we don't wait for background thejobs to return -- append it
1289 to the list of backgrounded thejobs and leave it alone */
1290 printf("[%d] %d\n", thejob->jobid,
1291 newjob->progs[newjob->num_progs - 1].pid);
1292 last_jobid = newjob->jobid;
1293 last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
1294 } else {
1295 newjob->job_list->fg = thejob;
1296
1297 /* move the new process group into the foreground */
1298 /* suppress messages when run from /linuxrc mag@sysgo.de */
1299 if (tcsetpgrp(shell_terminal, newjob->pgrp) && errno != ENOTTY)
1300 perror_msg("tcsetpgrp");
1301 }
1302}
1303
1304static int run_command(struct job *newjob, int inbg, int outpipe[2])
1305{
1306 /* struct job *thejob; */
1307 int i;
1308 int nextin, nextout;
1309 int pipefds[2]; /* pipefd[0] is for reading */
1310 struct built_in_command *x;
1311 struct child_prog *child;
1312
1313 nextin = 0, nextout = 1;
1314 for (i = 0; i < newjob->num_progs; i++) {
1315 child = & (newjob->progs[i]);
1316
1317 if ((i + 1) < newjob->num_progs) {
1318 if (pipe(pipefds)<0) perror_msg_and_die("pipe");
1319 nextout = pipefds[1];
1320 } else {
1321 if (outpipe[1]!=-1) {
1322 nextout = outpipe[1];
1323 } else {
1324 nextout = 1;
1325 }
1326 }
1327
1328
1329 /* Check if the command matches any non-forking builtins,
1330 * but only if this is a simple command.
1331 * Non-forking builtins within pipes have to fork anyway,
1332 * and are handled in pseudo_exec. "echo foo | read bar"
1333 * is doomed to failure, and doesn't work on bash, either.
1334 */
1335 if (newjob->num_progs == 1) {
1336 for (x = bltins; x->cmd; x++) {
1337 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1338 int squirrel[] = {-1, -1, -1};
1339 int rcode;
1340 setup_redirects(child, squirrel);
1341 rcode = x->function(child);
1342 restore_redirects(squirrel);
1343 return rcode;
1344 }
1345 }
1346 }
1347
1348 if (!(child->pid = fork())) {
1349 /* Set the handling for job control signals back to the default. */
1350 signal(SIGINT, SIG_DFL);
1351 signal(SIGQUIT, SIG_DFL);
1352 signal(SIGTSTP, SIG_DFL);
1353 signal(SIGTTIN, SIG_DFL);
1354 signal(SIGTTOU, SIG_DFL);
1355 signal(SIGCHLD, SIG_DFL);
1356
1357 close_all();
1358
1359 if (outpipe[1]!=-1) {
1360 close(outpipe[0]);
1361 }
1362 if (nextin != 0) {
1363 dup2(nextin, 0);
1364 close(nextin);
1365 }
1366
1367 if (nextout != 1) {
1368 dup2(nextout, 1);
1369 dup2(nextout, 2); /* Really? */
1370 close(nextout);
1371 close(pipefds[0]);
1372 }
1373
1374 /* explicit redirects override pipes */
1375 setup_redirects(child,NULL);
1376
1377 pseudo_exec(child);
1378 }
1379 if (outpipe[1]!=-1) {
1380 close(outpipe[1]);
1381 }
1382
1383 /* put our child in the process group whose leader is the
1384 first process in this pipe */
1385 setpgid(child->pid, newjob->progs[0].pid);
1386 if (nextin != 0)
1387 close(nextin);
1388 if (nextout != 1)
1389 close(nextout);
1390
1391 /* If there isn't another process, nextin is garbage
1392 but it doesn't matter */
1393 nextin = pipefds[0];
1394 }
1395
1396 newjob->pgrp = newjob->progs[0].pid;
1397
1398 insert_job(newjob, inbg);
1399
1400 return 0;
1401}
1402
1403static int busy_loop(FILE * input)
1404{
1405 char *command;
1406 char *next_command = NULL;
1407 struct job newjob;
1408 pid_t parent_pgrp;
1409 int i;
1410 int inbg;
1411 int status;
1412 newjob.job_list = &job_list;
1413 newjob.job_context = DEFAULT_CONTEXT;
1414
1415 /* save current owner of TTY so we can restore it on exit */
1416 parent_pgrp = tcgetpgrp(shell_terminal);
1417
1418 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1419
1420 while (1) {
1421 if (!job_list.fg) {
1422 /* no job is in the foreground */
1423
1424 /* see if any background processes have exited */
1425 checkjobs(&job_list);
1426
1427 if (!next_command) {
1428 if (get_command(input, command))
1429 break;
1430 next_command = command;
1431 }
1432
1433 if (expand_arguments(next_command) == FALSE) {
1434 free(command);
1435 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1436 next_command = NULL;
1437 continue;
1438 }
1439
1440 if (!parse_command(&next_command, &newjob, &inbg) &&
1441 newjob.num_progs) {
1442 int pipefds[2] = {-1,-1};
1443 debug_printf( "job=%p fed to run_command by busy_loop()'\n",
1444 &newjob);
1445 run_command(&newjob, inbg, pipefds);
1446 }
1447 else {
1448 free(command);
1449 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1450 next_command = NULL;
1451 }
1452 } else {
1453 /* a job is running in the foreground; wait for it */
1454 i = 0;
1455 while (!job_list.fg->progs[i].pid ||
1456 job_list.fg->progs[i].is_stopped == 1) i++;
1457
1458 if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0)
1459 perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
1460
1461 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1462 /* the child exited */
1463 job_list.fg->running_progs--;
1464 job_list.fg->progs[i].pid = 0;
1465
1466 last_return_code=WEXITSTATUS(status);
1467
1468 if (!job_list.fg->running_progs) {
1469 /* child exited */
1470 remove_job(&job_list, job_list.fg);
1471 job_list.fg = NULL;
1472 }
1473 } else {
1474 /* the child was stopped */
1475 job_list.fg->stopped_progs++;
1476 job_list.fg->progs[i].is_stopped = 1;
1477
1478 if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
1479 printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
1480 "Stopped", job_list.fg->text);
1481 job_list.fg = NULL;
1482 }
1483 }
1484
1485 if (!job_list.fg) {
1486 /* move the shell to the foreground */
1487 /* suppress messages when run from /linuxrc mag@sysgo.de */
1488 if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY)
1489 perror_msg("tcsetpgrp");
1490 }
1491 }
1492 }
1493 free(command);
1494
1495 /* return controlling TTY back to parent process group before exiting */
1496 if (tcsetpgrp(shell_terminal, parent_pgrp))
1497 perror_msg("tcsetpgrp");
1498
1499 /* return exit status if called with "-c" */
1500 if (input == NULL && WIFEXITED(status))
1501 return WEXITSTATUS(status);
1502
1503 return 0;
1504}
1505
1506
1507#ifdef BB_FEATURE_CLEAN_UP
1508void free_memory(void)
1509{
1510 if (cwd && cwd!=unknown) {
1511 free((char*)cwd);
1512 }
1513 if (local_pending_command)
1514 free(local_pending_command);
1515
1516 if (job_list.fg && !job_list.fg->running_progs) {
1517 remove_job(&job_list, job_list.fg);
1518 }
1519}
1520#endif
1521
1522/* Make sure we have a controlling tty. If we get started under a job
1523 * aware app (like bash for example), make sure we are now in charge so
1524 * we don't fight over who gets the foreground */
1525static void setup_job_control()
1526{
1527 int status;
1528
1529 /* Loop until we are in the foreground. */
1530 while ((status = tcgetpgrp (shell_terminal)) >= 0) {
1531 if (status == (shell_pgrp = getpgrp ())) {
1532 break;
1533 }
1534 kill (- shell_pgrp, SIGTTIN);
1535 }
1536
1537 /* Ignore interactive and job-control signals. */
1538 signal(SIGINT, SIG_IGN);
1539 signal(SIGQUIT, SIG_IGN);
1540 signal(SIGTSTP, SIG_IGN);
1541 signal(SIGTTIN, SIG_IGN);
1542 signal(SIGTTOU, SIG_IGN);
1543 signal(SIGCHLD, SIG_IGN);
1544
1545 /* Put ourselves in our own process group. */
1546 setsid();
1547 shell_pgrp = getpid ();
1548 setpgid (shell_pgrp, shell_pgrp);
1549
1550 /* Grab control of the terminal. */
1551 tcsetpgrp(shell_terminal, shell_pgrp);
1552}
1553
1554int lash_main(int argc_l, char **argv_l)
1555{
1556 int opt, interactive=FALSE;
1557 FILE *input = stdin;
1558 argc = argc_l;
1559 argv = argv_l;
1560
1561 /* These variables need re-initializing when recursing */
1562 last_jobid = 0;
1563 local_pending_command = NULL;
1564 close_me_head = NULL;
1565 job_list.head = NULL;
1566 job_list.fg = NULL;
1567 last_return_code=1;
1568
1569 if (argv[0] && argv[0][0] == '-') {
1570 FILE *prof_input;
1571 prof_input = fopen("/etc/profile", "r");
1572 if (prof_input) {
1573 int tmp_fd = fileno(prof_input);
1574 mark_open(tmp_fd);
1575 /* Now run the file */
1576 busy_loop(prof_input);
1577 fclose(prof_input);
1578 mark_closed(tmp_fd);
1579 }
1580 }
1581
1582 while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) {
1583 switch (opt) {
1584 case 'c':
1585 input = NULL;
1586 if (local_pending_command != 0)
1587 error_msg_and_die("multiple -c arguments");
1588 local_pending_command = xstrdup(argv[optind]);
1589 optind++;
1590 argv = argv+optind;
1591 break;
1592 case 'i':
1593 interactive = TRUE;
1594 break;
1595 default:
1596 show_usage();
1597 }
1598 }
1599 /* A shell is interactive if the `-i' flag was given, or if all of
1600 * the following conditions are met:
1601 * no -c command
1602 * no arguments remaining or the -s flag given
1603 * standard input is a terminal
1604 * standard output is a terminal
1605 * Refer to Posix.2, the description of the `sh' utility. */
1606 if (argv[optind]==NULL && input==stdin &&
1607 isatty(fileno(stdin)) && isatty(fileno(stdout))) {
1608 interactive=TRUE;
1609 }
1610 setup_job_control();
1611 if (interactive==TRUE) {
1612 //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
1613 /* Looks like they want an interactive shell */
1614#ifndef BB_FEATURE_SH_EXTRA_QUIET
1615 printf( "\n\n" BB_BANNER " Built-in shell (lash)\n");
1616 printf( "Enter 'help' for a list of built-in commands.\n\n");
1617#endif
1618 } else if (local_pending_command==NULL) {
1619 //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
1620 input = xfopen(argv[optind], "r");
1621 mark_open(fileno(input)); /* be lazy, never mark this closed */
1622 }
1623
1624 /* initialize the cwd -- this is never freed...*/
1625 cwd = xgetcwd(0);
1626 if (!cwd)
1627 cwd = unknown;
1628
1629#ifdef BB_FEATURE_CLEAN_UP
1630 atexit(free_memory);
1631#endif
1632
1633#ifdef BB_FEATURE_COMMAND_EDITING
1634 cmdedit_set_initial_prompt();
1635#else
1636 PS1 = NULL;
1637#endif
1638
1639 return (busy_loop(input));
1640}
diff --git a/length.c b/length.c
deleted file mode 100644
index 73becd28a..000000000
--- a/length.c
+++ /dev/null
@@ -1,13 +0,0 @@
1/* vi: set sw=4 ts=4: */
2#include <stdlib.h>
3#include <string.h>
4#include <stdio.h>
5#include "busybox.h"
6
7extern int length_main(int argc, char **argv)
8{
9 if (argc != 2 || **(argv + 1) == '-')
10 show_usage();
11 printf("%lu\n", (long)strlen(argv[1]));
12 return EXIT_SUCCESS;
13}
diff --git a/libbb/Makefile b/libbb/Makefile
index a9ea76947..60c3dda97 100644
--- a/libbb/Makefile
+++ b/libbb/Makefile
@@ -1,11 +1,75 @@
1# Silly wrapper makefile. This Makefile is _not_ used by the build system for 1# Makefile for busybox
2# busybox, it is just to make working on libbb more conveinient. 2#
3# -Erik Andersen 3# Copyright (C) 2001 Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4 18
5all: 19
6 make -C .. libbb.a 20
21TOPDIR :=..
22L_TARGET := libbb.a
23
24LIBBB_MSRC=messages.c
25LIBBB_OBJ= full_version name_too_long omitting_directory not_a_directory \
26 memory_exhausted invalid_date invalid_option io_error dash_dash_help \
27 write_error too_few_args name_longer_than_foo unknown can_not_create_raw_socket
28LIBBB_MOBJS=$(patsubst %,%.o, $(LIBBB_OBJ))
29
30LIBBB_ARCSRC=unarchive.c
31LIBBB_ARCOBJ= archive_offset seek_sub_file extract_archive unarchive \
32 get_header_ar get_header_cpio get_header_tar deb_extract
33LIBBB_AROBJS=$(patsubst %,%.o, $(LIBBB_ARCOBJ))
34
35
36obj-y :=
37obj-n :=
38obj- :=
39
40obj-y += ask_confirmation.o chomp.o concat_path_file.o copy_file.o \
41 copy_file_chunk.o libc5.o device_open.o error_msg.o \
42 error_msg_and_die.o fgets_str.o find_mount_point.o find_pid_by_name.o \
43 find_root_device.o full_read.o full_write.o get_console.o \
44 get_last_path_component.o get_line_from_file.o gz_open.o human_readable.o \
45 isdirectory.o kernel_version.o loop.o mode_string.o module_syscalls.o mtab.o \
46 mtab_file.o my_getgrnam.o my_getgrgid.o my_getpwnam.o my_getpwnamegid.o \
47 my_getpwuid.o parse_mode.o parse_number.o perror_msg.o perror_msg_and_die.o \
48 print_file.o process_escape_sequence.o read_package_field.o recursive_action.o \
49 safe_read.o safe_strncpy.o syscalls.o syslog_msg_with_name.o time_string.o \
50 trim.o unzip.o vdprintf.o verror_msg.o vperror_msg.o wfopen.o xfuncs.o \
51 xgetcwd.o xreadlink.o xregcomp.o interface.o remove_file.o last_char_is.o \
52 copyfd.o vherror_msg.o herror_msg.o herror_msg_and_die.o xgethostbyname.o \
53 dirname.o make_directory.o create_icmp_socket.o u_signal_names.o arith.o \
54 simplify_path.o $(LIBBB_MOBJS) $(LIBBB_AROBJS)
55
56
57# Hand off to toplevel Rules.mak
58include $(TOPDIR)/Rules.mak
59
60$(LIBBB_MOBJS): $(LIBBB_MSRC)
61 $(CC) $(CFLAGS) -DBB_VER='"$(VERSION)"' -DBB_BT='"$(BUILDTIME)"' \
62 $(LIBBB_CFLAGS) -DL_$(patsubst %,%,$*) -c $< -o $*.o
63
64$(LIBBB_AROBJS): $(LIBBB_ARCSRC)
65 $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst %,%,$*) -c $< -o $*.o
66
67loop.o: loop.h
68
69loop.h: mk_loop_h.sh
70 @ $(SHELL) $< > $@
7 71
8clean: 72clean:
9 - rm -rf libbb.a 73 rm -f $(L_TARGET) *.o core
10 - find -name \*.o -exec rm -f {} \; 74
11 75
diff --git a/libbb/ask_confirmation.c b/libbb/ask_confirmation.c
index f2922379c..d4d943ad7 100644
--- a/libbb/ask_confirmation.c
+++ b/libbb/ask_confirmation.c
@@ -2,27 +2,23 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version. 11 * (at your option) any later version.
13 * 12 *
14 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. 16 * General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * 21 * USA
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 22 */
27 23
28#include <stdio.h> 24#include <stdio.h>
diff --git a/libbb/chomp.c b/libbb/chomp.c
index 111d4cf77..94404a98d 100644
--- a/libbb/chomp.c
+++ b/libbb/chomp.c
@@ -2,27 +2,23 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version. 11 * (at your option) any later version.
13 * 12 *
14 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. 16 * General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * 21 * USA
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 22 */
27 23
28#include <stdio.h> 24#include <stdio.h>
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c
index 86dd2fbbf..e62b99ef6 100644
--- a/libbb/concat_path_file.c
+++ b/libbb/concat_path_file.c
@@ -1,9 +1,28 @@
1/* vi: set sw=4 ts=4: */
1/* 2/*
2 * busybox library eXtendet funcion 3 * Utility routines.
3 * 4 *
4 * concatenate path and file name to new allocation buffer, 5 * Copyright (C) many different people. If you wrote this, please
5 * not addition '/' if path name already have '/' 6 * acknowledge your work.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
6 * 17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 */
23
24/* concatenate path and file name to new allocation buffer,
25 * not addition '/' if path name already have '/'
7*/ 26*/
8 27
9#include <string.h> 28#include <string.h>
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index d3902ffbe..a80e30b50 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -2,7 +2,6 @@
2/* 2/*
3 * Mini copy_file implementation for busybox 3 * Mini copy_file implementation for busybox
4 * 4 *
5 *
6 * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu> 5 * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 * 6 *
8 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
diff --git a/libbb/copy_file_chunk.c b/libbb/copy_file_chunk.c
index c440a6102..63d2ab173 100644
--- a/libbb/copy_file_chunk.c
+++ b/libbb/copy_file_chunk.c
@@ -2,27 +2,23 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version. 11 * (at your option) any later version.
13 * 12 *
14 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. 16 * General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * 21 * USA
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 22 */
27 23
28#include <stdio.h> 24#include <stdio.h>
diff --git a/libbb/copyfd.c b/libbb/copyfd.c
index aa938d105..22d8c3996 100644
--- a/libbb/copyfd.c
+++ b/libbb/copyfd.c
@@ -2,7 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) 1999-2001 Erik Andersen <andersee@debian.org> 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
diff --git a/libbb/device_open.c b/libbb/device_open.c
index 8e97ce6c5..30b33d7f0 100644
--- a/libbb/device_open.c
+++ b/libbb/device_open.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/error_msg.c b/libbb/error_msg.c
index c7d5fdb98..58308b6be 100644
--- a/libbb/error_msg.c
+++ b/libbb/error_msg.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/error_msg_and_die.c b/libbb/error_msg_and_die.c
index b950ee00c..67a79c375 100644
--- a/libbb/error_msg_and_die.c
+++ b/libbb/error_msg_and_die.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/fgets_str.c b/libbb/fgets_str.c
index 4943464d5..6588f9482 100644
--- a/libbb/fgets_str.c
+++ b/libbb/fgets_str.c
@@ -1,17 +1,23 @@
1/* vi: set sw=4 ts=4: */
1/* 2/*
2 * This program is free software; you can redistribute it and/or modify 3 * Utility routines.
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 * 4 *
7 * This program is distributed in the hope that it will be useful, 5 * Copyright (C) many different people. If you wrote this, please
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 6 * acknowledge your work.
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
11 * 7 *
12 * You should have received a copy of the GNU General Public License 8 * This program is free software; you can redistribute it and/or modify
13 * along with this program; if not, write to the Free Software 9 * it under the terms of the GNU General Public License as published by
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */ 21 */
16 22
17 23
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
index 2d9481a69..1eb5dc942 100644
--- a/libbb/find_mount_point.c
+++ b/libbb/find_mount_point.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c
index 7f39dd41c..f183cc0bd 100644
--- a/libbb/find_pid_by_name.c
+++ b/libbb/find_pid_by_name.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
@@ -36,7 +30,7 @@
36 30
37 31
38/* For Erik's nifty devps device driver */ 32/* For Erik's nifty devps device driver */
39#ifdef BB_FEATURE_USE_DEVPS_PATCH 33#ifdef CONFIG_FEATURE_USE_DEVPS_PATCH
40#include <linux/devps.h> 34#include <linux/devps.h>
41 35
42/* find_pid_by_name() 36/* find_pid_by_name()
@@ -120,7 +114,7 @@ extern pid_t* find_pid_by_name( char* pidName)
120 return pidList; 114 return pidList;
121} 115}
122 116
123#else /* BB_FEATURE_USE_DEVPS_PATCH */ 117#else /* CONFIG_FEATURE_USE_DEVPS_PATCH */
124 118
125/* find_pid_by_name() 119/* find_pid_by_name()
126 * 120 *
@@ -187,7 +181,7 @@ extern pid_t* find_pid_by_name( char* pidName)
187 } 181 }
188 return pidList; 182 return pidList;
189} 183}
190#endif /* BB_FEATURE_USE_DEVPS_PATCH */ 184#endif /* CONFIG_FEATURE_USE_DEVPS_PATCH */
191 185
192/* END CODE */ 186/* END CODE */
193/* 187/*
diff --git a/libbb/find_root_device.c b/libbb/find_root_device.c
index f8f68464d..0a3f1bc77 100644
--- a/libbb/find_root_device.c
+++ b/libbb/find_root_device.c
@@ -1,8 +1,9 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * Copyright (C) 2000,2001 by Lineo, inc. 3 * Utility routines.
4 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
5 * 4 *
5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * Patched by a bunch of people. Feel free to acknowledge your work. 7 * Patched by a bunch of people. Feel free to acknowledge your work.
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
@@ -18,7 +19,6 @@
18 * You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software 20 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */ 22 */
23 23
24#include <stdio.h> 24#include <stdio.h>
diff --git a/libbb/full_read.c b/libbb/full_read.c
index e9c4bbfc6..ccf26fc3d 100644
--- a/libbb/full_read.c
+++ b/libbb/full_read.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/full_write.c b/libbb/full_write.c
index dc9937fa3..a2c07fbc9 100644
--- a/libbb/full_write.c
+++ b/libbb/full_write.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/get_console.c b/libbb/get_console.c
index 3b36a59e7..04a6bd1a6 100644
--- a/libbb/get_console.c
+++ b/libbb/get_console.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -19,10 +18,6 @@
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 21 */
27 22
28#include <stdio.h> 23#include <stdio.h>
diff --git a/libbb/get_last_path_component.c b/libbb/get_last_path_component.c
index f1ddfbde0..85c7609c9 100644
--- a/libbb/get_last_path_component.c
+++ b/libbb/get_last_path_component.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
index 759481731..9035c0412 100644
--- a/libbb/get_line_from_file.c
+++ b/libbb/get_line_from_file.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -19,10 +18,6 @@
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 21 */
27 22
28#include <stdio.h> 23#include <stdio.h>
diff --git a/libbb/gz_open.c b/libbb/gz_open.c
index ef30ff894..dbaf3bb02 100644
--- a/libbb/gz_open.c
+++ b/libbb/gz_open.c
@@ -1,3 +1,26 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people. If you wrote this, please
6 * acknowledge your work.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 */
23
1#include <sys/types.h> 24#include <sys/types.h>
2#include <sys/wait.h> 25#include <sys/wait.h>
3#include <signal.h> 26#include <signal.h>
diff --git a/libbb/herror_msg.c b/libbb/herror_msg.c
index f4210edad..1081a56b1 100644
--- a/libbb/herror_msg.c
+++ b/libbb/herror_msg.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdarg.h> 22#include <stdarg.h>
diff --git a/libbb/herror_msg_and_die.c b/libbb/herror_msg_and_die.c
index 0df5ed016..64482d859 100644
--- a/libbb/herror_msg_and_die.c
+++ b/libbb/herror_msg_and_die.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,11 +17,8 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
21/* vi: set sw=4 ts=4: */
27 22
28#include <stdarg.h> 23#include <stdarg.h>
29#include <stdlib.h> 24#include <stdlib.h>
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
index 790af8f31..52c54cdc1 100644
--- a/libbb/inode_hash.c
+++ b/libbb/inode_hash.c
@@ -2,27 +2,23 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version. 11 * (at your option) any later version.
13 * 12 *
14 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. 16 * General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * 21 * USA
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 22 */
27 23
28#include <stdio.h> 24#include <stdio.h>
diff --git a/libbb/interface.c b/libbb/interface.c
index 484597c5f..e69be15e6 100644
--- a/libbb/interface.c
+++ b/libbb/interface.c
@@ -1,9 +1,21 @@
1/* 1/*
2 * stolen from net-tools-1.59 and stripped down for busybox by
3 * Erik Andersen <andersee@debian.org>
4 *
5 * Heavily modified by Manuel Novoa III Mar 12, 2001
6 *
7 * Pruned unused code using KEEP_UNUSED define.
8 * Added print_bytes_scaled function to reduce code size.
9 * Added some (potentially) missing defines.
10 * Improved display support for -a and for a named interface.
11 *
12 * -----------------------------------------------------------
13 *
2 * ifconfig This file contains an implementation of the command 14 * ifconfig This file contains an implementation of the command
3 * that either displays or sets the characteristics of 15 * that either displays or sets the characteristics of
4 * one or more of the system's networking interfaces. 16 * one or more of the system's networking interfaces.
5 * 17 *
6 * Version: $Id: interface.c,v 1.4 2001/07/19 22:28:02 andersen Exp $ 18 * Version: $Id: interface.c,v 1.5 2001/10/24 04:59:38 andersen Exp $
7 * 19 *
8 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> 20 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
9 * and others. Copyright 1993 MicroWalt Corporation 21 * and others. Copyright 1993 MicroWalt Corporation
@@ -22,17 +34,6 @@
22 * 10/1998 - Andi Kleen. Use interface list primitives. 34 * 10/1998 - Andi Kleen. Use interface list primitives.
23 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu 35 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
24 * (default AF was wrong) 36 * (default AF was wrong)
25 * stolen from net-tools-1.59 and stripped down for busybox by
26 * Erik Andersen <andersee@debian.org>
27 */
28
29/*
30 * Heavily modified by Manuel Novoa III Mar 12, 2001
31 *
32 * Pruned unused code using KEEP_UNUSED define.
33 * Added print_bytes_scaled function to reduce code size.
34 * Added some (potentially) missing defines.
35 * Improved display support for -a and for a named interface.
36 */ 37 */
37 38
38/* #define KEEP_UNUSED */ 39/* #define KEEP_UNUSED */
diff --git a/libbb/isdirectory.c b/libbb/isdirectory.c
index 65f4fee00..3dfe10522 100644
--- a/libbb/isdirectory.c
+++ b/libbb/isdirectory.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
6 * isn't something I'm going to worry about... If you wrote something 6 * Permission has been granted to redistribute this code under the GPL.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -19,10 +18,6 @@
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 21 */
27 22
28#include <stdio.h> 23#include <stdio.h>
diff --git a/libbb/kernel_version.c b/libbb/kernel_version.c
index 09cd582c4..694af8e2c 100644
--- a/libbb/kernel_version.c
+++ b/libbb/kernel_version.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/libbb.h b/libbb/libbb.h
deleted file mode 100644
index 3ef0278f8..000000000
--- a/libbb/libbb.h
+++ /dev/null
@@ -1,326 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Busybox main internal header file
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
21 * Permission has been granted to redistribute this code under the GPL.
22 *
23 */
24#ifndef __LIBBB_H__
25#define __LIBBB_H__ 1
26
27#include <stdio.h>
28#include <stdarg.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31
32#include <netdb.h>
33
34#ifdef DMALLOC
35#include "dmalloc.h"
36#endif
37
38#include <features.h>
39
40#ifndef _BB_INTERNAL_H_
41#include "../busybox.h"
42#endif
43
44#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__)
45/* libc5 doesn't define socklen_t */
46typedef unsigned int socklen_t;
47/* libc5 doesn't implement BSD 4.4 daemon() */
48extern int daemon (int nochdir, int noclose);
49/* libc5 doesn't implement strtok_r */
50char *strtok_r(char *s, const char *delim, char **ptrptr);
51#endif
52
53/* Some useful definitions */
54#define FALSE ((int) 0)
55#define TRUE ((int) 1)
56#define SKIP ((int) 2)
57
58/* for mtab.c */
59#define MTAB_GETMOUNTPT '1'
60#define MTAB_GETDEVICE '2'
61
62#define BUF_SIZE 8192
63#define EXPAND_ALLOC 1024
64
65static inline int is_decimal(int ch) { return ((ch >= '0') && (ch <= '9')); }
66static inline int is_octal(int ch) { return ((ch >= '0') && (ch <= '7')); }
67
68/* Macros for min/max. */
69#ifndef MIN
70#define MIN(a,b) (((a)<(b))?(a):(b))
71#endif
72
73#ifndef MAX
74#define MAX(a,b) (((a)>(b))?(a):(b))
75#endif
76
77
78
79extern void show_usage(void) __attribute__ ((noreturn));
80extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
81extern void error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
82extern void perror_msg(const char *s, ...);
83extern void perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
84extern void vherror_msg(const char *s, va_list p);
85extern void herror_msg(const char *s, ...);
86extern void herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
87
88/* These two are used internally -- you shouldn't need to use them */
89extern void verror_msg(const char *s, va_list p);
90extern void vperror_msg(const char *s, va_list p);
91
92const char *mode_string(int mode);
93const char *time_string(time_t timeVal);
94int is_directory(const char *name, int followLinks, struct stat *statBuf);
95int isDevice(const char *name);
96
97int remove_file(const char *path, int flags);
98int copy_file(const char *source, const char *dest, int flags);
99int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize);
100char *buildName(const char *dirName, const char *fileName);
101int makeString(int argc, const char **argv, char *buf, int bufLen);
102char *getChunk(int size);
103char *chunkstrdup(const char *str);
104void freeChunks(void);
105ssize_t safe_read(int fd, void *buf, size_t count);
106int full_write(int fd, const char *buf, int len);
107int full_read(int fd, char *buf, int len);
108int recursive_action(const char *fileName, int recurse, int followLinks, int depthFirst,
109 int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData),
110 int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData),
111 void* userData);
112
113extern int parse_mode( const char* s, mode_t* theMode);
114
115extern int get_kernel_revision(void);
116
117extern int get_console_fd(char* tty_name);
118extern struct mntent *find_mount_point(const char *name, const char *table);
119extern void write_mtab(char* blockDevice, char* directory,
120 char* filesystemType, long flags, char* string_flags);
121extern void erase_mtab(const char * name);
122extern long atoi_w_units (const char *cp);
123extern pid_t* find_pid_by_name( char* pidName);
124extern char *find_real_root_device_name(const char* name);
125extern char *get_line_from_file(FILE *file);
126extern void print_file(FILE *file);
127extern int copyfd(int fd1, int fd2);
128extern int print_file_by_name(char *filename);
129extern char process_escape_sequence(const char **ptr);
130extern char *get_last_path_component(char *path);
131extern FILE *wfopen(const char *path, const char *mode);
132extern FILE *xfopen(const char *path, const char *mode);
133extern void chomp(char *s);
134extern void trim(char *s);
135extern struct BB_applet *find_applet_by_name(const char *name);
136void run_applet_by_name(const char *name, int argc, char **argv);
137
138#ifndef DMALLOC
139extern void *xmalloc (size_t size);
140extern void *xrealloc(void *old, size_t size);
141extern void *xcalloc(size_t nmemb, size_t size);
142extern char *xstrdup (const char *s);
143#endif
144extern char *xstrndup (const char *s, int n);
145extern char * safe_strncpy(char *dst, const char *src, size_t size);
146
147struct suffix_mult {
148 const char *suffix;
149 int mult;
150};
151
152extern unsigned long parse_number(const char *numstr,
153 const struct suffix_mult *suffixes);
154
155
156/* These parse entries in /etc/passwd and /etc/group. This is desirable
157 * for BusyBox since we want to avoid using the glibc NSS stuff, which
158 * increases target size and is often not needed embedded systems. */
159extern long my_getpwnam(const char *name);
160extern long my_getgrnam(const char *name);
161extern void my_getpwuid(char *name, long uid);
162extern void my_getgrgid(char *group, long gid);
163extern long my_getpwnamegid(const char *name);
164
165extern int device_open(char *device, int mode);
166
167extern int del_loop(const char *device);
168extern int set_loop(const char *device, const char *file, int offset, int *loopro);
169extern char *find_unused_loop_device (void);
170
171
172#if (__GLIBC__ < 2)
173extern int vdprintf(int d, const char *format, va_list ap);
174#endif
175
176int nfsmount(const char *spec, const char *node, int *flags,
177 char **extra_opts, char **mount_opts, int running_bg);
178
179void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg);
180void syslog_msg(int facility, int pri, const char *msg);
181
182/* Include our own copy of struct sysinfo to avoid binary compatability
183 * problems with Linux 2.4, which changed things. Grumble, grumble. */
184struct sysinfo {
185 long uptime; /* Seconds since boot */
186 unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
187 unsigned long totalram; /* Total usable main memory size */
188 unsigned long freeram; /* Available memory size */
189 unsigned long sharedram; /* Amount of shared memory */
190 unsigned long bufferram; /* Memory used by buffers */
191 unsigned long totalswap; /* Total swap space size */
192 unsigned long freeswap; /* swap space still available */
193 unsigned short procs; /* Number of current processes */
194 unsigned short pad; /* Padding needed for m68k */
195 unsigned long totalhigh; /* Total high memory size */
196 unsigned long freehigh; /* Available high memory size */
197 unsigned int mem_unit; /* Memory unit size in bytes */
198 char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
199};
200extern int sysinfo (struct sysinfo* info);
201
202enum {
203 KILOBYTE = 1024,
204 MEGABYTE = (KILOBYTE*1024),
205 GIGABYTE = (MEGABYTE*1024)
206};
207const char *make_human_readable_str(unsigned long size, unsigned long block_size, unsigned long display_unit);
208
209int ask_confirmation(void);
210int klogctl(int type, char * b, int len);
211
212char *xgetcwd(char *cwd);
213char *xreadlink(const char *path);
214char *concat_path_file(const char *path, const char *filename);
215char *last_char_is(const char *s, int c);
216
217extern long arith (const char *startbuf, int *errcode);
218
219typedef struct file_headers_s {
220 char *name;
221 char *link_name;
222 off_t size;
223 uid_t uid;
224 gid_t gid;
225 mode_t mode;
226 time_t mtime;
227 dev_t device;
228} file_header_t;
229file_header_t *get_header_ar(FILE *in_file);
230file_header_t *get_header_cpio(FILE *src_stream);
231file_header_t *get_header_tar(FILE *tar_stream);
232
233enum extract_functions_e {
234 extract_verbose_list = 1,
235 extract_list = 2,
236 extract_one_to_buffer = 4,
237 extract_to_stdout = 8,
238 extract_all_to_fs = 16,
239 extract_preserve_date = 32,
240 extract_data_tar_gz = 64,
241 extract_control_tar_gz = 128,
242 extract_unzip_only = 256,
243 extract_unconditional = 512,
244 extract_create_leading_dirs = 1024,
245 extract_quiet = 2048,
246 extract_exclude_list = 4096
247};
248char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_headers)(FILE *),
249 const int extract_function, const char *prefix, char **include_name, char **exclude_name);
250char *deb_extract(const char *package_filename, FILE *out_stream, const int extract_function,
251 const char *prefix, const char *filename);
252int read_package_field(const char *package_buffer, char **field_name, char **field_value);
253char *fgets_str(FILE *file, const char *terminating_string);
254
255extern int unzip(FILE *l_in_file, FILE *l_out_file);
256extern void gz_close(int gunzip_pid);
257extern FILE *gz_open(FILE *compressed_file, int *pid);
258
259extern struct hostent *xgethostbyname(const char *name);
260extern int create_icmp_socket(void);
261
262char *dirname (char *path);
263
264int make_directory (char *path, long mode, int flags);
265
266const char *u_signal_names(const char *str_sig, int *signo, int startnum);
267char *simplify_path(const char *path);
268
269#define CT_AUTO 0
270#define CT_UNIX2DOS 1
271#define CT_DOS2UNIX 2
272/* extern int convert(char *fn, int ConvType); */
273
274enum {
275 FILEUTILS_PRESERVE_STATUS = 1,
276 FILEUTILS_DEREFERENCE = 2,
277 FILEUTILS_RECUR = 4,
278 FILEUTILS_FORCE = 8,
279 FILEUTILS_INTERACTIVE = 16
280};
281
282extern const char *applet_name;
283extern const char * const full_version;
284extern const char * const name_too_long;
285extern const char * const omitting_directory;
286extern const char * const not_a_directory;
287extern const char * const memory_exhausted;
288extern const char * const invalid_date;
289extern const char * const invalid_option;
290extern const char * const io_error;
291extern const char * const dash_dash_help;
292extern const char * const write_error;
293extern const char * const too_few_args;
294extern const char * const name_longer_than_foo;
295extern const char * const unknown;
296extern const char * const can_not_create_raw_socket;
297
298#ifdef BB_FEATURE_DEVFS
299# define CURRENT_VC "/dev/vc/0"
300# define VC_1 "/dev/vc/1"
301# define VC_2 "/dev/vc/2"
302# define VC_3 "/dev/vc/3"
303# define VC_4 "/dev/vc/4"
304# define VC_5 "/dev/vc/5"
305# define SC_0 "/dev/tts/0"
306# define SC_1 "/dev/tts/1"
307# define VC_FORMAT "/dev/vc/%d"
308# define SC_FORMAT "/dev/tts/%d"
309#else
310# define CURRENT_VC "/dev/tty0"
311# define VC_1 "/dev/tty1"
312# define VC_2 "/dev/tty2"
313# define VC_3 "/dev/tty3"
314# define VC_4 "/dev/tty4"
315# define VC_5 "/dev/tty5"
316# define SC_0 "/dev/ttyS0"
317# define SC_1 "/dev/ttyS1"
318# define VC_FORMAT "/dev/tty%d"
319# define SC_FORMAT "/dev/ttyS%d"
320#endif
321
322/* The following devices are the same on devfs and non-devfs systems. */
323#define CURRENT_TTY "/dev/tty"
324#define CONSOLE_DEV "/dev/console"
325
326#endif /* __LIBBB_H__ */
diff --git a/libbb/loop.c b/libbb/loop.c
index 4754b8da1..36b13d6e6 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/messages.c b/libbb/messages.c
index 552c3ab5b..895cfdc2b 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -1,7 +1,7 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * Copyright (C) 2001 by Lineo, inc. 3 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
4 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 4 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
19 * 19 *
20 */ 20 */
21 21
22#include "busybox.h"
22#include "libbb.h" 23#include "libbb.h"
23 24
24#ifdef L_full_version 25#ifdef L_full_version
diff --git a/libbb/mode_string.c b/libbb/mode_string.c
index 0a3d6e6f0..12dc17966 100644
--- a/libbb/mode_string.c
+++ b/libbb/mode_string.c
@@ -2,27 +2,23 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version. 11 * (at your option) any later version.
13 * 12 *
14 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. 16 * General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * 21 * USA
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 22 */
27 23
28#include <stdio.h> 24#include <stdio.h>
diff --git a/libbb/module_syscalls.c b/libbb/module_syscalls.c
index 8326f15ad..3b60649a8 100644
--- a/libbb/module_syscalls.c
+++ b/libbb/module_syscalls.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * some system calls possibly missing from libc 3 * some system calls possibly missing from libc
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/libbb/mtab.c b/libbb/mtab.c
index 28c9978ef..c521b1e05 100644
--- a/libbb/mtab.c
+++ b/libbb/mtab.c
@@ -1,4 +1,24 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
2#include <stdlib.h> 22#include <stdlib.h>
3#include <unistd.h> 23#include <unistd.h>
4#include <errno.h> 24#include <errno.h>
diff --git a/libbb/mtab_file.c b/libbb/mtab_file.c
index 56f8e06ab..267a13720 100644
--- a/libbb/mtab_file.c
+++ b/libbb/mtab_file.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
@@ -31,10 +25,10 @@
31 25
32/* Busybox mount uses either /proc/mounts or /dev/mtab to 26/* Busybox mount uses either /proc/mounts or /dev/mtab to
33 * get the list of currently mounted filesystems */ 27 * get the list of currently mounted filesystems */
34#if defined BB_FEATURE_MTAB_SUPPORT 28#if defined CONFIG_FEATURE_MTAB_SUPPORT
35const char mtab_file[] = "/etc/mtab"; 29const char mtab_file[] = "/etc/mtab";
36#else 30#else
37# if defined BB_FEATURE_USE_DEVPS_PATCH 31# if defined CONFIG_FEATURE_USE_DEVPS_PATCH
38 const char mtab_file[] = "/dev/mtab"; 32 const char mtab_file[] = "/dev/mtab";
39# else 33# else
40 const char mtab_file[] = "/proc/mounts"; 34 const char mtab_file[] = "/proc/mounts";
diff --git a/libbb/my_getgrgid.c b/libbb/my_getgrgid.c
index fabd4776c..27b671922 100644
--- a/libbb/my_getgrgid.c
+++ b/libbb/my_getgrgid.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,16 +17,12 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
29#include <string.h> 23#include <string.h>
30#include "../pwd_grp/pwd.h" 24#include "pwd.h"
31#include "../pwd_grp/grp.h" 25#include "grp.h"
32#include "libbb.h" 26#include "libbb.h"
33 27
34 28
diff --git a/libbb/my_getgrnam.c b/libbb/my_getgrnam.c
index e3226a275..dbacf5192 100644
--- a/libbb/my_getgrnam.c
+++ b/libbb/my_getgrnam.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,20 +17,15 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
29#include <string.h> 23#include <string.h>
30#include "../pwd_grp/pwd.h" 24#include "pwd.h"
31#include "../pwd_grp/grp.h" 25#include "grp.h"
32#include "libbb.h" 26#include "libbb.h"
33 27
34 28
35
36/* returns a gid given a group name */ 29/* returns a gid given a group name */
37long my_getgrnam(const char *name) 30long my_getgrnam(const char *name)
38{ 31{
diff --git a/libbb/my_getpwnam.c b/libbb/my_getpwnam.c
index ae73ae7f1..90277040e 100644
--- a/libbb/my_getpwnam.c
+++ b/libbb/my_getpwnam.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,20 +17,15 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
29#include <string.h> 23#include <string.h>
30#include "../pwd_grp/pwd.h" 24#include "pwd.h"
31#include "../pwd_grp/grp.h" 25#include "grp.h"
32#include "libbb.h" 26#include "libbb.h"
33 27
34 28
35
36/* returns a uid given a username */ 29/* returns a uid given a username */
37long my_getpwnam(const char *name) 30long my_getpwnam(const char *name)
38{ 31{
diff --git a/libbb/my_getpwnamegid.c b/libbb/my_getpwnamegid.c
index fb3d148ce..9c45580b5 100644
--- a/libbb/my_getpwnamegid.c
+++ b/libbb/my_getpwnamegid.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,16 +17,12 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
29#include <string.h> 23#include <string.h>
30#include "../pwd_grp/pwd.h" 24#include "pwd.h"
31#include "../pwd_grp/grp.h" 25#include "grp.h"
32#include "libbb.h" 26#include "libbb.h"
33 27
34 28
diff --git a/libbb/my_getpwuid.c b/libbb/my_getpwuid.c
index 46c7a884a..49bc8fb49 100644
--- a/libbb/my_getpwuid.c
+++ b/libbb/my_getpwuid.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,16 +17,12 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
29#include <string.h> 23#include <string.h>
30#include "../pwd_grp/pwd.h" 24#include "pwd.h"
31#include "../pwd_grp/grp.h" 25#include "grp.h"
32#include "libbb.h" 26#include "libbb.h"
33 27
34 28
diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c
index 30d2f21cf..ba34ea929 100644
--- a/libbb/parse_mode.c
+++ b/libbb/parse_mode.c
@@ -2,27 +2,23 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version. 11 * (at your option) any later version.
13 * 12 *
14 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. 16 * General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * 21 * USA
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 22 */
27 23
28#include <stdio.h> 24#include <stdio.h>
diff --git a/libbb/parse_number.c b/libbb/parse_number.c
index c90511dca..755a357ad 100644
--- a/libbb/parse_number.c
+++ b/libbb/parse_number.c
@@ -2,27 +2,23 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version. 11 * (at your option) any later version.
13 * 12 *
14 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. 16 * General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * 21 * USA
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 22 */
27 23
28#include <stdio.h> 24#include <stdio.h>
diff --git a/libbb/perror_msg.c b/libbb/perror_msg.c
index 18c71ab1c..8c57b0d16 100644
--- a/libbb/perror_msg.c
+++ b/libbb/perror_msg.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/perror_msg_and_die.c b/libbb/perror_msg_and_die.c
index 9d304a26b..9004925cc 100644
--- a/libbb/perror_msg_and_die.c
+++ b/libbb/perror_msg_and_die.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/print_file.c b/libbb/print_file.c
index bfedc5eff..a6df14ed9 100644
--- a/libbb/print_file.c
+++ b/libbb/print_file.c
@@ -2,7 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) 1999-2001 Erik Andersen <andersee@debian.org> 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
diff --git a/libbb/read_package_field.c b/libbb/read_package_field.c
index f561df831..ac5f80167 100644
--- a/libbb/read_package_field.c
+++ b/libbb/read_package_field.c
@@ -1,3 +1,26 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people. If you wrote this, please
6 * acknowledge your work.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 */
23
1#include <stdlib.h> 24#include <stdlib.h>
2#include <string.h> 25#include <string.h>
3#include "libbb.h" 26#include "libbb.h"
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
index 6672db17f..e87ab9860 100644
--- a/libbb/recursive_action.c
+++ b/libbb/recursive_action.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/remove_file.c b/libbb/remove_file.c
index 3b84680c4..988b09124 100644
--- a/libbb/remove_file.c
+++ b/libbb/remove_file.c
@@ -2,10 +2,8 @@
2/* 2/*
3 * Mini remove_file implementation for busybox 3 * Mini remove_file implementation for busybox
4 * 4 *
5 *
6 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu> 5 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 * 6 *
8 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 9 * the Free Software Foundation; either version 2 of the License, or
@@ -19,7 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */ 20 */
24 21
25#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/safe_read.c b/libbb/safe_read.c
index dbf4aa7e4..b6d6d742f 100644
--- a/libbb/safe_read.c
+++ b/libbb/safe_read.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/safe_strncpy.c b/libbb/safe_strncpy.c
index 55ec79802..0c5cf12ef 100644
--- a/libbb/safe_strncpy.c
+++ b/libbb/safe_strncpy.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <string.h> 22#include <string.h>
diff --git a/libbb/syscalls.c b/libbb/syscalls.c
index 426a14aa1..383eb6ab9 100644
--- a/libbb/syscalls.c
+++ b/libbb/syscalls.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * some system calls possibly missing from libc 3 * some system calls possibly missing from libc
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/libbb/syslog_msg_with_name.c b/libbb/syslog_msg_with_name.c
index 5dadcc433..6474da459 100644
--- a/libbb/syslog_msg_with_name.c
+++ b/libbb/syslog_msg_with_name.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/time_string.c b/libbb/time_string.c
index 076529006..d103a02f8 100644
--- a/libbb/time_string.c
+++ b/libbb/time_string.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/trim.c b/libbb/trim.c
index 76b87ca1c..cb673cac3 100644
--- a/libbb/trim.c
+++ b/libbb/trim.c
@@ -2,27 +2,23 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version. 11 * (at your option) any later version.
13 * 12 *
14 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. 16 * General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * 21 * USA
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 22 */
27 23
28#include <stdio.h> 24#include <stdio.h>
diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c
index 623b10312..aee1db07c 100644
--- a/libbb/u_signal_names.c
+++ b/libbb/u_signal_names.c
@@ -1,3 +1,26 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people. If you wrote this, please
6 * acknowledge your work.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 */
23
1#include <signal.h> 24#include <signal.h>
2#include <ctype.h> 25#include <ctype.h>
3#include <string.h> 26#include <string.h>
diff --git a/libbb/vdprintf.c b/libbb/vdprintf.c
index 8c3e32a7a..0f250ae69 100644
--- a/libbb/vdprintf.c
+++ b/libbb/vdprintf.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c
index b34821561..21cde2047 100644
--- a/libbb/verror_msg.c
+++ b/libbb/verror_msg.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/vherror_msg.c b/libbb/vherror_msg.c
index 44f6ebd28..67db17fe4 100644
--- a/libbb/vherror_msg.c
+++ b/libbb/vherror_msg.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdarg.h> 22#include <stdarg.h>
diff --git a/libbb/vperror_msg.c b/libbb/vperror_msg.c
index ca9361e45..7da5bae0a 100644
--- a/libbb/vperror_msg.c
+++ b/libbb/vperror_msg.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/wfopen.c b/libbb/wfopen.c
index 8b074d2f7..f58ec90c0 100644
--- a/libbb/wfopen.c
+++ b/libbb/wfopen.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index eb93bf139..291bfafd6 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -19,10 +17,6 @@
19 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 20 */
27 21
28#include <stdio.h> 22#include <stdio.h>
diff --git a/libbb/xgethostbyname.c b/libbb/xgethostbyname.c
index be56f2ed1..b71979701 100644
--- a/libbb/xgethostbyname.c
+++ b/libbb/xgethostbyname.c
@@ -2,7 +2,6 @@
2/* 2/*
3 * Mini xgethostbyname implementation. 3 * Mini xgethostbyname implementation.
4 * 4 *
5 *
6 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>. 5 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
7 * 6 *
8 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
diff --git a/libbb/xregcomp.c b/libbb/xregcomp.c
index 6f5e2f0cb..07cf779d1 100644
--- a/libbb/xregcomp.c
+++ b/libbb/xregcomp.c
@@ -2,27 +2,23 @@
2/* 2/*
3 * Utility routines. 3 * Utility routines.
4 * 4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what 5 * Copyright (C) many different people. If you wrote this, please
6 * isn't something I'm going to worry about... If you wrote something 6 * acknowledge your work.
7 * here, please feel free to acknowledge your work.
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version. 11 * (at your option) any later version.
13 * 12 *
14 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. 16 * General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * 21 * USA
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */ 22 */
27 23
28#include <stdio.h> 24#include <stdio.h>
diff --git a/ln.c b/ln.c
deleted file mode 100644
index 7412a86fd..000000000
--- a/ln.c
+++ /dev/null
@@ -1,131 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini ln implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <stdio.h>
25#include <dirent.h>
26#include <string.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <unistd.h>
30#include "busybox.h"
31
32
33static const int LN_SYMLINK = 1;
34static const int LN_FORCE = 2;
35static const int LN_NODEREFERENCE = 4;
36
37/*
38 * linkDestName is where the link points to,
39 * linkSrcName is the name of the link to be created.
40 */
41static int fs_link(const char *link_destname, const char *link_srcname,
42 const int flag)
43{
44 int status;
45 int src_is_dir;
46 char *src_name;
47
48 if (link_destname==NULL)
49 return(FALSE);
50
51 src_name = (char *) xmalloc(strlen(link_srcname)+strlen(link_destname)+1);
52
53 if (link_srcname==NULL)
54 strcpy(src_name, link_destname);
55 else
56 strcpy(src_name, link_srcname);
57
58 if (flag&LN_NODEREFERENCE)
59 src_is_dir = is_directory(src_name, TRUE, NULL);
60 else
61 src_is_dir = is_directory(src_name, FALSE, NULL);
62
63 if ((src_is_dir==TRUE)&&((flag&LN_NODEREFERENCE)==0)) {
64 char* srcdir_name;
65
66 srcdir_name = xstrdup(link_destname);
67 strcat(src_name, "/");
68 strcat(src_name, get_last_path_component(srcdir_name));
69 free(srcdir_name);
70 }
71
72 if (flag&LN_FORCE)
73 unlink(src_name);
74
75 if (flag&LN_SYMLINK)
76 status = symlink(link_destname, src_name);
77 else
78 status = link(link_destname, src_name);
79
80 if (status != 0) {
81 perror_msg(src_name);
82 return(FALSE);
83 }
84 return(TRUE);
85}
86
87extern int ln_main(int argc, char **argv)
88{
89 int status = EXIT_SUCCESS;
90 int flag = 0;
91 int opt;
92
93 /* Parse any options */
94 while ((opt=getopt(argc, argv, "sfn")) != -1) {
95 switch(opt) {
96 case 's':
97 flag |= LN_SYMLINK;
98 break;
99 case 'f':
100 flag |= LN_FORCE;
101 break;
102 case 'n':
103 flag |= LN_NODEREFERENCE;
104 break;
105 default:
106 show_usage();
107 }
108 }
109 if (optind > (argc-1)) {
110 show_usage();
111 }
112 if (optind == (argc-1)) {
113 if (fs_link(argv[optind],
114 get_last_path_component(argv[optind]), flag)==FALSE)
115 status = EXIT_FAILURE;
116 }
117 while(optind<(argc-1)) {
118 if (fs_link(argv[optind], argv[argc-1], flag)==FALSE)
119 status = EXIT_FAILURE;
120 optind++;
121 }
122 exit(status);
123}
124
125/*
126Local Variables:
127c-file-style: "linux"
128c-basic-offset: 4
129tab-width: 4
130End:
131*/
diff --git a/loadacm.c b/loadacm.c
deleted file mode 100644
index 3fb4e7665..000000000
--- a/loadacm.c
+++ /dev/null
@@ -1,357 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Derived from
4 * mapscrn.c - version 0.92
5 *
6 * Was taken from console-tools and adapted by
7 * Peter Novodvorsky <petya@logic.ru>
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <memory.h>
13#include <string.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <assert.h>
17#include <errno.h>
18#include <signal.h>
19#include <sys/kd.h>
20#include <sys/types.h>
21#include <sys/ioctl.h>
22#include "busybox.h"
23
24typedef unsigned short unicode;
25
26static long int ctoi(unsigned char *s, int *is_unicode);
27static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]);
28static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode);
29static unicode utf8_to_ucs2(char *buf);
30static int screen_map_load(int fd, FILE * fp);
31
32int loadacm_main(int argc, char **argv)
33{
34 int fd;
35
36 if (argc>=2 && *argv[1]=='-') {
37 show_usage();
38 }
39
40 fd = open(CURRENT_VC, O_RDWR);
41 if (fd < 0) {
42 perror_msg_and_die("Error opening " CURRENT_VC);
43 }
44
45 if (screen_map_load(fd, stdin)) {
46 perror_msg_and_die("Error loading acm");
47 }
48
49 write(fd, "\033(K", 3);
50
51 return EXIT_SUCCESS;
52}
53
54static int screen_map_load(int fd, FILE * fp)
55{
56 struct stat stbuf;
57 unicode wbuf[E_TABSZ];
58 unsigned char buf[E_TABSZ];
59 int parse_failed = 0;
60 int is_unicode;
61
62 if (fstat(fileno(fp), &stbuf))
63 perror_msg_and_die("Cannot stat map file");
64
65 /* first try a UTF screen-map: either ASCII (no restriction) or binary (regular file) */
66 if (!
67 (parse_failed =
68 (-1 == uni_screen_map_read_ascii(fp, wbuf, &is_unicode)))
69|| (S_ISREG(stbuf.st_mode) && (stbuf.st_size == (sizeof(unicode) * E_TABSZ)))) { /* test for binary UTF map by size */
70 if (parse_failed) {
71 if (-1 == fseek(fp, 0, SEEK_SET)) {
72 if (errno == ESPIPE)
73 error_msg_and_die("16bit screen-map MUST be a regular file.");
74 else
75 perror_msg_and_die("fseek failed reading binary 16bit screen-map");
76 }
77
78 if (fread(wbuf, sizeof(unicode) * E_TABSZ, 1, fp) != 1)
79 perror_msg_and_die("Cannot read [new] map from file");
80#if 0
81 else
82 error_msg("Input screen-map is binary.");
83#endif
84 }
85
86 /* if it was effectively a 16-bit ASCII, OK, else try to read as 8-bit map */
87 /* same if it was binary, ie. if parse_failed */
88 if (parse_failed || is_unicode) {
89 if (ioctl(fd, PIO_UNISCRNMAP, wbuf))
90 perror_msg_and_die("PIO_UNISCRNMAP ioctl");
91 else
92 return 0;
93 }
94 }
95
96 /* rewind... */
97 if (-1 == fseek(fp, 0, SEEK_SET)) {
98 if (errno == ESPIPE)
99 error_msg("Assuming 8bit screen-map - MUST be a regular file."),
100 exit(1);
101 else
102 perror_msg_and_die("fseek failed assuming 8bit screen-map");
103 }
104
105 /* ... and try an old 8-bit screen-map */
106 if (!(parse_failed = (-1 == old_screen_map_read_ascii(fp, buf))) ||
107 (S_ISREG(stbuf.st_mode) && (stbuf.st_size == E_TABSZ))) { /* test for binary old 8-bit map by size */
108 if (parse_failed) {
109 if (-1 == fseek(fp, 0, SEEK_SET)) {
110 if (errno == ESPIPE)
111 /* should not - it succedeed above */
112 error_msg_and_die("fseek() returned ESPIPE !");
113 else
114 perror_msg_and_die("fseek for binary 8bit screen-map");
115 }
116
117 if (fread(buf, E_TABSZ, 1, fp) != 1)
118 perror_msg_and_die("Cannot read [old] map from file");
119#if 0
120 else
121 error_msg("Input screen-map is binary.");
122#endif
123 }
124
125 if (ioctl(fd, PIO_SCRNMAP, buf))
126 perror_msg_and_die("PIO_SCRNMAP ioctl");
127 else
128 return 0;
129 }
130 error_msg("Error parsing symbolic map");
131 return(1);
132}
133
134
135/*
136 * - reads `fp' as a 16-bit ASCII SFM file.
137 * - returns -1 on error.
138 * - returns it in `unicode' in an E_TABSZ-elements array.
139 * - sets `*is_unicode' flagiff there were any non-8-bit
140 * (ie. real 16-bit) mapping.
141 *
142 * FIXME: ignores everything after second word
143 */
144static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode)
145{
146 char buffer[256]; /* line buffer reading file */
147 char *p, *q; /* 1st + 2nd words in line */
148 int in, on; /* the same, as numbers */
149 int tmp_is_unicode; /* tmp for is_unicode calculation */
150 int i; /* loop index - result holder */
151 int ret_code = 0; /* return code */
152 sigset_t acmsigset, old_sigset;
153
154 assert(is_unicode);
155
156 *is_unicode = 0;
157
158 /* first 128 codes defaults to ASCII */
159 for (i = 0; i < 128; i++)
160 buf[i] = i;
161 /* remaining defaults to replacement char (usually E_TABSZ = 256) */
162 for (; i < E_TABSZ; i++)
163 buf[i] = 0xfffd;
164
165 /* block SIGCHLD */
166 sigemptyset(&acmsigset);
167 sigaddset(&acmsigset, SIGCHLD);
168 sigprocmask(SIG_BLOCK, &acmsigset, &old_sigset);
169
170 do {
171 if (NULL == fgets(buffer, sizeof(buffer), fp)) {
172 if (feof(fp))
173 break;
174 else
175 perror_msg_and_die("uni_screen_map_read_ascii() can't read line");
176 }
177
178 /* get "charset-relative charcode", stripping leading spaces */
179 p = strtok(buffer, " \t\n");
180
181 /* skip empty lines and comments */
182 if (!p || *p == '#')
183 continue;
184
185 /* get unicode mapping */
186 q = strtok(NULL, " \t\n");
187 if (q) {
188 in = ctoi(p, NULL);
189 if (in < 0 || in > 255) {
190 ret_code = -1;
191 break;
192 }
193
194 on = ctoi(q, &tmp_is_unicode);
195 if (in < 0 && on > 65535) {
196 ret_code = -1;
197 break;
198 }
199
200 *is_unicode |= tmp_is_unicode;
201 buf[in] = on;
202 } else {
203 ret_code = -1;
204 break;
205 }
206 }
207 while (1); /* terminated by break on feof() */
208
209 /* restore sig mask */
210 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
211
212 return ret_code;
213}
214
215
216static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[])
217{
218 char buffer[256];
219 int in, on;
220 char *p, *q;
221
222 for (in = 0; in < 256; in++)
223 buf[in] = in;
224
225 while (fgets(buffer, sizeof(buffer) - 1, fp)) {
226 p = strtok(buffer, " \t\n");
227
228 if (!p || *p == '#')
229 continue;
230
231 q = strtok(NULL, " \t\n#");
232 if (q) {
233 in = ctoi(p, NULL);
234 if (in < 0 || in > 255)
235 return -1;
236
237 on = ctoi(q, NULL);
238 if (in < 0 && on > 255)
239 return -1;
240
241 buf[in] = on;
242 } else
243 return -1;
244 }
245
246 return (0);
247}
248
249
250/*
251 * - converts a string into an int.
252 * - supports dec and hex bytes, hex UCS2, single-quoted byte and UTF8 chars.
253 * - returns the converted value
254 * - if `is_unicode != NULL', use it to tell whether it was unicode
255 *
256 * CAVEAT: will report valid UTF mappings using only 1 byte as 8-bit ones.
257 */
258static long int ctoi(unsigned char *s, int *is_unicode)
259{
260 int i;
261 size_t ls;
262
263 ls = strlen(s);
264 if (is_unicode)
265 *is_unicode = 0;
266
267 /* hex-specified UCS2 */
268 if ((strncmp(s, "U+", 2) == 0) &&
269 (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) {
270 sscanf(s + 2, "%x", &i);
271 if (is_unicode)
272 *is_unicode = 1;
273 }
274
275 /* hex-specified byte */
276 else if ((ls <= 4) && (strncmp(s, "0x", 2) == 0) &&
277 (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2))
278 sscanf(s + 2, "%x", &i);
279
280 /* oct-specified number (byte) */
281 else if ((*s == '0') && (strspn(s, "01234567") == ls))
282 sscanf(s, "%o", &i);
283
284 /* dec-specified number (byte) */
285 else if (strspn(s, "0123456789") == ls)
286 sscanf(s, "%d", &i);
287
288 /* single-byte quoted char */
289 else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\''))
290 i = s[1];
291
292 /* multi-byte UTF8 quoted char */
293 else if ((s[0] == '\'') && (s[ls - 1] == '\'')) {
294 s[ls - 1] = 0; /* ensure we'll not "parse UTF too far" */
295 i = utf8_to_ucs2(s + 1);
296 if (is_unicode)
297 *is_unicode = 1;
298 } else
299 return (-1);
300
301 return (i);
302}
303
304
305static unicode utf8_to_ucs2(char *buf)
306{
307 int utf_count = 0;
308 long utf_char = 0;
309 unicode tc = 0;
310 unsigned char c;
311
312 do {
313 c = *buf;
314 buf++;
315
316 /* if byte should be part of multi-byte sequence */
317 if (c & 0x80) {
318 /* if we have already started to parse a UTF8 sequence */
319 if (utf_count > 0 && (c & 0xc0) == 0x80) {
320 utf_char = (utf_char << 6) | (c & 0x3f);
321 utf_count--;
322 if (utf_count == 0)
323 tc = utf_char;
324 else
325 continue;
326 } else { /* Possibly 1st char of a UTF8 sequence */
327
328 if ((c & 0xe0) == 0xc0) {
329 utf_count = 1;
330 utf_char = (c & 0x1f);
331 } else if ((c & 0xf0) == 0xe0) {
332 utf_count = 2;
333 utf_char = (c & 0x0f);
334 } else if ((c & 0xf8) == 0xf0) {
335 utf_count = 3;
336 utf_char = (c & 0x07);
337 } else if ((c & 0xfc) == 0xf8) {
338 utf_count = 4;
339 utf_char = (c & 0x03);
340 } else if ((c & 0xfe) == 0xfc) {
341 utf_count = 5;
342 utf_char = (c & 0x01);
343 } else
344 utf_count = 0;
345 continue;
346 }
347 } else { /* not part of multi-byte sequence - treat as ASCII
348 * this makes incomplete sequences to be ignored
349 */
350 tc = c;
351 utf_count = 0;
352 }
353 }
354 while (utf_count);
355
356 return tc;
357}
diff --git a/loadfont.c b/loadfont.c
deleted file mode 100644
index d66500195..000000000
--- a/loadfont.c
+++ /dev/null
@@ -1,209 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * loadfont.c - Eugene Crosser & Andries Brouwer
4 *
5 * Version 0.96bb
6 *
7 * Loads the console font, and possibly the corresponding screen map(s).
8 * (Adapted for busybox by Matej Vela.)
9 */
10#include <stdio.h>
11#include <string.h>
12#include <fcntl.h>
13#include <memory.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <sys/types.h>
17#include <dirent.h>
18#include <errno.h>
19#include <sys/ioctl.h>
20#include <sys/kd.h>
21#include <endian.h>
22#include "busybox.h"
23
24static const int PSF_MAGIC1 = 0x36;
25static const int PSF_MAGIC2 = 0x04;
26
27static const int PSF_MODE512 = 0x01;
28static const int PSF_MODEHASTAB = 0x02;
29static const int PSF_MAXMODE = 0x03;
30static const int PSF_SEPARATOR = 0xFFFF;
31
32struct psf_header {
33 unsigned char magic1, magic2; /* Magic number */
34 unsigned char mode; /* PSF font mode */
35 unsigned char charsize; /* Character size */
36};
37
38#define PSF_MAGIC_OK(x) ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2)
39
40static void loadnewfont(int fd);
41
42extern int loadfont_main(int argc, char **argv)
43{
44 int fd;
45
46 if (argc != 1)
47 show_usage();
48
49 fd = open(CURRENT_VC, O_RDWR);
50 if (fd < 0)
51 perror_msg_and_die("Error opening " CURRENT_VC);
52 loadnewfont(fd);
53
54 return EXIT_SUCCESS;
55}
56
57static void do_loadfont(int fd, char *inbuf, int unit, int fontsize)
58{
59 char buf[16384];
60 int i;
61
62 memset(buf, 0, sizeof(buf));
63
64 if (unit < 1 || unit > 32)
65 error_msg_and_die("Bad character size %d", unit);
66
67 for (i = 0; i < fontsize; i++)
68 memcpy(buf + (32 * i), inbuf + (unit * i), unit);
69
70#if defined( PIO_FONTX ) && !defined( __sparc__ )
71 {
72 struct consolefontdesc cfd;
73
74 cfd.charcount = fontsize;
75 cfd.charheight = unit;
76 cfd.chardata = buf;
77
78 if (ioctl(fd, PIO_FONTX, &cfd) == 0)
79 return; /* success */
80 perror_msg("PIO_FONTX ioctl error (trying PIO_FONT)");
81 }
82#endif
83 if (ioctl(fd, PIO_FONT, buf))
84 perror_msg_and_die("PIO_FONT ioctl error");
85}
86
87static void
88do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize)
89{
90 struct unimapinit advice;
91 struct unimapdesc ud;
92 struct unipair *up;
93 int ct = 0, maxct;
94 int glyph;
95 u_short unicode;
96
97 maxct = tailsz; /* more than enough */
98 up = (struct unipair *) xmalloc(maxct * sizeof(struct unipair));
99
100 for (glyph = 0; glyph < fontsize; glyph++) {
101 while (tailsz >= 2) {
102 unicode = (((u_short) inbuf[1]) << 8) + inbuf[0];
103 tailsz -= 2;
104 inbuf += 2;
105 if (unicode == PSF_SEPARATOR)
106 break;
107 up[ct].unicode = unicode;
108 up[ct].fontpos = glyph;
109 ct++;
110 }
111 }
112
113 /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
114 this printf did not work on many kernels */
115
116 advice.advised_hashsize = 0;
117 advice.advised_hashstep = 0;
118 advice.advised_hashlevel = 0;
119 if (ioctl(fd, PIO_UNIMAPCLR, &advice)) {
120#ifdef ENOIOCTLCMD
121 if (errno == ENOIOCTLCMD) {
122 error_msg("It seems this kernel is older than 1.1.92");
123 error_msg_and_die("No Unicode mapping table loaded.");
124 } else
125#endif
126 perror_msg_and_die("PIO_UNIMAPCLR");
127 }
128 ud.entry_ct = ct;
129 ud.entries = up;
130 if (ioctl(fd, PIO_UNIMAP, &ud)) {
131#if 0
132 if (errno == ENOMEM) {
133 /* change advice parameters */
134 }
135#endif
136 perror_msg_and_die("PIO_UNIMAP");
137 }
138}
139
140static void loadnewfont(int fd)
141{
142 int unit;
143 char inbuf[32768]; /* primitive */
144 unsigned int inputlth, offset;
145
146 /*
147 * We used to look at the length of the input file
148 * with stat(); now that we accept compressed files,
149 * just read the entire file.
150 */
151 inputlth = fread(inbuf, 1, sizeof(inbuf), stdin);
152 if (ferror(stdin))
153 perror_msg_and_die("Error reading input font");
154 /* use malloc/realloc in case of giant files;
155 maybe these do not occur: 16kB for the font,
156 and 16kB for the map leaves 32 unicode values
157 for each font position */
158 if (!feof(stdin))
159 perror_msg_and_die("Font too large");
160
161 /* test for psf first */
162 {
163 struct psf_header psfhdr;
164 int fontsize;
165 int hastable;
166 unsigned int head0, head;
167
168 if (inputlth < sizeof(struct psf_header))
169 goto no_psf;
170
171 psfhdr = *(struct psf_header *) &inbuf[0];
172
173 if (!PSF_MAGIC_OK(psfhdr))
174 goto no_psf;
175
176 if (psfhdr.mode > PSF_MAXMODE)
177 error_msg_and_die("Unsupported psf file mode");
178 fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256);
179#if !defined( PIO_FONTX ) || defined( __sparc__ )
180 if (fontsize != 256)
181 error_msg_and_die("Only fontsize 256 supported");
182#endif
183 hastable = (psfhdr.mode & PSF_MODEHASTAB);
184 unit = psfhdr.charsize;
185 head0 = sizeof(struct psf_header);
186
187 head = head0 + fontsize * unit;
188 if (head > inputlth || (!hastable && head != inputlth))
189 error_msg_and_die("Input file: bad length");
190 do_loadfont(fd, inbuf + head0, unit, fontsize);
191 if (hastable)
192 do_loadtable(fd, inbuf + head, inputlth - head, fontsize);
193 return;
194 }
195 no_psf:
196
197 /* file with three code pages? */
198 if (inputlth == 9780) {
199 offset = 40;
200 unit = 16;
201 } else {
202 /* bare font */
203 if (inputlth & 0377)
204 error_msg_and_die("Bad input file size");
205 offset = 0;
206 unit = inputlth / 256;
207 }
208 do_loadfont(fd, inbuf + offset, unit, 256);
209}
diff --git a/loadkmap.c b/loadkmap.c
deleted file mode 100644
index 4f217d630..000000000
--- a/loadkmap.c
+++ /dev/null
@@ -1,89 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini loadkmap implementation for busybox
4 *
5 * Copyright (C) 1998 Enrique Zanardi <ezanardi@ull.es>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <errno.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <sys/ioctl.h>
30#include "busybox.h"
31
32#define BINARY_KEYMAP_MAGIC "bkeymap"
33
34/* From <linux/kd.h> */
35struct kbentry {
36 unsigned char kb_table;
37 unsigned char kb_index;
38 unsigned short kb_value;
39};
40static const int KDSKBENT = 0x4B47; /* sets one entry in translation table */
41
42/* From <linux/keyboard.h> */
43static const int NR_KEYS = 128;
44static const int MAX_NR_KEYMAPS = 256;
45
46int loadkmap_main(int argc, char **argv)
47{
48 struct kbentry ke;
49 u_short *ibuff;
50 int i, j, fd, readsz, pos, ibuffsz = NR_KEYS * sizeof(u_short);
51 char flags[MAX_NR_KEYMAPS], buff[7];
52
53 if (argc != 1)
54 show_usage();
55
56 fd = open(CURRENT_VC, O_RDWR);
57 if (fd < 0)
58 perror_msg_and_die("Error opening " CURRENT_VC);
59
60 read(0, buff, 7);
61 if (0 != strncmp(buff, BINARY_KEYMAP_MAGIC, 7))
62 error_msg_and_die("This is not a valid binary keymap.");
63
64 if (MAX_NR_KEYMAPS != read(0, flags, MAX_NR_KEYMAPS))
65 perror_msg_and_die("Error reading keymap flags");
66
67 ibuff = (u_short *) xmalloc(ibuffsz);
68
69 for (i = 0; i < MAX_NR_KEYMAPS; i++) {
70 if (flags[i] == 1) {
71 pos = 0;
72 while (pos < ibuffsz) {
73 if ((readsz = read(0, (char *) ibuff + pos, ibuffsz - pos)) < 0)
74 perror_msg_and_die("Error reading keymap");
75 pos += readsz;
76 }
77 for (j = 0; j < NR_KEYS; j++) {
78 ke.kb_index = j;
79 ke.kb_table = i;
80 ke.kb_value = ibuff[j];
81 ioctl(fd, KDSKBENT, &ke);
82 }
83 }
84 }
85 /* Don't bother to close files. Exit does that
86 * automagically, so we can save a few bytes */
87 /* close(fd); */
88 return EXIT_SUCCESS;
89}
diff --git a/logger.c b/logger.c
deleted file mode 100644
index 9f730915f..000000000
--- a/logger.c
+++ /dev/null
@@ -1,200 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini logger implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <stdio.h>
25#include <unistd.h>
26#include <sys/types.h>
27#include <fcntl.h>
28#include <ctype.h>
29#include <string.h>
30#include <stdlib.h>
31
32#include "busybox.h"
33#if !defined BB_SYSLOGD
34
35#define SYSLOG_NAMES
36#include <sys/syslog.h>
37
38#else
39#include <sys/syslog.h>
40# ifndef __dietlibc__
41 /* We have to do this since the header file defines static
42 * structures. Argh.... bad libc, bad, bad...
43 */
44 typedef struct _code {
45 char *c_name;
46 int c_val;
47 } CODE;
48 extern CODE prioritynames[];
49 extern CODE facilitynames[];
50# endif
51#endif
52
53/* Decode a symbolic name to a numeric value
54 * this function is based on code
55 * Copyright (c) 1983, 1993
56 * The Regents of the University of California. All rights reserved.
57 *
58 * Original copyright notice is retained at the end of this file.
59 */
60static int decode(char *name, CODE * codetab)
61{
62 CODE *c;
63
64 if (isdigit(*name))
65 return (atoi(name));
66 for (c = codetab; c->c_name; c++) {
67 if (!strcasecmp(name, c->c_name)) {
68 return (c->c_val);
69 }
70 }
71
72 return (-1);
73}
74
75/* Decode a symbolic name to a numeric value
76 * this function is based on code
77 * Copyright (c) 1983, 1993
78 * The Regents of the University of California. All rights reserved.
79 *
80 * Original copyright notice is retained at the end of this file.
81 */
82static int pencode(char *s)
83{
84 char *save;
85 int lev, fac = LOG_USER;
86
87 for (save = s; *s && *s != '.'; ++s);
88 if (*s) {
89 *s = '\0';
90 fac = decode(save, facilitynames);
91 if (fac < 0)
92 error_msg_and_die("unknown facility name: %s", save);
93 *s++ = '.';
94 } else {
95 s = save;
96 }
97 lev = decode(s, prioritynames);
98 if (lev < 0)
99 error_msg_and_die("unknown priority name: %s", save);
100 return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
101}
102
103
104extern int logger_main(int argc, char **argv)
105{
106 int pri = LOG_USER | LOG_NOTICE;
107 int option = 0;
108 int c, i, len, opt;
109 char *message=NULL, buf[1024], name[128];
110
111 /* Fill out the name string early (may be overwritten later) */
112 my_getpwuid(name, geteuid());
113
114 /* Parse any options */
115 while ((opt = getopt(argc, argv, "p:st:")) > 0) {
116 switch (opt) {
117 case 's':
118 option |= LOG_PERROR;
119 break;
120 case 'p':
121 pri = pencode(optarg);
122 break;
123 case 't':
124 strncpy(name, optarg, sizeof(name));
125 break;
126 default:
127 show_usage();
128 }
129 }
130
131 openlog(name, option, (pri | LOG_FACMASK));
132 if (optind == argc) {
133 do {
134 /* read from stdin */
135 i = 0;
136 while ((c = getc(stdin)) != EOF && c != '\n' &&
137 i < (sizeof(buf)-1)) {
138 buf[i++] = c;
139 }
140 if (i > 0) {
141 buf[i++] = '\0';
142 syslog(pri, "%s", buf);
143 }
144 } while (c != EOF);
145 } else {
146 len = 1; /* for the '\0' */
147 message=xcalloc(1, 1);
148 for (i = optind; i < argc; i++) {
149 len += strlen(argv[i]);
150 len += 1; /* for the space between the args */
151 message = xrealloc(message, len);
152 strcat(message, argv[i]);
153 strcat(message, " ");
154 }
155 message[strlen(message)-1] = '\0';
156 syslog(pri, "%s", message);
157 }
158
159 closelog();
160 return EXIT_SUCCESS;
161}
162
163
164/*-
165 * Copyright (c) 1983, 1993
166 * The Regents of the University of California. All rights reserved.
167 *
168 * This is the original license statement for the decode and pencode functions.
169 *
170 * Redistribution and use in source and binary forms, with or without
171 * modification, are permitted provided that the following conditions
172 * are met:
173 * 1. Redistributions of source code must retain the above copyright
174 * notice, this list of conditions and the following disclaimer.
175 * 2. Redistributions in binary form must reproduce the above copyright
176 * notice, this list of conditions and the following disclaimer in the
177 * documentation and/or other materials provided with the distribution.
178 *
179 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
180 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
181 *
182 * 4. Neither the name of the University nor the names of its contributors
183 * may be used to endorse or promote products derived from this software
184 * without specific prior written permission.
185 *
186 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
187 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
189 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
190 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
192 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
193 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
194 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
195 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
196 * SUCH DAMAGE.
197 */
198
199
200
diff --git a/logname.c b/logname.c
deleted file mode 100644
index 0924b2471..000000000
--- a/logname.c
+++ /dev/null
@@ -1,41 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini logname implementation for busybox
4 *
5 * Copyright (C) 2000 Edward Betts <edward@debian.org>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include "busybox.h"
27
28extern int logname_main(int argc, char **argv)
29{
30 char user[9];
31
32 if (argc > 1)
33 show_usage();
34
35 my_getpwuid(user, geteuid());
36 if (*user) {
37 puts(user);
38 return EXIT_SUCCESS;
39 }
40 error_msg_and_die("no login name");
41}
diff --git a/logread.c b/logread.c
deleted file mode 100644
index d3349625c..000000000
--- a/logread.c
+++ /dev/null
@@ -1,144 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * circular buffer syslog implementation for busybox
4 *
5 * Copyright (C) 2000 by Gennady Feldman <gfeldman@cachier.com>
6 *
7 * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 * 02111-1307 USA
23 *
24 */
25
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/ipc.h>
31#include <sys/types.h>
32#include <sys/sem.h>
33#include <sys/shm.h>
34#include <signal.h>
35#include <setjmp.h>
36#include "busybox.h"
37
38#if __GNU_LIBRARY__ < 5
39#error Sorry. Looks like you are using libc5.
40#error libc5 shm support isnt good enough.
41#error Please disable BB_FEATURE_IPC_SYSLOG
42#endif
43
44
45static const long KEY_ID = 0x414e4547; /*"GENA"*/
46
47static struct shbuf_ds {
48 int size; // size of data written
49 int head; // start of message list
50 int tail; // end of message list
51 char data[1]; // data/messages
52} *buf = NULL; // shared memory pointer
53
54
55// Semaphore operation structures
56static struct sembuf SMrup[1] = {{0, -1, IPC_NOWAIT | SEM_UNDO}}; // set SMrup
57static struct sembuf SMrdn[2] = {{1, 0}, {0, +1, SEM_UNDO}}; // set SMrdn
58
59static int log_shmid = -1; // ipc shared memory id
60static int log_semid = -1; // ipc semaphore id
61static jmp_buf jmp_env;
62
63static void error_exit(const char *str);
64static void interrupted(int sig);
65
66/*
67 * sem_up - up()'s a semaphore.
68 */
69static inline void sem_up(int semid)
70{
71 if ( semop(semid, SMrup, 1) == -1 )
72 error_exit("semop[SMrup]");
73}
74
75/*
76 * sem_down - down()'s a semaphore
77 */
78static inline void sem_down(int semid)
79{
80 if ( semop(semid, SMrdn, 2) == -1 )
81 error_exit("semop[SMrdn]");
82}
83
84extern int logread_main(int argc, char **argv)
85{
86 int i;
87
88 /* no options, no getopt */
89 if (argc > 1)
90 show_usage();
91
92 // handle intrrupt signal
93 if (setjmp(jmp_env)) goto output_end;
94
95 // attempt to redefine ^C signal
96 signal(SIGINT, interrupted);
97
98 if ( (log_shmid = shmget(KEY_ID, 0, 0)) == -1)
99 error_exit("Can't find circular buffer");
100
101 // Attach shared memory to our char*
102 if ( (buf = shmat(log_shmid, NULL, SHM_RDONLY)) == NULL)
103 error_exit("Can't get access to circular buffer from syslogd");
104
105 if ( (log_semid = semget(KEY_ID, 0, 0)) == -1)
106 error_exit("Can't get access to semaphone(s) for circular buffer from syslogd");
107
108 sem_down(log_semid);
109 // Read Memory
110 i=buf->head;
111
112 //printf("head: %i tail: %i size: %i\n",buf->head,buf->tail,buf->size);
113 if (buf->head == buf->tail) {
114 printf("<empty syslog>\n");
115 }
116
117 while ( i != buf->tail) {
118 printf("%s", buf->data+i);
119 i+= strlen(buf->data+i) + 1;
120 if (i >= buf->size )
121 i=0;
122 }
123 sem_up(log_semid);
124
125output_end:
126 if (log_shmid != -1)
127 shmdt(buf);
128
129 return EXIT_SUCCESS;
130}
131
132static void interrupted(int sig){
133 signal(SIGINT, SIG_IGN);
134 longjmp(jmp_env, 1);
135}
136
137static void error_exit(const char *str){
138 perror(str);
139 //release all acquired resources
140 if (log_shmid != -1)
141 shmdt(buf);
142
143 exit(1);
144}
diff --git a/ls.c b/ls.c
deleted file mode 100644
index 8d0282dfe..000000000
--- a/ls.c
+++ /dev/null
@@ -1,937 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * tiny-ls.c version 0.1.0: A minimalist 'ls'
4 * Copyright (C) 1996 Brian Candler <B.Candler@pobox.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/*
22 * To achieve a small memory footprint, this version of 'ls' doesn't do any
23 * file sorting, and only has the most essential command line switches
24 * (i.e., the ones I couldn't live without :-) All features which involve
25 * linking in substantial chunks of libc can be disabled.
26 *
27 * Although I don't really want to add new features to this program to
28 * keep it small, I *am* interested to receive bug fixes and ways to make
29 * it more portable.
30 *
31 * KNOWN BUGS:
32 * 1. ls -l of a directory doesn't give "total <blocks>" header
33 * 2. ls of a symlink to a directory doesn't list directory contents
34 * 3. hidden files can make column width too large
35 *
36 * NON-OPTIMAL BEHAVIOUR:
37 * 1. autowidth reads directories twice
38 * 2. if you do a short directory listing without filetype characters
39 * appended, there's no need to stat each one
40 * PORTABILITY:
41 * 1. requires lstat (BSD) - how do you do it without?
42 */
43
44enum {
45 TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */
46 COLUMN_WIDTH = 14, /* default if AUTOWIDTH not defined */
47 COLUMN_GAP = 2, /* includes the file type char */
48};
49
50
51/************************************************************************/
52
53#include <sys/types.h>
54#include <sys/stat.h>
55#include <stdio.h>
56#include <unistd.h>
57#include <dirent.h>
58#include <errno.h>
59#include <stdio.h>
60#include <string.h>
61#include <stdlib.h>
62#include <fcntl.h>
63#include <signal.h>
64#include <termios.h>
65#include <sys/ioctl.h>
66#include "busybox.h"
67
68#ifdef BB_FEATURE_LS_TIMESTAMPS
69#include <time.h>
70#endif
71
72#ifndef MAJOR
73#define MAJOR(dev) (((dev)>>8)&0xff)
74#define MINOR(dev) ((dev)&0xff)
75#endif
76
77/* what is the overall style of the listing */
78enum {
79STYLE_AUTO = 0,
80STYLE_LONG = 1, /* one record per line, extended info */
81STYLE_SINGLE = 2, /* one record per line */
82STYLE_COLUMNS = 3 /* fill columns */
83};
84
85/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */
86/* what file information will be listed */
87#define LIST_INO (1<<0)
88#define LIST_BLOCKS (1<<1)
89#define LIST_MODEBITS (1<<2)
90#define LIST_NLINKS (1<<3)
91#define LIST_ID_NAME (1<<4)
92#define LIST_ID_NUMERIC (1<<5)
93#define LIST_SIZE (1<<6)
94#define LIST_DEV (1<<7)
95#define LIST_DATE_TIME (1<<8)
96#define LIST_FULLTIME (1<<9)
97#define LIST_FILENAME (1<<10)
98#define LIST_SYMLINK (1<<11)
99#define LIST_FILETYPE (1<<12)
100#define LIST_EXEC (1<<13)
101
102/* what files will be displayed */
103#define DISP_NORMAL (0) /* show normal filenames */
104#define DISP_DIRNAME (1<<0) /* 2 or more items? label directories */
105#define DISP_HIDDEN (1<<1) /* show filenames starting with . */
106#define DISP_DOT (1<<2) /* show . and .. */
107#define DISP_NOLIST (1<<3) /* show directory as itself, not contents */
108#define DISP_RECURSIVE (1<<4) /* show directory and everything below it */
109#define DISP_ROWS (1<<5) /* print across rows */
110
111#ifdef BB_FEATURE_LS_SORTFILES
112/* how will the files be sorted */
113static const int SORT_FORWARD = 0; /* sort in reverse order */
114static const int SORT_REVERSE = 1; /* sort in reverse order */
115static const int SORT_NAME = 2; /* sort by file name */
116static const int SORT_SIZE = 3; /* sort by file size */
117static const int SORT_ATIME = 4; /* sort by last access time */
118static const int SORT_CTIME = 5; /* sort by last change time */
119static const int SORT_MTIME = 6; /* sort by last modification time */
120static const int SORT_VERSION = 7; /* sort by version */
121static const int SORT_EXT = 8; /* sort by file name extension */
122static const int SORT_DIR = 9; /* sort by file or directory */
123#endif
124
125#ifdef BB_FEATURE_LS_TIMESTAMPS
126/* which of the three times will be used */
127static const int TIME_MOD = 0;
128static const int TIME_CHANGE = 1;
129static const int TIME_ACCESS = 2;
130#endif
131
132#define LIST_SHORT (LIST_FILENAME)
133#define LIST_ISHORT (LIST_INO | LIST_FILENAME)
134#define LIST_LONG (LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | \
135 LIST_SIZE | LIST_DATE_TIME | LIST_FILENAME | \
136 LIST_SYMLINK)
137#define LIST_ILONG (LIST_INO | LIST_LONG)
138
139static const int SPLIT_DIR = 0;
140static const int SPLIT_FILE = 1;
141static const int SPLIT_SUBDIR = 2;
142
143#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
144#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
145#ifdef BB_FEATURE_LS_FILETYPES
146#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
147#endif
148
149/*
150 * a directory entry and its stat info are stored here
151 */
152struct dnode { /* the basic node */
153 char *name; /* the dir entry name */
154 char *fullname; /* the dir entry name */
155 struct stat dstat; /* the file stat info */
156 struct dnode *next; /* point at the next node */
157};
158typedef struct dnode dnode_t;
159
160static struct dnode **list_dir(char *);
161static struct dnode **dnalloc(int);
162static int list_single(struct dnode *);
163
164static unsigned int disp_opts;
165static unsigned int style_fmt;
166static unsigned int list_fmt;
167#ifdef BB_FEATURE_LS_SORTFILES
168static unsigned int sort_opts;
169static unsigned int sort_order;
170#endif
171#ifdef BB_FEATURE_LS_TIMESTAMPS
172static unsigned int time_fmt;
173#endif
174#ifdef BB_FEATURE_LS_FOLLOWLINKS
175static unsigned int follow_links=FALSE;
176#endif
177
178static unsigned short column = 0;
179#ifdef BB_FEATURE_AUTOWIDTH
180static unsigned short terminal_width = TERMINAL_WIDTH;
181static unsigned short column_width = COLUMN_WIDTH;
182static unsigned short tabstops = COLUMN_GAP;
183#else
184static unsigned short column_width = COLUMN_WIDTH;
185#endif
186
187static int status = EXIT_SUCCESS;
188
189#ifdef BB_FEATURE_HUMAN_READABLE
190static unsigned long ls_disp_hr = 0;
191#endif
192
193static int my_stat(struct dnode *cur)
194{
195#ifdef BB_FEATURE_LS_FOLLOWLINKS
196 if (follow_links == TRUE) {
197 if (stat(cur->fullname, &cur->dstat)) {
198 perror_msg("%s", cur->fullname);
199 status = EXIT_FAILURE;
200 free(cur->fullname);
201 free(cur);
202 return -1;
203 }
204 } else
205#endif
206 if (lstat(cur->fullname, &cur->dstat)) {
207 perror_msg("%s", cur->fullname);
208 status = EXIT_FAILURE;
209 free(cur->fullname);
210 free(cur);
211 return -1;
212 }
213 return 0;
214}
215
216static void newline(void)
217{
218 if (column > 0) {
219 putchar('\n');
220 column = 0;
221 }
222}
223
224/*----------------------------------------------------------------------*/
225#ifdef BB_FEATURE_LS_FILETYPES
226static char append_char(mode_t mode)
227{
228 if ( !(list_fmt & LIST_FILETYPE))
229 return '\0';
230 if ((list_fmt & LIST_EXEC) && S_ISREG(mode)
231 && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*';
232 return APPCHAR(mode);
233}
234#endif
235
236/*----------------------------------------------------------------------*/
237static void nexttabstop( void )
238{
239 static short nexttab= 0;
240 int n=0;
241
242 if (column > 0) {
243 n= nexttab - column;
244 if (n < 1) n= 1;
245 while (n--) {
246 putchar(' ');
247 column++;
248 }
249 }
250 nexttab= column + column_width + COLUMN_GAP;
251}
252
253/*----------------------------------------------------------------------*/
254static int is_subdir(struct dnode *dn)
255{
256 return (S_ISDIR(dn->dstat.st_mode) && strcmp(dn->name, ".") != 0 &&
257 strcmp(dn->name, "..") != 0);
258}
259
260static int countdirs(struct dnode **dn, int nfiles)
261{
262 int i, dirs;
263
264 if (dn==NULL || nfiles < 1) return(0);
265 dirs= 0;
266 for (i=0; i<nfiles; i++) {
267 if (S_ISDIR(dn[i]->dstat.st_mode)) dirs++;
268 }
269 return(dirs);
270}
271
272static int countsubdirs(struct dnode **dn, int nfiles)
273{
274 int i, subdirs;
275
276 if (dn == NULL || nfiles < 1) return 0;
277 subdirs = 0;
278 for (i = 0; i < nfiles; i++)
279 if (is_subdir(dn[i]))
280 subdirs++;
281 return subdirs;
282}
283
284static int countfiles(struct dnode **dnp)
285{
286 int nfiles;
287 struct dnode *cur;
288
289 if (dnp == NULL) return(0);
290 nfiles= 0;
291 for (cur= dnp[0]; cur->next != NULL ; cur= cur->next) nfiles++;
292 nfiles++;
293 return(nfiles);
294}
295
296/* get memory to hold an array of pointers */
297static struct dnode **dnalloc(int num)
298{
299 struct dnode **p;
300
301 if (num < 1) return(NULL);
302
303 p= (struct dnode **)xcalloc((size_t)num, (size_t)(sizeof(struct dnode *)));
304 return(p);
305}
306
307#ifdef BB_FEATURE_LS_RECURSIVE
308static void dfree(struct dnode **dnp)
309{
310 struct dnode *cur, *next;
311
312 if(dnp == NULL) return;
313
314 cur=dnp[0];
315 while (cur != NULL) {
316 if (cur->fullname != NULL) free(cur->fullname); /* free the filename */
317 next= cur->next;
318 free(cur); /* free the dnode */
319 cur= next;
320 }
321 free(dnp); /* free the array holding the dnode pointers */
322}
323#endif
324
325static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
326{
327 int dncnt, i, d;
328 struct dnode **dnp;
329
330 if (dn==NULL || nfiles < 1) return(NULL);
331
332 /* count how many dirs and regular files there are */
333 if (which == SPLIT_SUBDIR)
334 dncnt = countsubdirs(dn, nfiles);
335 else {
336 dncnt= countdirs(dn, nfiles); /* assume we are looking for dirs */
337 if (which == SPLIT_FILE)
338 dncnt= nfiles - dncnt; /* looking for files */
339 }
340
341 /* allocate a file array and a dir array */
342 dnp= dnalloc(dncnt);
343
344 /* copy the entrys into the file or dir array */
345 for (d= i=0; i<nfiles; i++) {
346 if (which == SPLIT_DIR) {
347 if (S_ISDIR(dn[i]->dstat.st_mode)) {
348 dnp[d++]= dn[i];
349 } /* else skip the file */
350 } else if (which == SPLIT_SUBDIR) {
351 if (is_subdir(dn[i])) {
352 dnp[d++]= dn[i];
353 } /* else skip the file or dir */
354 } else {
355 if (!(S_ISDIR(dn[i]->dstat.st_mode))) {
356 dnp[d++]= dn[i];
357 } /* else skip the dir */
358 }
359 }
360 return(dnp);
361}
362
363/*----------------------------------------------------------------------*/
364#ifdef BB_FEATURE_LS_SORTFILES
365static int sortcmp(struct dnode *d1, struct dnode *d2)
366{
367 int cmp, dif;
368
369 cmp= 0;
370 if (sort_opts == SORT_SIZE) {
371 dif= (int)(d1->dstat.st_size - d2->dstat.st_size);
372 } else if (sort_opts == SORT_ATIME) {
373 dif= (int)(d1->dstat.st_atime - d2->dstat.st_atime);
374 } else if (sort_opts == SORT_CTIME) {
375 dif= (int)(d1->dstat.st_ctime - d2->dstat.st_ctime);
376 } else if (sort_opts == SORT_MTIME) {
377 dif= (int)(d1->dstat.st_mtime - d2->dstat.st_mtime);
378 } else if (sort_opts == SORT_DIR) {
379 dif= S_ISDIR(d1->dstat.st_mode) - S_ISDIR(d2->dstat.st_mode);
380 /* } else if (sort_opts == SORT_VERSION) { */
381 /* } else if (sort_opts == SORT_EXT) { */
382 } else { /* assume SORT_NAME */
383 dif= 0;
384 }
385
386 if (dif > 0) cmp= -1;
387 if (dif < 0) cmp= 1;
388 if (dif == 0) {
389 /* sort by name- may be a tie_breaker for time or size cmp */
390 dif= strcmp(d1->name, d2->name);
391 if (dif > 0) cmp= 1;
392 if (dif < 0) cmp= -1;
393 }
394
395 if (sort_order == SORT_REVERSE) {
396 cmp= -1 * cmp;
397 }
398 return(cmp);
399}
400
401/*----------------------------------------------------------------------*/
402static void shellsort(struct dnode **dn, int size)
403{
404 struct dnode *temp;
405 int gap, i, j;
406
407 /* shell short the array */
408 if(dn==NULL || size < 2) return;
409
410 for (gap= size/2; gap>0; gap /=2) {
411 for (i=gap; i<size; i++) {
412 for (j= i-gap; j>=0; j-=gap) {
413 if (sortcmp(dn[j], dn[j+gap]) <= 0)
414 break;
415 /* they are out of order, swap them */
416 temp= dn[j];
417 dn[j]= dn[j+gap];
418 dn[j+gap]= temp;
419 }
420 }
421 }
422}
423#endif
424
425/*----------------------------------------------------------------------*/
426static void showfiles(struct dnode **dn, int nfiles)
427{
428 int i, ncols, nrows, row, nc;
429#ifdef BB_FEATURE_AUTOWIDTH
430 int len;
431#endif
432
433 if(dn==NULL || nfiles < 1) return;
434
435#ifdef BB_FEATURE_AUTOWIDTH
436 /* find the longest file name- use that as the column width */
437 column_width= 0;
438 for (i=0; i<nfiles; i++) {
439 len= strlen(dn[i]->name) +
440 ((list_fmt & LIST_INO) ? 8 : 0) +
441 ((list_fmt & LIST_BLOCKS) ? 5 : 0)
442 ;
443 if (column_width < len)
444 column_width= len;
445 }
446 if (column_width >= 6)
447 ncols = (int)(terminal_width / (column_width + COLUMN_GAP));
448 else {
449 ncols = 1;
450 column_width = COLUMN_WIDTH;
451 }
452#else
453 ncols= TERMINAL_WIDTH;
454#endif
455 switch (style_fmt) {
456 case STYLE_LONG: /* one record per line, extended info */
457 case STYLE_SINGLE: /* one record per line */
458 ncols= 1;
459 break;
460 }
461
462 if (ncols > 1) {
463 nrows = nfiles / ncols;
464 } else {
465 nrows = nfiles;
466 ncols = 1;
467 }
468 if ((nrows * ncols) < nfiles) nrows++; /* round up fractionals */
469
470 if (nrows > nfiles) nrows= nfiles;
471 for (row=0; row<nrows; row++) {
472 for (nc=0; nc<ncols; nc++) {
473 /* reach into the array based on the column and row */
474 i= (nc * nrows) + row; /* assume display by column */
475 if (disp_opts & DISP_ROWS)
476 i= (row * ncols) + nc; /* display across row */
477 if (i < nfiles) {
478 nexttabstop();
479 list_single(dn[i]);
480 }
481 }
482 newline();
483 }
484}
485
486/*----------------------------------------------------------------------*/
487static void showdirs(struct dnode **dn, int ndirs)
488{
489 int i, nfiles;
490 struct dnode **subdnp;
491#ifdef BB_FEATURE_LS_RECURSIVE
492 int dndirs;
493 struct dnode **dnd;
494#endif
495
496 if (dn==NULL || ndirs < 1) return;
497
498 for (i=0; i<ndirs; i++) {
499 if (disp_opts & (DISP_DIRNAME | DISP_RECURSIVE)) {
500 printf("\n%s:\n", dn[i]->fullname);
501 }
502 subdnp= list_dir(dn[i]->fullname);
503 nfiles= countfiles(subdnp);
504 if (nfiles > 0) {
505 /* list all files at this level */
506#ifdef BB_FEATURE_LS_SORTFILES
507 shellsort(subdnp, nfiles);
508#endif
509 showfiles(subdnp, nfiles);
510#ifdef BB_FEATURE_LS_RECURSIVE
511 if (disp_opts & DISP_RECURSIVE) {
512 /* recursive- list the sub-dirs */
513 dnd= splitdnarray(subdnp, nfiles, SPLIT_SUBDIR);
514 dndirs= countsubdirs(subdnp, nfiles);
515 if (dndirs > 0) {
516#ifdef BB_FEATURE_LS_SORTFILES
517 shellsort(dnd, dndirs);
518#endif
519 showdirs(dnd, dndirs);
520 free(dnd); /* free the array of dnode pointers to the dirs */
521 }
522 }
523 dfree(subdnp); /* free the dnodes and the fullname mem */
524#endif
525 }
526 }
527}
528
529/*----------------------------------------------------------------------*/
530static struct dnode **list_dir(char *path)
531{
532 struct dnode *dn, *cur, **dnp;
533 struct dirent *entry;
534 DIR *dir;
535 int i, nfiles;
536
537 if (path==NULL) return(NULL);
538
539 dn= NULL;
540 nfiles= 0;
541 dir = opendir(path);
542 if (dir == NULL) {
543 perror_msg("%s", path);
544 status = EXIT_FAILURE;
545 return(NULL); /* could not open the dir */
546 }
547 while ((entry = readdir(dir)) != NULL) {
548 /* are we going to list the file- it may be . or .. or a hidden file */
549 if ((strcmp(entry->d_name, ".")==0) && !(disp_opts & DISP_DOT))
550 continue;
551 if ((strcmp(entry->d_name, "..")==0) && !(disp_opts & DISP_DOT))
552 continue;
553 if ((entry->d_name[0] == '.') && !(disp_opts & DISP_HIDDEN))
554 continue;
555 cur= (struct dnode *)xmalloc(sizeof(struct dnode));
556 cur->fullname = concat_path_file(path, entry->d_name);
557 cur->name = cur->fullname +
558 (strlen(cur->fullname) - strlen(entry->d_name));
559 if (my_stat(cur))
560 continue;
561 cur->next= dn;
562 dn= cur;
563 nfiles++;
564 }
565 closedir(dir);
566
567 /* now that we know how many files there are
568 ** allocate memory for an array to hold dnode pointers
569 */
570 if (nfiles < 1) return(NULL);
571 dnp= dnalloc(nfiles);
572 for (i=0, cur=dn; i<nfiles; i++) {
573 dnp[i]= cur; /* save pointer to node in array */
574 cur= cur->next;
575 }
576
577 return(dnp);
578}
579
580/*----------------------------------------------------------------------*/
581static int list_single(struct dnode *dn)
582{
583 int i;
584 char scratch[BUFSIZ + 1];
585#ifdef BB_FEATURE_LS_TIMESTAMPS
586 char *filetime;
587 time_t ttime, age;
588#endif
589#if defined (BB_FEATURE_LS_FILETYPES)
590 struct stat info;
591#endif
592#ifdef BB_FEATURE_LS_FILETYPES
593 char append;
594#endif
595
596 if (dn==NULL || dn->fullname==NULL) return(0);
597
598#ifdef BB_FEATURE_LS_TIMESTAMPS
599 ttime= dn->dstat.st_mtime; /* the default time */
600 if (time_fmt & TIME_ACCESS) ttime= dn->dstat.st_atime;
601 if (time_fmt & TIME_CHANGE) ttime= dn->dstat.st_ctime;
602 filetime= ctime(&ttime);
603#endif
604#ifdef BB_FEATURE_LS_FILETYPES
605 append = append_char(dn->dstat.st_mode);
606#endif
607
608 for (i=0; i<=31; i++) {
609 switch (list_fmt & (1<<i)) {
610 case LIST_INO:
611 printf("%7ld ", (long int)dn->dstat.st_ino);
612 column += 8;
613 break;
614 case LIST_BLOCKS:
615#ifdef BB_FEATURE_HUMAN_READABLE
616 fprintf(stdout, "%6s ", make_human_readable_str(dn->dstat.st_blocks>>1,
617 KILOBYTE, (ls_disp_hr==TRUE)? 0: KILOBYTE));
618#else
619#if _FILE_OFFSET_BITS == 64
620 printf("%4lld ", dn->dstat.st_blocks>>1);
621#else
622 printf("%4ld ", dn->dstat.st_blocks>>1);
623#endif
624#endif
625 column += 5;
626 break;
627 case LIST_MODEBITS:
628 printf("%-10s ", (char *)mode_string(dn->dstat.st_mode));
629 column += 10;
630 break;
631 case LIST_NLINKS:
632 printf("%4ld ", (long)dn->dstat.st_nlink);
633 column += 10;
634 break;
635 case LIST_ID_NAME:
636#ifdef BB_FEATURE_LS_USERNAME
637 my_getpwuid(scratch, dn->dstat.st_uid);
638 printf("%-8.8s ", scratch);
639 my_getgrgid(scratch, dn->dstat.st_gid);
640 printf("%-8.8s", scratch);
641 column += 17;
642 break;
643#endif
644 case LIST_ID_NUMERIC:
645 printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid);
646 column += 17;
647 break;
648 case LIST_SIZE:
649 case LIST_DEV:
650 if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
651 printf("%4d, %3d ", (int)MAJOR(dn->dstat.st_rdev), (int)MINOR(dn->dstat.st_rdev));
652 } else {
653#ifdef BB_FEATURE_HUMAN_READABLE
654 if (ls_disp_hr==TRUE) {
655 fprintf(stdout, "%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0));
656 } else
657#endif
658 {
659#if _FILE_OFFSET_BITS == 64
660 printf("%9lld ", (long long)dn->dstat.st_size);
661#else
662 printf("%9ld ", dn->dstat.st_size);
663#endif
664 }
665 }
666 column += 10;
667 break;
668#ifdef BB_FEATURE_LS_TIMESTAMPS
669 case LIST_FULLTIME:
670 case LIST_DATE_TIME:
671 if (list_fmt & LIST_FULLTIME) {
672 printf("%24.24s ", filetime);
673 column += 25;
674 break;
675 }
676 age = time(NULL) - ttime;
677 printf("%6.6s ", filetime+4);
678 if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
679 /* hh:mm if less than 6 months old */
680 printf("%5.5s ", filetime+11);
681 } else {
682 printf(" %4.4s ", filetime+20);
683 }
684 column += 13;
685 break;
686#endif
687 case LIST_FILENAME:
688 printf("%s", dn->name);
689 column += strlen(dn->name);
690 break;
691 case LIST_SYMLINK:
692 if (S_ISLNK(dn->dstat.st_mode)) {
693 char *lpath = xreadlink(dn->fullname);
694 if (lpath) {
695 printf(" -> %s", lpath);
696#ifdef BB_FEATURE_LS_FILETYPES
697 if (!stat(dn->fullname, &info)) {
698 append = append_char(info.st_mode);
699 }
700#endif
701 column += strlen(lpath) + 4;
702 free(lpath);
703 }
704 }
705 break;
706#ifdef BB_FEATURE_LS_FILETYPES
707 case LIST_FILETYPE:
708 if (append != '\0') {
709 printf("%1c", append);
710 column++;
711 }
712 break;
713#endif
714 }
715 }
716
717 return(0);
718}
719
720/*----------------------------------------------------------------------*/
721extern int ls_main(int argc, char **argv)
722{
723 struct dnode **dnf, **dnd;
724 int dnfiles, dndirs;
725 struct dnode *dn, *cur, **dnp;
726 int i, nfiles;
727 int opt;
728 int oi, ac;
729 char **av;
730#ifdef BB_FEATURE_AUTOWIDTH
731 struct winsize win = { 0, 0, 0, 0 };
732#endif
733
734 disp_opts= DISP_NORMAL;
735 style_fmt= STYLE_AUTO;
736 list_fmt= LIST_SHORT;
737#ifdef BB_FEATURE_LS_SORTFILES
738 sort_opts= SORT_NAME;
739 sort_order= SORT_FORWARD;
740#endif
741#ifdef BB_FEATURE_LS_TIMESTAMPS
742 time_fmt= TIME_MOD;
743#endif
744#ifdef BB_FEATURE_AUTOWIDTH
745 ioctl(fileno(stdout), TIOCGWINSZ, &win);
746 if (win.ws_row > 4)
747 column_width = win.ws_row - 2;
748 if (win.ws_col > 0)
749 terminal_width = win.ws_col - 1;
750#endif
751 nfiles=0;
752
753 /* process options */
754 while ((opt = getopt(argc, argv, "1AaCdgilnsx"
755#ifdef BB_FEATURE_AUTOWIDTH
756"T:w:"
757#endif
758#ifdef BB_FEATURE_LS_FILETYPES
759"Fp"
760#endif
761#ifdef BB_FEATURE_LS_RECURSIVE
762"R"
763#endif
764#ifdef BB_FEATURE_LS_SORTFILES
765"rSvX"
766#endif
767#ifdef BB_FEATURE_LS_TIMESTAMPS
768"cetu"
769#endif
770#ifdef BB_FEATURE_LS_FOLLOWLINKS
771"L"
772#endif
773#ifdef BB_FEATURE_HUMAN_READABLE
774"h"
775#endif
776"k")) > 0) {
777 switch (opt) {
778 case '1': style_fmt = STYLE_SINGLE; break;
779 case 'A': disp_opts |= DISP_HIDDEN; break;
780 case 'a': disp_opts |= DISP_HIDDEN | DISP_DOT; break;
781 case 'C': style_fmt = STYLE_COLUMNS; break;
782 case 'd': disp_opts |= DISP_NOLIST; break;
783 case 'g': /* ignore -- for ftp servers */ break;
784 case 'i': list_fmt |= LIST_INO; break;
785 case 'l':
786 style_fmt = STYLE_LONG;
787 list_fmt |= LIST_LONG;
788#ifdef BB_FEATURE_HUMAN_READABLE
789 ls_disp_hr = FALSE;
790#endif
791 break;
792 case 'n': list_fmt |= LIST_ID_NUMERIC; break;
793 case 's': list_fmt |= LIST_BLOCKS; break;
794 case 'x': disp_opts = DISP_ROWS; break;
795#ifdef BB_FEATURE_LS_FILETYPES
796 case 'F': list_fmt |= LIST_FILETYPE | LIST_EXEC; break;
797 case 'p': list_fmt |= LIST_FILETYPE; break;
798#endif
799#ifdef BB_FEATURE_LS_RECURSIVE
800 case 'R': disp_opts |= DISP_RECURSIVE; break;
801#endif
802#ifdef BB_FEATURE_LS_SORTFILES
803 case 'r': sort_order |= SORT_REVERSE; break;
804 case 'S': sort_opts= SORT_SIZE; break;
805 case 'v': sort_opts= SORT_VERSION; break;
806 case 'X': sort_opts= SORT_EXT; break;
807#endif
808#ifdef BB_FEATURE_LS_TIMESTAMPS
809 case 'e': list_fmt |= LIST_FULLTIME; break;
810 case 'c':
811 time_fmt = TIME_CHANGE;
812#ifdef BB_FEATURE_LS_SORTFILES
813 sort_opts= SORT_CTIME;
814#endif
815 break;
816 case 'u':
817 time_fmt = TIME_ACCESS;
818#ifdef BB_FEATURE_LS_SORTFILES
819 sort_opts= SORT_ATIME;
820#endif
821 break;
822 case 't':
823#ifdef BB_FEATURE_LS_SORTFILES
824 sort_opts= SORT_MTIME;
825#endif
826 break;
827#endif
828#ifdef BB_FEATURE_LS_FOLLOWLINKS
829 case 'L': follow_links= TRUE; break;
830#endif
831#ifdef BB_FEATURE_AUTOWIDTH
832 case 'T': tabstops= atoi(optarg); break;
833 case 'w': terminal_width= atoi(optarg); break;
834#endif
835#ifdef BB_FEATURE_HUMAN_READABLE
836 case 'h': ls_disp_hr = TRUE; break;
837#endif
838 case 'k': break;
839 default:
840 goto print_usage_message;
841 }
842 }
843
844 /* sort out which command line options take precedence */
845#ifdef BB_FEATURE_LS_RECURSIVE
846 if (disp_opts & DISP_NOLIST)
847 disp_opts &= ~DISP_RECURSIVE; /* no recurse if listing only dir */
848#endif
849#if defined (BB_FEATURE_LS_TIMESTAMPS) && defined (BB_FEATURE_LS_SORTFILES)
850 if (time_fmt & TIME_CHANGE) sort_opts= SORT_CTIME;
851 if (time_fmt & TIME_ACCESS) sort_opts= SORT_ATIME;
852#endif
853 if (style_fmt != STYLE_LONG)
854 list_fmt &= ~LIST_ID_NUMERIC; /* numeric uid only for long list */
855#ifdef BB_FEATURE_LS_USERNAME
856 if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC))
857 list_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */
858#endif
859
860 /* choose a display format */
861 if (style_fmt == STYLE_AUTO)
862 style_fmt = isatty(fileno(stdout)) ? STYLE_COLUMNS : STYLE_SINGLE;
863
864 /*
865 * when there are no cmd line args we have to supply a default "." arg.
866 * we will create a second argv array, "av" that will hold either
867 * our created "." arg, or the real cmd line args. The av array
868 * just holds the pointers- we don't move the date the pointers
869 * point to.
870 */
871 ac= argc - optind; /* how many cmd line args are left */
872 if (ac < 1) {
873 av= (char **)xcalloc((size_t)1, (size_t)(sizeof(char *)));
874 av[0]= xstrdup(".");
875 ac=1;
876 } else {
877 av= (char **)xcalloc((size_t)ac, (size_t)(sizeof(char *)));
878 for (oi=0 ; oi < ac; oi++) {
879 av[oi]= argv[optind++]; /* copy pointer to real cmd line arg */
880 }
881 }
882
883 /* now, everything is in the av array */
884 if (ac > 1)
885 disp_opts |= DISP_DIRNAME; /* 2 or more items? label directories */
886
887 /* stuff the command line file names into an dnode array */
888 dn=NULL;
889 for (oi=0 ; oi < ac; oi++) {
890 cur= (struct dnode *)xmalloc(sizeof(struct dnode));
891 cur->fullname= xstrdup(av[oi]);
892 cur->name= cur->fullname;
893 if (my_stat(cur))
894 continue;
895 cur->next= dn;
896 dn= cur;
897 nfiles++;
898 }
899
900 /* now that we know how many files there are
901 ** allocate memory for an array to hold dnode pointers
902 */
903 dnp= dnalloc(nfiles);
904 for (i=0, cur=dn; i<nfiles; i++) {
905 dnp[i]= cur; /* save pointer to node in array */
906 cur= cur->next;
907 }
908
909
910 if (disp_opts & DISP_NOLIST) {
911#ifdef BB_FEATURE_LS_SORTFILES
912 shellsort(dnp, nfiles);
913#endif
914 if (nfiles > 0) showfiles(dnp, nfiles);
915 } else {
916 dnd= splitdnarray(dnp, nfiles, SPLIT_DIR);
917 dnf= splitdnarray(dnp, nfiles, SPLIT_FILE);
918 dndirs= countdirs(dnp, nfiles);
919 dnfiles= nfiles - dndirs;
920 if (dnfiles > 0) {
921#ifdef BB_FEATURE_LS_SORTFILES
922 shellsort(dnf, dnfiles);
923#endif
924 showfiles(dnf, dnfiles);
925 }
926 if (dndirs > 0) {
927#ifdef BB_FEATURE_LS_SORTFILES
928 shellsort(dnd, dndirs);
929#endif
930 showdirs(dnd, dndirs);
931 }
932 }
933 return(status);
934
935 print_usage_message:
936 show_usage();
937}
diff --git a/lsmod.c b/lsmod.c
deleted file mode 100644
index 76ed2fdd8..000000000
--- a/lsmod.c
+++ /dev/null
@@ -1,166 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini lsmod implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
9 * Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
10 * (which lack the query_module() interface).
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 */
27
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31#include <stddef.h>
32#include <errno.h>
33#include <unistd.h>
34#include <dirent.h>
35#include <ctype.h>
36#include <assert.h>
37#include <getopt.h>
38#include <sys/utsname.h>
39#include <sys/file.h>
40#include "busybox.h"
41
42
43
44#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
45
46struct module_info
47{
48 unsigned long addr;
49 unsigned long size;
50 unsigned long flags;
51 long usecount;
52};
53
54
55int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
56
57/* Values for query_module's which. */
58static const int QM_MODULES = 1;
59static const int QM_DEPS = 2;
60static const int QM_REFS = 3;
61static const int QM_SYMBOLS = 4;
62static const int QM_INFO = 5;
63
64/* Bits of module.flags. */
65static const int NEW_MOD_RUNNING = 1;
66static const int NEW_MOD_DELETED = 2;
67static const int NEW_MOD_AUTOCLEAN = 4;
68static const int NEW_MOD_VISITED = 8;
69static const int NEW_MOD_USED_ONCE = 16;
70static const int NEW_MOD_INITIALIZING = 64;
71
72static int my_query_module(const char *name, int which, void **buf,
73 size_t *bufsize, size_t *ret)
74{
75 int my_ret;
76
77 my_ret = query_module(name, which, *buf, *bufsize, ret);
78
79 if (my_ret == -1 && errno == ENOSPC) {
80 *buf = xrealloc(*buf, *ret);
81 *bufsize = *ret;
82
83 my_ret = query_module(name, which, *buf, *bufsize, ret);
84 }
85
86 return my_ret;
87}
88
89extern int lsmod_main(int argc, char **argv)
90{
91 struct module_info info;
92 char *module_names, *mn, *deps, *dn;
93 size_t bufsize, depsize, nmod, count, i, j;
94
95 module_names = xmalloc(bufsize = 256);
96 if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize,
97 &nmod)) {
98 perror_msg_and_die("QM_MODULES");
99 }
100
101 deps = xmalloc(depsize = 256);
102 printf("Module Size Used by\n");
103 for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) {
104 if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) {
105 if (errno == ENOENT) {
106 /* The module was removed out from underneath us. */
107 continue;
108 }
109 /* else choke */
110 perror_msg_and_die("module %s: QM_INFO", mn);
111 }
112 if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) {
113 if (errno == ENOENT) {
114 /* The module was removed out from underneath us. */
115 continue;
116 }
117 perror_msg_and_die("module %s: QM_REFS", mn);
118 }
119 printf("%-20s%8lu%4ld ", mn, info.size, info.usecount);
120 if (info.flags & NEW_MOD_DELETED)
121 printf("(deleted)");
122 else if (info.flags & NEW_MOD_INITIALIZING)
123 printf("(initializing)");
124 else if (!(info.flags & NEW_MOD_RUNNING))
125 printf("(uninitialized)");
126 else {
127 if (info.flags & NEW_MOD_AUTOCLEAN)
128 printf("(autoclean) ");
129 if (!(info.flags & NEW_MOD_USED_ONCE))
130 printf("(unused)");
131 }
132 if (count) printf("[");
133 for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) {
134 printf("%s%s", dn, (j==count-1)? "":" ");
135 }
136 if (count) printf("] ");
137
138 printf("\n");
139 }
140
141
142 return( 0);
143}
144
145#else /*BB_FEATURE_OLD_MODULE_INTERFACE*/
146
147extern int lsmod_main(int argc, char **argv)
148{
149 int fd, i;
150 char line[128];
151
152 puts("Module Size Used by");
153 fflush(stdout);
154
155 if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) {
156 while ((i = read(fd, line, sizeof(line))) > 0) {
157 write(fileno(stdout), line, i);
158 }
159 close(fd);
160 return 0;
161 }
162 perror_msg_and_die("/proc/modules");
163 return 1;
164}
165
166#endif /*BB_FEATURE_OLD_MODULE_INTERFACE*/
diff --git a/makedevs.c b/makedevs.c
deleted file mode 100644
index b8c6dd1d8..000000000
--- a/makedevs.c
+++ /dev/null
@@ -1,95 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
4 *
5 * makedevs
6 * Make ranges of device files quickly.
7 * known bugs: can't deal with alpha ranges
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <fcntl.h>
14#include <unistd.h>
15#include <sys/types.h>
16#include "busybox.h"
17
18int makedevs_main(int argc, char **argv)
19{
20
21 const char *basedev = argv[1];
22 const char *type = argv[2];
23 int major = atoi(argv[3]);
24 int Sminor = atoi(argv[4]);
25 int S = atoi(argv[5]);
26 int E = atoi(argv[6]);
27 int sbase = argc == 8 ? 1 : 0;
28
29 mode_t mode = 0;
30 dev_t dev = 0;
31 char devname[255];
32 char buf[255];
33
34 if (argc < 7 || *argv[1]=='-')
35 show_usage();
36
37 switch (type[0]) {
38 case 'c':
39 mode = S_IFCHR;
40 break;
41 case 'b':
42 mode = S_IFBLK;
43 break;
44 case 'f':
45 mode = S_IFIFO;
46 break;
47 default:
48 show_usage();
49 }
50 mode |= 0660;
51
52 while (S <= E) {
53
54 if (type[0] != 'f')
55 dev = (major << 8) | Sminor;
56 strcpy(devname, basedev);
57
58 if (sbase == 0) {
59 sprintf(buf, "%d", S);
60 strcat(devname, buf);
61 } else {
62 sbase = 0;
63 }
64
65 if (mknod(devname, mode, dev))
66 printf("Failed to create: %s\n", devname);
67
68 S++;
69 Sminor++;
70 }
71
72 return 0;
73}
74
75/*
76And this is what this program replaces. The shell is too slow!
77
78makedev () {
79local basedev=$1; local S=$2; local E=$3
80local major=$4; local Sminor=$5; local type=$6
81local sbase=$7
82
83 if [ ! "$sbase" = "" ]; then
84 mknod "$basedev" $type $major $Sminor
85 S=`expr $S + 1`
86 Sminor=`expr $Sminor + 1`
87 fi
88
89 while [ $S -le $E ]; do
90 mknod "$basedev$S" $type $major $Sminor
91 S=`expr $S + 1`
92 Sminor=`expr $Sminor + 1`
93 done
94}
95*/
diff --git a/md5sum.c b/md5sum.c
deleted file mode 100644
index bb4d115ca..000000000
--- a/md5sum.c
+++ /dev/null
@@ -1,1074 +0,0 @@
1/* md5sum.c - Compute MD5 checksum of files or strings according to the
2 * definition of MD5 in RFC 1321 from April 1992.
3 * Copyright (C) 1995-1999 Free Software Foundation, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu> */
21/* Hacked to work with BusyBox by Alfred M. Szmidt <ams@trillian.itslinux.org> */
22
23/*
24 * June 29, 2001 Manuel Novoa III
25 *
26 * Added MD5SUM_SIZE_VS_SPEED configuration option.
27 *
28 * Current valid values, with data from my system for comparison, are:
29 * (using uClibc and running on linux-2.4.4.tar.bz2)
30 * user times (sec) text size (386)
31 * 0 (fastest) 1.1 6144
32 * 1 1.4 5392
33 * 2 3.0 5088
34 * 3 (smallest) 5.1 4912
35 */
36
37#define MD5SUM_SIZE_VS_SPEED 2
38
39/**********************************************************************/
40
41#include <stdio.h>
42#include <errno.h>
43#include <ctype.h>
44#include <getopt.h>
45#include <stdlib.h>
46#include <string.h>
47#include <endian.h>
48#include <sys/types.h>
49#if defined HAVE_LIMITS_H
50# include <limits.h>
51#endif
52#include "busybox.h"
53
54/* For some silly reason, this file uses backwards TRUE and FALSE conventions */
55#undef TRUE
56#undef FALSE
57#define FALSE ((int) 1)
58#define TRUE ((int) 0)
59
60//----------------------------------------------------------------------------
61//--------md5.c
62//----------------------------------------------------------------------------
63
64/* md5.c - Functions to compute MD5 message digest of files or memory blocks
65 * according to the definition of MD5 in RFC 1321 from April 1992.
66 */
67
68/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
69
70//----------------------------------------------------------------------------
71//--------md5.h
72//----------------------------------------------------------------------------
73
74/* md5.h - Declaration of functions and data types used for MD5 sum
75 computing library functions. */
76
77typedef u_int32_t md5_uint32;
78
79/* Structure to save state of computation between the single steps. */
80struct md5_ctx
81{
82 md5_uint32 A;
83 md5_uint32 B;
84 md5_uint32 C;
85 md5_uint32 D;
86
87 md5_uint32 total[2];
88 md5_uint32 buflen;
89 char buffer[128];
90};
91
92/*
93 * The following three functions are build up the low level used in
94 * the functions `md5_stream' and `md5_buffer'.
95 */
96
97/* Initialize structure containing state of computation.
98 (RFC 1321, 3.3: Step 3) */
99static void md5_init_ctx __P ((struct md5_ctx *ctx));
100
101/* Starting with the result of former calls of this function (or the
102 initialization function update the context for the next LEN bytes
103 starting at BUFFER.
104 It is necessary that LEN is a multiple of 64!!! */
105static void md5_process_block __P ((const void *buffer, size_t len,
106 struct md5_ctx *ctx));
107
108/* Starting with the result of former calls of this function (or the
109 initialization function update the context for the next LEN bytes
110 starting at BUFFER.
111 It is NOT required that LEN is a multiple of 64. */
112static void md5_process_bytes __P ((const void *buffer, size_t len,
113 struct md5_ctx *ctx));
114
115/* Process the remaining bytes in the buffer and put result from CTX
116 in first 16 bytes following RESBUF. The result is always in little
117 endian byte order, so that a byte-wise output yields to the wanted
118 ASCII representation of the message digest.
119
120 IMPORTANT: On some systems it is required that RESBUF is correctly
121 aligned for a 32 bits value. */
122static void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
123
124
125
126
127/* Compute MD5 message digest for bytes read from STREAM. The
128 resulting message digest number will be written into the 16 bytes
129 beginning at RESBLOCK. */
130static int md5_stream __P ((FILE *stream, void *resblock));
131
132/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
133 result is always in little endian byte order, so that a byte-wise
134 output yields to the wanted ASCII representation of the message
135 digest. */
136static void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
137
138//----------------------------------------------------------------------------
139//--------end of md5.h
140//----------------------------------------------------------------------------
141
142/* Handle endian-ness */
143#if __BYTE_ORDER == __LITTLE_ENDIAN
144 #define SWAP(n) (n)
145#else
146 #define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24))
147#endif
148
149
150
151#if MD5SUM_SIZE_VS_SPEED == 0
152/* This array contains the bytes used to pad the buffer to the next
153 64-byte boundary. (RFC 1321, 3.1: Step 1) */
154static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
155#endif
156
157/* Initialize structure containing state of computation.
158 (RFC 1321, 3.3: Step 3) */
159void md5_init_ctx(struct md5_ctx *ctx)
160{
161 ctx->A = 0x67452301;
162 ctx->B = 0xefcdab89;
163 ctx->C = 0x98badcfe;
164 ctx->D = 0x10325476;
165
166 ctx->total[0] = ctx->total[1] = 0;
167 ctx->buflen = 0;
168}
169
170/* Process the remaining bytes in the internal buffer and the usual
171 prolog according to the standard and write the result to RESBUF.
172
173 IMPORTANT: On some systems it is required that RESBUF is correctly
174 aligned for a 32 bits value. */
175static void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
176{
177 /* Take yet unprocessed bytes into account. */
178 md5_uint32 bytes = ctx->buflen;
179 size_t pad;
180
181 /* Now count remaining bytes. */
182 ctx->total[0] += bytes;
183 if (ctx->total[0] < bytes)
184 ++ctx->total[1];
185
186 pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
187#if MD5SUM_SIZE_VS_SPEED > 0
188 memset(&ctx->buffer[bytes], 0, pad);
189 ctx->buffer[bytes] = 0x80;
190#else
191 memcpy(&ctx->buffer[bytes], fillbuf, pad);
192#endif
193
194 /* Put the 64-bit file length in *bits* at the end of the buffer. */
195 *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3);
196 *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] =
197 SWAP( ((ctx->total[1] << 3) | (ctx->total[0] >> 29)) );
198
199 /* Process last bytes. */
200 md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
201
202/* Put result from CTX in first 16 bytes following RESBUF. The result is
203 always in little endian byte order, so that a byte-wise output yields
204 to the wanted ASCII representation of the message digest.
205
206 IMPORTANT: On some systems it is required that RESBUF is correctly
207 aligned for a 32 bits value. */
208 ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A);
209 ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B);
210 ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C);
211 ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D);
212
213 return resbuf;
214}
215
216/* Compute MD5 message digest for bytes read from STREAM. The
217 resulting message digest number will be written into the 16 bytes
218 beginning at RESBLOCK. */
219static int md5_stream(FILE *stream, void *resblock)
220{
221 /* Important: BLOCKSIZE must be a multiple of 64. */
222static const int BLOCKSIZE = 4096;
223 struct md5_ctx ctx;
224 char buffer[BLOCKSIZE + 72];
225 size_t sum;
226
227 /* Initialize the computation context. */
228 md5_init_ctx(&ctx);
229
230 /* Iterate over full file contents. */
231 while (1) {
232 /* We read the file in blocks of BLOCKSIZE bytes. One call of the
233 computation function processes the whole buffer so that with the
234 next round of the loop another block can be read. */
235 size_t n;
236 sum = 0;
237
238 /* Read block. Take care for partial reads. */
239 do {
240 n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
241
242 sum += n;
243 }
244 while (sum < BLOCKSIZE && n != 0);
245 if (n == 0 && ferror(stream))
246 return 1;
247
248 /* If end of file is reached, end the loop. */
249 if (n == 0)
250 break;
251
252 /* Process buffer with BLOCKSIZE bytes. Note that
253 BLOCKSIZE % 64 == 0
254 */
255 md5_process_block(buffer, BLOCKSIZE, &ctx);
256 }
257
258 /* Add the last bytes if necessary. */
259 if (sum > 0)
260 md5_process_bytes(buffer, sum, &ctx);
261
262 /* Construct result in desired memory. */
263 md5_finish_ctx(&ctx, resblock);
264 return 0;
265}
266
267/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
268 result is always in little endian byte order, so that a byte-wise
269 output yields to the wanted ASCII representation of the message
270 digest. */
271static void *md5_buffer(const char *buffer, size_t len, void *resblock)
272{
273 struct md5_ctx ctx;
274
275 /* Initialize the computation context. */
276 md5_init_ctx(&ctx);
277
278 /* Process whole buffer but last len % 64 bytes. */
279 md5_process_bytes(buffer, len, &ctx);
280
281 /* Put result in desired memory area. */
282 return md5_finish_ctx(&ctx, resblock);
283}
284
285static void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx)
286{
287 /* When we already have some bits in our internal buffer concatenate
288 both inputs first. */
289 if (ctx->buflen != 0) {
290 size_t left_over = ctx->buflen;
291 size_t add = 128 - left_over > len ? len : 128 - left_over;
292
293 memcpy(&ctx->buffer[left_over], buffer, add);
294 ctx->buflen += add;
295
296 if (left_over + add > 64) {
297 md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx);
298 /* The regions in the following copy operation cannot overlap. */
299 memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
300 (left_over + add) & 63);
301 ctx->buflen = (left_over + add) & 63;
302 }
303
304 buffer = (const char *) buffer + add;
305 len -= add;
306 }
307
308 /* Process available complete blocks. */
309 if (len > 64) {
310 md5_process_block(buffer, len & ~63, ctx);
311 buffer = (const char *) buffer + (len & ~63);
312 len &= 63;
313 }
314
315 /* Move remaining bytes in internal buffer. */
316 if (len > 0) {
317 memcpy(ctx->buffer, buffer, len);
318 ctx->buflen = len;
319 }
320}
321
322/* These are the four functions used in the four steps of the MD5 algorithm
323 and defined in the RFC 1321. The first function is a little bit optimized
324 (as found in Colin Plumbs public domain implementation). */
325/* #define FF(b, c, d) ((b & c) | (~b & d)) */
326#define FF(b, c, d) (d ^ (b & (c ^ d)))
327#define FG(b, c, d) FF (d, b, c)
328#define FH(b, c, d) (b ^ c ^ d)
329#define FI(b, c, d) (c ^ (b | ~d))
330
331/* Process LEN bytes of BUFFER, accumulating context into CTX.
332 It is assumed that LEN % 64 == 0. */
333static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
334{
335 md5_uint32 correct_words[16];
336 const md5_uint32 *words = buffer;
337 size_t nwords = len / sizeof(md5_uint32);
338 const md5_uint32 *endp = words + nwords;
339#if MD5SUM_SIZE_VS_SPEED > 0
340 static const md5_uint32 C_array[] = {
341 /* round 1 */
342 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
343 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
344 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
345 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
346 /* round 2 */
347 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
348 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
349 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
350 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
351 /* round 3 */
352 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
353 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
354 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
355 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
356 /* round 4 */
357 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
358 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
359 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
360 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
361 };
362
363 static const char P_array[] = {
364#if MD5SUM_SIZE_VS_SPEED > 1
365 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
366#endif
367 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
368 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
369 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
370 };
371
372#if MD5SUM_SIZE_VS_SPEED > 1
373 static const char S_array[] = {
374 7, 12, 17, 22,
375 5, 9, 14, 20,
376 4, 11, 16, 23,
377 6, 10, 15, 21
378 };
379#endif
380#endif
381
382 md5_uint32 A = ctx->A;
383 md5_uint32 B = ctx->B;
384 md5_uint32 C = ctx->C;
385 md5_uint32 D = ctx->D;
386
387 /* First increment the byte count. RFC 1321 specifies the possible
388 length of the file up to 2^64 bits. Here we only compute the
389 number of bytes. Do a double word increment. */
390 ctx->total[0] += len;
391 if (ctx->total[0] < len)
392 ++ctx->total[1];
393
394 /* Process all bytes in the buffer with 64 bytes in each round of
395 the loop. */
396 while (words < endp) {
397 md5_uint32 *cwp = correct_words;
398 md5_uint32 A_save = A;
399 md5_uint32 B_save = B;
400 md5_uint32 C_save = C;
401 md5_uint32 D_save = D;
402
403#if MD5SUM_SIZE_VS_SPEED > 1
404#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
405
406 const md5_uint32 *pc;
407 const char *pp;
408 const char *ps;
409 int i;
410 md5_uint32 temp;
411
412 for ( i=0 ; i < 16 ; i++ ) {
413 cwp[i] = SWAP(words[i]);
414 }
415 words += 16;
416
417#if MD5SUM_SIZE_VS_SPEED > 2
418 pc = C_array; pp = P_array; ps = S_array - 4;
419
420 for ( i = 0 ; i < 64 ; i++ ) {
421 if ((i&0x0f) == 0) ps += 4;
422 temp = A;
423 switch (i>>4) {
424 case 0:
425 temp += FF(B,C,D);
426 break;
427 case 1:
428 temp += FG(B,C,D);
429 break;
430 case 2:
431 temp += FH(B,C,D);
432 break;
433 case 3:
434 temp += FI(B,C,D);
435 }
436 temp += cwp[(int)(*pp++)] + *pc++;
437 temp = CYCLIC (temp, ps[i&3]);
438 temp += B;
439 A = D; D = C; C = B; B = temp;
440 }
441#else
442 pc = C_array; pp = P_array; ps = S_array;
443
444 for ( i = 0 ; i < 16 ; i++ ) {
445 temp = A + FF(B,C,D) + cwp[(int)(*pp++)] + *pc++;
446 temp = CYCLIC (temp, ps[i&3]);
447 temp += B;
448 A = D; D = C; C = B; B = temp;
449 }
450
451 ps += 4;
452 for ( i = 0 ; i < 16 ; i++ ) {
453 temp = A + FG(B,C,D) + cwp[(int)(*pp++)] + *pc++;
454 temp = CYCLIC (temp, ps[i&3]);
455 temp += B;
456 A = D; D = C; C = B; B = temp;
457 }
458 ps += 4;
459 for ( i = 0 ; i < 16 ; i++ ) {
460 temp = A + FH(B,C,D) + cwp[(int)(*pp++)] + *pc++;
461 temp = CYCLIC (temp, ps[i&3]);
462 temp += B;
463 A = D; D = C; C = B; B = temp;
464 }
465 ps += 4;
466 for ( i = 0 ; i < 16 ; i++ ) {
467 temp = A + FI(B,C,D) + cwp[(int)(*pp++)] + *pc++;
468 temp = CYCLIC (temp, ps[i&3]);
469 temp += B;
470 A = D; D = C; C = B; B = temp;
471 }
472
473#endif
474#else
475 /* First round: using the given function, the context and a constant
476 the next context is computed. Because the algorithms processing
477 unit is a 32-bit word and it is determined to work on words in
478 little endian byte order we perhaps have to change the byte order
479 before the computation. To reduce the work for the next steps
480 we store the swapped words in the array CORRECT_WORDS. */
481
482#define OP(a, b, c, d, s, T) \
483 do \
484 { \
485 a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
486 ++words; \
487 CYCLIC (a, s); \
488 a += b; \
489 } \
490 while (0)
491
492 /* It is unfortunate that C does not provide an operator for
493 cyclic rotation. Hope the C compiler is smart enough. */
494 /* gcc 2.95.4 seems to be --aaronl */
495#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
496
497 /* Before we start, one word to the strange constants.
498 They are defined in RFC 1321 as
499
500 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
501 */
502
503#if MD5SUM_SIZE_VS_SPEED == 1
504 const md5_uint32 *pc;
505 const char *pp;
506 int i;
507#endif
508
509 /* Round 1. */
510#if MD5SUM_SIZE_VS_SPEED == 1
511 pc = C_array;
512 for ( i=0 ; i < 4 ; i++ ) {
513 OP(A, B, C, D, 7, *pc++);
514 OP(D, A, B, C, 12, *pc++);
515 OP(C, D, A, B, 17, *pc++);
516 OP(B, C, D, A, 22, *pc++);
517 }
518#else
519 OP(A, B, C, D, 7, 0xd76aa478);
520 OP(D, A, B, C, 12, 0xe8c7b756);
521 OP(C, D, A, B, 17, 0x242070db);
522 OP(B, C, D, A, 22, 0xc1bdceee);
523 OP(A, B, C, D, 7, 0xf57c0faf);
524 OP(D, A, B, C, 12, 0x4787c62a);
525 OP(C, D, A, B, 17, 0xa8304613);
526 OP(B, C, D, A, 22, 0xfd469501);
527 OP(A, B, C, D, 7, 0x698098d8);
528 OP(D, A, B, C, 12, 0x8b44f7af);
529 OP(C, D, A, B, 17, 0xffff5bb1);
530 OP(B, C, D, A, 22, 0x895cd7be);
531 OP(A, B, C, D, 7, 0x6b901122);
532 OP(D, A, B, C, 12, 0xfd987193);
533 OP(C, D, A, B, 17, 0xa679438e);
534 OP(B, C, D, A, 22, 0x49b40821);
535#endif
536
537 /* For the second to fourth round we have the possibly swapped words
538 in CORRECT_WORDS. Redefine the macro to take an additional first
539 argument specifying the function to use. */
540#undef OP
541#define OP(f, a, b, c, d, k, s, T) \
542 do \
543 { \
544 a += f (b, c, d) + correct_words[k] + T; \
545 CYCLIC (a, s); \
546 a += b; \
547 } \
548 while (0)
549
550 /* Round 2. */
551#if MD5SUM_SIZE_VS_SPEED == 1
552 pp = P_array;
553 for ( i=0 ; i < 4 ; i++ ) {
554 OP(FG, A, B, C, D, (int)(*pp++), 5, *pc++);
555 OP(FG, D, A, B, C, (int)(*pp++), 9, *pc++);
556 OP(FG, C, D, A, B, (int)(*pp++), 14, *pc++);
557 OP(FG, B, C, D, A, (int)(*pp++), 20, *pc++);
558 }
559#else
560 OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
561 OP(FG, D, A, B, C, 6, 9, 0xc040b340);
562 OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
563 OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
564 OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
565 OP(FG, D, A, B, C, 10, 9, 0x02441453);
566 OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
567 OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
568 OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
569 OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
570 OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
571 OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
572 OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
573 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
574 OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
575 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
576#endif
577
578 /* Round 3. */
579#if MD5SUM_SIZE_VS_SPEED == 1
580 for ( i=0 ; i < 4 ; i++ ) {
581 OP(FH, A, B, C, D, (int)(*pp++), 4, *pc++);
582 OP(FH, D, A, B, C, (int)(*pp++), 11, *pc++);
583 OP(FH, C, D, A, B, (int)(*pp++), 16, *pc++);
584 OP(FH, B, C, D, A, (int)(*pp++), 23, *pc++);
585 }
586#else
587 OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
588 OP(FH, D, A, B, C, 8, 11, 0x8771f681);
589 OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
590 OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
591 OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
592 OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
593 OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
594 OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
595 OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
596 OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
597 OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
598 OP(FH, B, C, D, A, 6, 23, 0x04881d05);
599 OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
600 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
601 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
602 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
603#endif
604
605 /* Round 4. */
606#if MD5SUM_SIZE_VS_SPEED == 1
607 for ( i=0 ; i < 4 ; i++ ) {
608 OP(FI, A, B, C, D, (int)(*pp++), 6, *pc++);
609 OP(FI, D, A, B, C, (int)(*pp++), 10, *pc++);
610 OP(FI, C, D, A, B, (int)(*pp++), 15, *pc++);
611 OP(FI, B, C, D, A, (int)(*pp++), 21, *pc++);
612 }
613#else
614 OP(FI, A, B, C, D, 0, 6, 0xf4292244);
615 OP(FI, D, A, B, C, 7, 10, 0x432aff97);
616 OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
617 OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
618 OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
619 OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
620 OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
621 OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
622 OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
623 OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
624 OP(FI, C, D, A, B, 6, 15, 0xa3014314);
625 OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
626 OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
627 OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
628 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
629 OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
630#endif
631#endif
632
633 /* Add the starting values of the context. */
634 A += A_save;
635 B += B_save;
636 C += C_save;
637 D += D_save;
638 }
639
640 /* Put checksum in context given as argument. */
641 ctx->A = A;
642 ctx->B = B;
643 ctx->C = C;
644 ctx->D = D;
645}
646
647//----------------------------------------------------------------------------
648//--------end of md5.c
649//----------------------------------------------------------------------------
650
651#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
652#define ISXDIGIT(c) (isxdigit (c))
653
654/* The minimum length of a valid digest line in a file produced
655 by `md5sum FILE' and read by `md5sum -c'. This length does
656 not include any newline character at the end of a line. */
657static const int MIN_DIGEST_LINE_LENGTH = 35; /* 32 - message digest length
658 2 - blank and binary indicator
659 1 - minimum filename length */
660
661static int have_read_stdin; /* Nonzero if any of the files read were
662 the standard input. */
663
664static int status_only = 0; /* With -c, don't generate any output.
665 The exit code indicates success or failure */
666static int warn = 0; /* With -w, print a message to standard error warning
667 about each improperly formatted MD5 checksum line */
668
669static int split_3(char *s,
670 size_t s_len,
671 unsigned char **u,
672 char **w)
673{
674 size_t i = 0;
675 int escaped_filename = 0;
676
677 while (ISWHITE(s[i]))
678 ++i;
679
680 /* The line must have at least 35 (36 if the first is a backslash)
681 more characters to contain correct message digest information.
682 Ignore this line if it is too short. */
683 if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH
684 || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH)))
685 return FALSE;
686
687 if (s[i] == '\\') {
688 ++i;
689 escaped_filename = 1;
690 }
691 *u = (unsigned char *) &s[i];
692
693 /* The first field has to be the 32-character hexadecimal
694 representation of the message digest. If it is not followed
695 immediately by a white space it's an error. */
696 i += 32;
697 if (!ISWHITE(s[i]))
698 return FALSE;
699
700 s[i++] = '\0';
701
702 if (s[i] != ' ' && s[i++] != '*')
703 return FALSE;
704
705 /* All characters between the type indicator and end of line are
706 significant -- that includes leading and trailing white space. */
707 *w = &s[i];
708
709 if (escaped_filename) {
710 /* Translate each `\n' string in the file name to a NEWLINE,
711 and each `\\' string to a backslash. */
712
713 char *dst = &s[i];
714
715 while (i < s_len) {
716 switch (s[i]) {
717 case '\\':
718 if (i == s_len - 1) {
719 /* A valid line does not end with a backslash. */
720 return FALSE;
721 }
722 ++i;
723 switch (s[i++]) {
724 case 'n':
725 *dst++ = '\n';
726 break;
727 case '\\':
728 *dst++ = '\\';
729 break;
730 default:
731 /* Only `\' or `n' may follow a backslash. */
732 return FALSE;
733 }
734 break;
735
736 case '\0':
737 /* The file name may not contain a NUL. */
738 return FALSE;
739 break;
740
741 default:
742 *dst++ = s[i++];
743 break;
744 }
745 }
746 *dst = '\0';
747 }
748 return TRUE;
749}
750
751static inline int hex_digits(unsigned char const *s)
752{
753 while (*s) {
754 if (!ISXDIGIT(*s))
755 return TRUE;
756 ++s;
757 }
758 return FALSE;
759}
760
761/* An interface to md5_stream. Operate on FILENAME (it may be "-") and
762 put the result in *MD5_RESULT. Return non-zero upon failure, zero
763 to indicate success. */
764static int md5_file(const char *filename,
765 unsigned char *md5_result)
766{
767 FILE *fp;
768
769 if (filename[0] == '-' && filename[1] == '\0') {
770 have_read_stdin = 1;
771 fp = stdin;
772 } else {
773 fp = wfopen(filename, "r");
774 if (fp == NULL)
775 return FALSE;
776 }
777
778 if (md5_stream(fp, md5_result)) {
779 perror_msg("%s", filename);
780
781 if (fp != stdin)
782 fclose(fp);
783 return FALSE;
784 }
785
786 if (fp != stdin && fclose(fp) == EOF) {
787 perror_msg("%s", filename);
788 return FALSE;
789 }
790
791 return TRUE;
792}
793
794static int md5_check(const char *checkfile_name)
795{
796 FILE *checkfile_stream;
797 int n_properly_formated_lines = 0;
798 int n_mismatched_checksums = 0;
799 int n_open_or_read_failures = 0;
800 unsigned char md5buffer[16];
801 size_t line_number;
802 char line[BUFSIZ];
803
804 if (checkfile_name[0] == '-' && checkfile_name[1] == '\0') {
805 have_read_stdin = 1;
806 checkfile_stream = stdin;
807 } else {
808 checkfile_stream = wfopen(checkfile_name, "r");
809 if (checkfile_stream == NULL)
810 return FALSE;
811 }
812
813 line_number = 0;
814
815 do {
816 char *filename;
817 unsigned char *md5num;
818 int line_length;
819
820 ++line_number;
821
822 fgets(line, BUFSIZ-1, checkfile_stream);
823 line_length = strlen(line);
824
825 if (line_length <= 0 || line==NULL)
826 break;
827
828 /* Ignore comment lines, which begin with a '#' character. */
829 if (line[0] == '#')
830 continue;
831
832 /* Remove any trailing newline. */
833 if (line[line_length - 1] == '\n')
834 line[--line_length] = '\0';
835
836 if (split_3(line, line_length, &md5num, &filename)
837 || !hex_digits(md5num)) {
838 if (warn) {
839 error_msg("%s: %lu: improperly formatted MD5 checksum line",
840 checkfile_name, (unsigned long) line_number);
841 }
842 } else {
843 static const char bin2hex[] = {
844 '0', '1', '2', '3',
845 '4', '5', '6', '7',
846 '8', '9', 'a', 'b',
847 'c', 'd', 'e', 'f'
848 };
849
850 ++n_properly_formated_lines;
851
852 if (md5_file(filename, md5buffer)) {
853 ++n_open_or_read_failures;
854 if (!status_only) {
855 printf("%s: FAILED open or read\n", filename);
856 fflush(stdout);
857 }
858 } else {
859 size_t cnt;
860 /* Compare generated binary number with text representation
861 in check file. Ignore case of hex digits. */
862 for (cnt = 0; cnt < 16; ++cnt) {
863 if (tolower(md5num[2 * cnt])
864 != bin2hex[md5buffer[cnt] >> 4]
865 || (tolower(md5num[2 * cnt + 1])
866 != (bin2hex[md5buffer[cnt] & 0xf])))
867 break;
868 }
869 if (cnt != 16)
870 ++n_mismatched_checksums;
871
872 if (!status_only) {
873 printf("%s: %s\n", filename,
874 (cnt != 16 ? "FAILED" : "OK"));
875 fflush(stdout);
876 }
877 }
878 }
879 }
880
881 while (!feof(checkfile_stream) && !ferror(checkfile_stream));
882
883 if (ferror(checkfile_stream)) {
884 error_msg("%s: read error", checkfile_name);
885 return FALSE;
886 }
887
888 if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) {
889 perror_msg("md5sum: %s", checkfile_name);
890 return FALSE;
891 }
892
893 if (n_properly_formated_lines == 0) {
894 /* Warn if no tests are found. */
895 error_msg("%s: no properly formatted MD5 checksum lines found",
896 checkfile_name);
897 return FALSE;
898 } else {
899 if (!status_only) {
900 int n_computed_checkums = (n_properly_formated_lines
901 - n_open_or_read_failures);
902
903 if (n_open_or_read_failures > 0) {
904 error_msg("WARNING: %d of %d listed files could not be read",
905 n_open_or_read_failures, n_properly_formated_lines);
906 return FALSE;
907 }
908
909 if (n_mismatched_checksums > 0) {
910 error_msg("WARNING: %d of %d computed checksums did NOT match",
911 n_mismatched_checksums, n_computed_checkums);
912 return FALSE;
913 }
914 }
915 }
916
917 return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
918 && n_open_or_read_failures == 0) ? 0 : 1);
919}
920
921int md5sum_main(int argc,
922 char **argv)
923{
924 unsigned char md5buffer[16];
925 int do_check = 0;
926 int opt;
927 char **string = NULL;
928 size_t n_strings = 0;
929 size_t err = 0;
930 char file_type_specified = 0;
931 char binary = 0;
932
933 while ((opt = getopt(argc, argv, "g:bcstw")) != -1) {
934 switch (opt) {
935 case 'g': { /* read a string */
936 if (string == NULL)
937 string = (char **) xmalloc ((argc - 1) * sizeof (char *));
938
939 string[n_strings++] = optarg;
940 break;
941 }
942
943 case 'b': /* read files in binary mode */
944 file_type_specified = 1;
945 binary = 1;
946 break;
947
948 case 'c': /* check MD5 sums against given list */
949 do_check = 1;
950 break;
951
952 case 's': /* don't output anything, status code shows success */
953 status_only = 1;
954 warn = 0;
955 break;
956
957 case 't': /* read files in text mode (default) */
958 file_type_specified = 1;
959 binary = 0;
960 break;
961
962 case 'w': /* warn about improperly formated MD5 checksum lines */
963 status_only = 0;
964 warn = 1;
965 break;
966
967 default:
968 show_usage();
969 }
970 }
971
972 if (file_type_specified && do_check) {
973 error_msg_and_die("the -b and -t options are meaningless when verifying checksums");
974 }
975
976 if (n_strings > 0 && do_check) {
977 error_msg_and_die("the -g and -c options are mutually exclusive");
978 }
979
980 if (status_only && !do_check) {
981 error_msg_and_die("the -s option is meaningful only when verifying checksums");
982 }
983
984 if (warn && !do_check) {
985 error_msg_and_die("the -w option is meaningful only when verifying checksums");
986 }
987
988 if (n_strings > 0) {
989 size_t i;
990
991 if (optind < argc) {
992 error_msg_and_die("no files may be specified when using -g");
993 }
994 for (i = 0; i < n_strings; ++i) {
995 size_t cnt;
996 md5_buffer (string[i], strlen (string[i]), md5buffer);
997
998 for (cnt = 0; cnt < 16; ++cnt)
999 printf ("%02x", md5buffer[cnt]);
1000
1001 printf (" \"%s\"\n", string[i]);
1002 }
1003 } else if (do_check) {
1004 if (optind + 1 < argc) {
1005 error_msg("only one argument may be specified when using -c");
1006 }
1007
1008 err = md5_check ((optind == argc) ? "-" : argv[optind]);
1009 } else {
1010 if (optind == argc)
1011 argv[argc++] = "-";
1012
1013 for (; optind < argc; ++optind) {
1014 int fail;
1015 char *file = argv[optind];
1016
1017 fail = md5_file (file, md5buffer);
1018 err |= fail;
1019 if (!fail && file[0]=='-' && file[1] == '\0') {
1020 size_t i;
1021 for (i = 0; i < 16; ++i)
1022 printf ("%02x", md5buffer[i]);
1023 putchar ('\n');
1024 } else if (!fail) {
1025 size_t i;
1026 /* Output a leading backslash if the file name contains
1027 a newline or backslash. */
1028 if (strchr (file, '\n') || strchr (file, '\\'))
1029 putchar ('\\');
1030
1031 for (i = 0; i < 16; ++i)
1032 printf ("%02x", md5buffer[i]);
1033
1034 putchar (' ');
1035 if (binary)
1036 putchar ('*');
1037 else
1038 putchar (' ');
1039
1040 /* Translate each NEWLINE byte to the string, "\\n",
1041 and each backslash to "\\\\". */
1042 for (i = 0; i < strlen (file); ++i) {
1043 switch (file[i]) {
1044 case '\n':
1045 fputs ("\\n", stdout);
1046 break;
1047
1048 case '\\':
1049 fputs ("\\\\", stdout);
1050 break;
1051
1052 default:
1053 putchar (file[i]);
1054 break;
1055 }
1056 }
1057 putchar ('\n');
1058 }
1059 }
1060 }
1061
1062 if (fclose (stdout) == EOF) {
1063 error_msg_and_die("write error");
1064 }
1065
1066 if (have_read_stdin && fclose (stdin) == EOF) {
1067 error_msg_and_die("standard input");
1068 }
1069
1070 if (err == 0)
1071 return EXIT_SUCCESS;
1072 else
1073 return EXIT_FAILURE;
1074}
diff --git a/miscutils/Makefile b/miscutils/Makefile
new file mode 100644
index 000000000..4e006ba57
--- /dev/null
+++ b/miscutils/Makefile
@@ -0,0 +1,44 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := miscutils.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27
28obj-$(CONFIG_ADJTIMEX) += adjtimex.o
29obj-$(CONFIG_DC) += dc.o
30obj-$(CONFIG_DUTMP) += dutmp.o
31obj-$(CONFIG_MAKEDEVS) += makedevs.o
32obj-$(CONFIG_mktemp) += mktemp.o
33obj-$(CONFIG_mt) += mt.o
34obj-$(CONFIG_readlink) += readlink.o
35obj-$(CONFIG_update) += update.o
36obj-$(CONFIG_watchdog) += watchdog.o
37
38
39# Hand off to toplevel Rules.mak
40include $(TOPDIR)/Rules.mak
41
42clean:
43 rm -f $(L_TARGET) *.o core
44
diff --git a/miscutils/config.in b/miscutils/config.in
new file mode 100644
index 000000000..61b2113bc
--- /dev/null
+++ b/miscutils/config.in
@@ -0,0 +1,20 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Miscellaneous Utilities'
8
9bool 'adjtimex' CONFIG_ADJTIMEX
10bool 'dc' CONFIG_DC
11bool 'dutmp' CONFIG_DUTMP
12bool 'makedevs' CONFIG_MAKEDEVS
13bool 'mktemp' CONFIG_MKTEMP
14bool 'mt' CONFIG_MT
15bool 'readlink' CONFIG_READLINK
16bool 'update' CONFIG_UPDATE
17bool 'watchdog' CONFIG_WATCHDOG
18
19endmenu
20
diff --git a/miscutils/readlink.c b/miscutils/readlink.c
index c46ebd108..da5259038 100644
--- a/miscutils/readlink.c
+++ b/miscutils/readlink.c
@@ -2,9 +2,7 @@
2/* 2/*
3 * Mini readlink implementation for busybox 3 * Mini readlink implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 2000,2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -40,7 +38,7 @@ int readlink_main(int argc, char **argv)
40 if (!buf) 38 if (!buf)
41 return EXIT_FAILURE; 39 return EXIT_FAILURE;
42 puts(buf); 40 puts(buf);
43#ifdef BB_FEATURE_CLEAN_UP 41#ifdef CONFIG_FEATURE_CLEAN_UP
44 free(buf); 42 free(buf);
45#endif 43#endif
46 44
diff --git a/mk_loop_h.sh b/mk_loop_h.sh
deleted file mode 100755
index 71c987376..000000000
--- a/mk_loop_h.sh
+++ /dev/null
@@ -1,37 +0,0 @@
1#!/bin/sh
2#
3# Figure out (i) the type of dev_t (ii) the defines for loop stuff
4#
5# Output of this script is normally redirected to "loop.h".
6
7# Since 1.3.79 there is an include file <asm/posix_types.h>
8# that defines __kernel_dev_t.
9# (The file itself appeared in 1.3.78, but there it defined __dev_t.)
10# If it exists, we use it, or, rather, <linux/posix_types.h> which
11# avoids namespace pollution. Otherwise we guess that __kernel_dev_t
12# is an unsigned short (which is true on i386, but false on alpha).
13
14# BUG: This test is actually broken if your gcc is not configured to
15# search /usr/include, as may well happen with cross-compilers.
16# It would be better to ask $(CC) if these files can be found.
17
18if [ -f /usr/include/linux/posix_types.h ]; then
19 echo '#include <linux/posix_types.h>'
20 echo '#undef dev_t'
21 echo '#define dev_t __kernel_dev_t'
22else
23 echo '#undef dev_t'
24 echo '#define dev_t unsigned short'
25fi
26
27# Next we have to find the loop stuff itself.
28# First try kernel source, then a private version.
29
30if [ -f /usr/include/linux/loop.h ]; then
31 echo '#include <linux/loop.h>'
32else
33 echo '#include "real_loop.h"'
34fi
35
36echo '#undef dev_t'
37
diff --git a/mkdir.c b/mkdir.c
deleted file mode 100644
index 03c49f098..000000000
--- a/mkdir.c
+++ /dev/null
@@ -1,64 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini mkdir implementation for busybox
4 *
5 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <errno.h>
24#include <getopt.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <fcntl.h>
28#include <unistd.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include "busybox.h"
33
34extern int mkdir_main (int argc, char **argv)
35{
36 mode_t mode = -1;
37 int flags = 0;
38 int status = 0;
39 int i, opt;
40
41 while ((opt = getopt (argc, argv, "m:p")) != -1) {
42 switch (opt) {
43 case 'm':
44 mode = 0777;
45 if (!parse_mode (optarg, &mode))
46 error_msg_and_die ("invalid mode `%s'", optarg);
47 break;
48 case 'p':
49 flags |= FILEUTILS_RECUR;
50 break;
51 default:
52 show_usage ();
53 }
54 }
55
56 if (optind == argc)
57 show_usage ();
58
59 for (i = optind; i < argc; i++)
60 if (make_directory (argv[i], mode, flags) < 0)
61 status = 1;
62
63 return status;
64}
diff --git a/mkfifo.c b/mkfifo.c
deleted file mode 100644
index ca217fa23..000000000
--- a/mkfifo.c
+++ /dev/null
@@ -1,60 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini mkfifo implementation for busybox
4 *
5 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <sys/types.h>
25#include <errno.h>
26#include <stdlib.h>
27#include "busybox.h"
28
29extern int mkfifo_main(int argc, char **argv)
30{
31 char *thisarg;
32 mode_t mode = 0666;
33
34 argc--;
35 argv++;
36
37 /* Parse any options */
38 while (argc > 1) {
39 if (**argv != '-')
40 show_usage();
41 thisarg = *argv;
42 thisarg++;
43 switch (*thisarg) {
44 case 'm':
45 argc--;
46 argv++;
47 parse_mode(*argv, &mode);
48 break;
49 default:
50 show_usage();
51 }
52 argc--;
53 argv++;
54 }
55 if (argc < 1 || *argv[0] == '-')
56 show_usage();
57 if (mkfifo(*argv, mode) < 0)
58 perror_msg_and_die("mkfifo");
59 return EXIT_SUCCESS;
60}
diff --git a/mkfs_minix.c b/mkfs_minix.c
deleted file mode 100644
index ccc0e85d7..000000000
--- a/mkfs_minix.c
+++ /dev/null
@@ -1,847 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mkfs.c - make a linux (minix) file-system.
4 *
5 * (C) 1991 Linus Torvalds. This file may be redistributed as per
6 * the Linux copyright.
7 */
8
9/*
10 * DD.MM.YY
11 *
12 * 24.11.91 - Time began. Used the fsck sources to get started.
13 *
14 * 25.11.91 - Corrected some bugs. Added support for ".badblocks"
15 * The algorithm for ".badblocks" is a bit weird, but
16 * it should work. Oh, well.
17 *
18 * 25.01.92 - Added the -l option for getting the list of bad blocks
19 * out of a named file. (Dave Rivers, rivers@ponds.uucp)
20 *
21 * 28.02.92 - Added %-information when using -c.
22 *
23 * 28.02.93 - Added support for other namelengths than the original
24 * 14 characters so that I can test the new kernel routines..
25 *
26 * 09.10.93 - Make exit status conform to that required by fsutil
27 * (Rik Faith, faith@cs.unc.edu)
28 *
29 * 31.10.93 - Added inode request feature, for backup floppies: use
30 * 32 inodes, for a news partition use more.
31 * (Scott Heavner, sdh@po.cwru.edu)
32 *
33 * 03.01.94 - Added support for file system valid flag.
34 * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
35 *
36 * 30.10.94 - added support for v2 filesystem
37 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
38 *
39 * 09.11.94 - Added test to prevent overwrite of mounted fs adapted
40 * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
41 * program. (Daniel Quinlan, quinlan@yggdrasil.com)
42 *
43 * 03.20.95 - Clear first 512 bytes of filesystem to make certain that
44 * the filesystem is not misidentified as a MS-DOS FAT filesystem.
45 * (Daniel Quinlan, quinlan@yggdrasil.com)
46 *
47 * 02.07.96 - Added small patch from Russell King to make the program a
48 * good deal more portable (janl@math.uio.no)
49 *
50 * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
51 *
52 * -c for readablility checking (SLOW!)
53 * -l for getting a list of bad blocks from a file.
54 * -n for namelength (currently the kernel only uses 14 or 30)
55 * -i for number of inodes
56 * -v for v2 filesystem
57 *
58 * The device may be a block device or a image of one, but this isn't
59 * enforced (but it's not much fun on a character device :-).
60 *
61 * Modified for BusyBox by Erik Andersen <andersen@debian.org> --
62 * removed getopt based parser and added a hand rolled one.
63 */
64
65#include <stdio.h>
66#include <time.h>
67#include <unistd.h>
68#include <string.h>
69#include <signal.h>
70#include <fcntl.h>
71#include <ctype.h>
72#include <stdlib.h>
73#include <termios.h>
74#include <sys/ioctl.h>
75#include <sys/param.h>
76#include <mntent.h>
77#include "busybox.h"
78
79#define MINIX_ROOT_INO 1
80#define MINIX_LINK_MAX 250
81#define MINIX2_LINK_MAX 65530
82
83#define MINIX_I_MAP_SLOTS 8
84#define MINIX_Z_MAP_SLOTS 64
85#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
86#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
87#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
88#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
89#define MINIX_VALID_FS 0x0001 /* Clean fs. */
90#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
91
92#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
93#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
94
95#define MINIX_V1 0x0001 /* original minix fs */
96#define MINIX_V2 0x0002 /* minix V2 fs */
97
98#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
99
100/*
101 * This is the original minix inode layout on disk.
102 * Note the 8-bit gid and atime and ctime.
103 */
104struct minix_inode {
105 u_int16_t i_mode;
106 u_int16_t i_uid;
107 u_int32_t i_size;
108 u_int32_t i_time;
109 u_int8_t i_gid;
110 u_int8_t i_nlinks;
111 u_int16_t i_zone[9];
112};
113
114/*
115 * The new minix inode has all the time entries, as well as
116 * long block numbers and a third indirect block (7+1+1+1
117 * instead of 7+1+1). Also, some previously 8-bit values are
118 * now 16-bit. The inode is now 64 bytes instead of 32.
119 */
120struct minix2_inode {
121 u_int16_t i_mode;
122 u_int16_t i_nlinks;
123 u_int16_t i_uid;
124 u_int16_t i_gid;
125 u_int32_t i_size;
126 u_int32_t i_atime;
127 u_int32_t i_mtime;
128 u_int32_t i_ctime;
129 u_int32_t i_zone[10];
130};
131
132/*
133 * minix super-block data on disk
134 */
135struct minix_super_block {
136 u_int16_t s_ninodes;
137 u_int16_t s_nzones;
138 u_int16_t s_imap_blocks;
139 u_int16_t s_zmap_blocks;
140 u_int16_t s_firstdatazone;
141 u_int16_t s_log_zone_size;
142 u_int32_t s_max_size;
143 u_int16_t s_magic;
144 u_int16_t s_state;
145 u_int32_t s_zones;
146};
147
148struct minix_dir_entry {
149 u_int16_t inode;
150 char name[0];
151};
152
153#define BLOCK_SIZE_BITS 10
154#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
155
156#define NAME_MAX 255 /* # chars in a file name */
157
158#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
159
160#define MINIX_VALID_FS 0x0001 /* Clean fs. */
161#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
162
163#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
164#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
165
166#ifndef BLKGETSIZE
167#define BLKGETSIZE _IO(0x12,96) /* return device size */
168#endif
169
170
171#ifndef __linux__
172#define volatile
173#endif
174
175#define MINIX_ROOT_INO 1
176#define MINIX_BAD_INO 2
177
178#define TEST_BUFFER_BLOCKS 16
179#define MAX_GOOD_BLOCKS 512
180
181#define UPPER(size,n) (((size)+((n)-1))/(n))
182#define INODE_SIZE (sizeof(struct minix_inode))
183#ifdef BB_FEATURE_MINIX2
184#define INODE_SIZE2 (sizeof(struct minix2_inode))
185#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
186 : MINIX_INODES_PER_BLOCK))
187#else
188#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
189#endif
190#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
191
192#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
193
194static char *device_name = NULL;
195static int DEV = -1;
196static long BLOCKS = 0;
197static int check = 0;
198static int badblocks = 0;
199static int namelen = 30; /* default (changed to 30, per Linus's
200
201 suggestion, Sun Nov 21 08:05:07 1993) */
202static int dirsize = 32;
203static int magic = MINIX_SUPER_MAGIC2;
204static int version2 = 0;
205
206static char root_block[BLOCK_SIZE] = "\0";
207
208static char *inode_buffer = NULL;
209
210#define Inode (((struct minix_inode *) inode_buffer)-1)
211#ifdef BB_FEATURE_MINIX2
212#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
213#endif
214static char super_block_buffer[BLOCK_SIZE];
215static char boot_block_buffer[512];
216
217#define Super (*(struct minix_super_block *)super_block_buffer)
218#define INODES ((unsigned long)Super.s_ninodes)
219#ifdef BB_FEATURE_MINIX2
220#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
221#else
222#define ZONES ((unsigned long)(Super.s_nzones))
223#endif
224#define IMAPS ((unsigned long)Super.s_imap_blocks)
225#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
226#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
227#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
228#define MAXSIZE ((unsigned long)Super.s_max_size)
229#define MAGIC (Super.s_magic)
230#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
231
232static char *inode_map;
233static char *zone_map;
234
235static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
236static int used_good_blocks = 0;
237static unsigned long req_nr_inodes = 0;
238
239static inline int bit(char * a,unsigned int i)
240{
241 return (a[i >> 3] & (1<<(i & 7))) != 0;
242}
243#define inode_in_use(x) (bit(inode_map,(x)))
244#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
245
246#define mark_inode(x) (setbit(inode_map,(x)))
247#define unmark_inode(x) (clrbit(inode_map,(x)))
248
249#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1))
250#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1))
251
252/*
253 * Check to make certain that our new filesystem won't be created on
254 * an already mounted partition. Code adapted from mke2fs, Copyright
255 * (C) 1994 Theodore Ts'o. Also licensed under GPL.
256 */
257static void check_mount(void)
258{
259 FILE *f;
260 struct mntent *mnt;
261
262 if ((f = setmntent(MOUNTED, "r")) == NULL)
263 return;
264 while ((mnt = getmntent(f)) != NULL)
265 if (strcmp(device_name, mnt->mnt_fsname) == 0)
266 break;
267 endmntent(f);
268 if (!mnt)
269 return;
270
271 error_msg_and_die("%s is mounted; will not make a filesystem here!", device_name);
272}
273
274static long valid_offset(int fd, int offset)
275{
276 char ch;
277
278 if (lseek(fd, offset, 0) < 0)
279 return 0;
280 if (read(fd, &ch, 1) < 1)
281 return 0;
282 return 1;
283}
284
285static int count_blocks(int fd)
286{
287 int high, low;
288
289 low = 0;
290 for (high = 1; valid_offset(fd, high); high *= 2)
291 low = high;
292 while (low < high - 1) {
293 const int mid = (low + high) / 2;
294
295 if (valid_offset(fd, mid))
296 low = mid;
297 else
298 high = mid;
299 }
300 valid_offset(fd, 0);
301 return (low + 1);
302}
303
304static int get_size(const char *file)
305{
306 int fd;
307 long size;
308
309 if ((fd = open(file, O_RDWR)) < 0)
310 perror_msg_and_die("%s", file);
311 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
312 close(fd);
313 return (size * 512);
314 }
315
316 size = count_blocks(fd);
317 close(fd);
318 return size;
319}
320
321static void write_tables(void)
322{
323 /* Mark the super block valid. */
324 Super.s_state |= MINIX_VALID_FS;
325 Super.s_state &= ~MINIX_ERROR_FS;
326
327 if (lseek(DEV, 0, SEEK_SET))
328 error_msg_and_die("seek to boot block failed in write_tables");
329 if (512 != write(DEV, boot_block_buffer, 512))
330 error_msg_and_die("unable to clear boot sector");
331 if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET))
332 error_msg_and_die("seek failed in write_tables");
333 if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE))
334 error_msg_and_die("unable to write super-block");
335 if (IMAPS * BLOCK_SIZE != write(DEV, inode_map, IMAPS * BLOCK_SIZE))
336 error_msg_and_die("unable to write inode map");
337 if (ZMAPS * BLOCK_SIZE != write(DEV, zone_map, ZMAPS * BLOCK_SIZE))
338 error_msg_and_die("unable to write zone map");
339 if (INODE_BUFFER_SIZE != write(DEV, inode_buffer, INODE_BUFFER_SIZE))
340 error_msg_and_die("unable to write inodes");
341
342}
343
344static void write_block(int blk, char *buffer)
345{
346 if (blk * BLOCK_SIZE != lseek(DEV, blk * BLOCK_SIZE, SEEK_SET))
347 error_msg_and_die("seek failed in write_block");
348 if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE))
349 error_msg_and_die("write failed in write_block");
350}
351
352static int get_free_block(void)
353{
354 int blk;
355
356 if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
357 error_msg_and_die("too many bad blocks");
358 if (used_good_blocks)
359 blk = good_blocks_table[used_good_blocks - 1] + 1;
360 else
361 blk = FIRSTZONE;
362 while (blk < ZONES && zone_in_use(blk))
363 blk++;
364 if (blk >= ZONES)
365 error_msg_and_die("not enough good blocks");
366 good_blocks_table[used_good_blocks] = blk;
367 used_good_blocks++;
368 return blk;
369}
370
371static void mark_good_blocks(void)
372{
373 int blk;
374
375 for (blk = 0; blk < used_good_blocks; blk++)
376 mark_zone(good_blocks_table[blk]);
377}
378
379static int next(int zone)
380{
381 if (!zone)
382 zone = FIRSTZONE - 1;
383 while (++zone < ZONES)
384 if (zone_in_use(zone))
385 return zone;
386 return 0;
387}
388
389static void make_bad_inode(void)
390{
391 struct minix_inode *inode = &Inode[MINIX_BAD_INO];
392 int i, j, zone;
393 int ind = 0, dind = 0;
394 unsigned short ind_block[BLOCK_SIZE >> 1];
395 unsigned short dind_block[BLOCK_SIZE >> 1];
396
397#define NEXT_BAD (zone = next(zone))
398
399 if (!badblocks)
400 return;
401 mark_inode(MINIX_BAD_INO);
402 inode->i_nlinks = 1;
403 inode->i_time = time(NULL);
404 inode->i_mode = S_IFREG + 0000;
405 inode->i_size = badblocks * BLOCK_SIZE;
406 zone = next(0);
407 for (i = 0; i < 7; i++) {
408 inode->i_zone[i] = zone;
409 if (!NEXT_BAD)
410 goto end_bad;
411 }
412 inode->i_zone[7] = ind = get_free_block();
413 memset(ind_block, 0, BLOCK_SIZE);
414 for (i = 0; i < 512; i++) {
415 ind_block[i] = zone;
416 if (!NEXT_BAD)
417 goto end_bad;
418 }
419 inode->i_zone[8] = dind = get_free_block();
420 memset(dind_block, 0, BLOCK_SIZE);
421 for (i = 0; i < 512; i++) {
422 write_block(ind, (char *) ind_block);
423 dind_block[i] = ind = get_free_block();
424 memset(ind_block, 0, BLOCK_SIZE);
425 for (j = 0; j < 512; j++) {
426 ind_block[j] = zone;
427 if (!NEXT_BAD)
428 goto end_bad;
429 }
430 }
431 error_msg_and_die("too many bad blocks");
432 end_bad:
433 if (ind)
434 write_block(ind, (char *) ind_block);
435 if (dind)
436 write_block(dind, (char *) dind_block);
437}
438
439#ifdef BB_FEATURE_MINIX2
440static void make_bad_inode2(void)
441{
442 struct minix2_inode *inode = &Inode2[MINIX_BAD_INO];
443 int i, j, zone;
444 int ind = 0, dind = 0;
445 unsigned long ind_block[BLOCK_SIZE >> 2];
446 unsigned long dind_block[BLOCK_SIZE >> 2];
447
448 if (!badblocks)
449 return;
450 mark_inode(MINIX_BAD_INO);
451 inode->i_nlinks = 1;
452 inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
453 inode->i_mode = S_IFREG + 0000;
454 inode->i_size = badblocks * BLOCK_SIZE;
455 zone = next(0);
456 for (i = 0; i < 7; i++) {
457 inode->i_zone[i] = zone;
458 if (!NEXT_BAD)
459 goto end_bad;
460 }
461 inode->i_zone[7] = ind = get_free_block();
462 memset(ind_block, 0, BLOCK_SIZE);
463 for (i = 0; i < 256; i++) {
464 ind_block[i] = zone;
465 if (!NEXT_BAD)
466 goto end_bad;
467 }
468 inode->i_zone[8] = dind = get_free_block();
469 memset(dind_block, 0, BLOCK_SIZE);
470 for (i = 0; i < 256; i++) {
471 write_block(ind, (char *) ind_block);
472 dind_block[i] = ind = get_free_block();
473 memset(ind_block, 0, BLOCK_SIZE);
474 for (j = 0; j < 256; j++) {
475 ind_block[j] = zone;
476 if (!NEXT_BAD)
477 goto end_bad;
478 }
479 }
480 /* Could make triple indirect block here */
481 error_msg_and_die("too many bad blocks");
482 end_bad:
483 if (ind)
484 write_block(ind, (char *) ind_block);
485 if (dind)
486 write_block(dind, (char *) dind_block);
487}
488#endif
489
490static void make_root_inode(void)
491{
492 struct minix_inode *inode = &Inode[MINIX_ROOT_INO];
493
494 mark_inode(MINIX_ROOT_INO);
495 inode->i_zone[0] = get_free_block();
496 inode->i_nlinks = 2;
497 inode->i_time = time(NULL);
498 if (badblocks)
499 inode->i_size = 3 * dirsize;
500 else {
501 root_block[2 * dirsize] = '\0';
502 root_block[2 * dirsize + 1] = '\0';
503 inode->i_size = 2 * dirsize;
504 }
505 inode->i_mode = S_IFDIR + 0755;
506 inode->i_uid = getuid();
507 if (inode->i_uid)
508 inode->i_gid = getgid();
509 write_block(inode->i_zone[0], root_block);
510}
511
512#ifdef BB_FEATURE_MINIX2
513static void make_root_inode2(void)
514{
515 struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO];
516
517 mark_inode(MINIX_ROOT_INO);
518 inode->i_zone[0] = get_free_block();
519 inode->i_nlinks = 2;
520 inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
521 if (badblocks)
522 inode->i_size = 3 * dirsize;
523 else {
524 root_block[2 * dirsize] = '\0';
525 root_block[2 * dirsize + 1] = '\0';
526 inode->i_size = 2 * dirsize;
527 }
528 inode->i_mode = S_IFDIR + 0755;
529 inode->i_uid = getuid();
530 if (inode->i_uid)
531 inode->i_gid = getgid();
532 write_block(inode->i_zone[0], root_block);
533}
534#endif
535
536static void setup_tables(void)
537{
538 int i;
539 unsigned long inodes;
540
541 memset(super_block_buffer, 0, BLOCK_SIZE);
542 memset(boot_block_buffer, 0, 512);
543 MAGIC = magic;
544 ZONESIZE = 0;
545 MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
546 ZONES = BLOCKS;
547/* some magic nrs: 1 inode / 3 blocks */
548 if (req_nr_inodes == 0)
549 inodes = BLOCKS / 3;
550 else
551 inodes = req_nr_inodes;
552 /* Round up inode count to fill block size */
553#ifdef BB_FEATURE_MINIX2
554 if (version2)
555 inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) &
556 ~(MINIX2_INODES_PER_BLOCK - 1));
557 else
558#endif
559 inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) &
560 ~(MINIX_INODES_PER_BLOCK - 1));
561 if (inodes > 65535)
562 inodes = 65535;
563 INODES = inodes;
564 IMAPS = UPPER(INODES + 1, BITS_PER_BLOCK);
565 ZMAPS = 0;
566 i = 0;
567 while (ZMAPS !=
568 UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
569 BITS_PER_BLOCK) && i < 1000) {
570 ZMAPS =
571 UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
572 BITS_PER_BLOCK);
573 i++;
574 }
575 /* Real bad hack but overwise mkfs.minix can be thrown
576 * in infinite loop...
577 * try:
578 * dd if=/dev/zero of=test.fs count=10 bs=1024
579 * /sbin/mkfs.minix -i 200 test.fs
580 * */
581 if (i >= 999) {
582 error_msg_and_die("unable to allocate buffers for maps");
583 }
584 FIRSTZONE = NORM_FIRSTZONE;
585 inode_map = xmalloc(IMAPS * BLOCK_SIZE);
586 zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
587 memset(inode_map, 0xff, IMAPS * BLOCK_SIZE);
588 memset(zone_map, 0xff, ZMAPS * BLOCK_SIZE);
589 for (i = FIRSTZONE; i < ZONES; i++)
590 unmark_zone(i);
591 for (i = MINIX_ROOT_INO; i <= INODES; i++)
592 unmark_inode(i);
593 inode_buffer = xmalloc(INODE_BUFFER_SIZE);
594 memset(inode_buffer, 0, INODE_BUFFER_SIZE);
595 printf("%ld inodes\n", INODES);
596 printf("%ld blocks\n", ZONES);
597 printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
598 printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
599 printf("Maxsize=%ld\n\n", MAXSIZE);
600}
601
602/*
603 * Perform a test of a block; return the number of
604 * blocks readable/writeable.
605 */
606static long do_check(char *buffer, int try, unsigned int current_block)
607{
608 long got;
609
610 /* Seek to the correct loc. */
611 if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) !=
612 current_block * BLOCK_SIZE) {
613 error_msg_and_die("seek failed during testing of blocks");
614 }
615
616
617 /* Try the read */
618 got = read(DEV, buffer, try * BLOCK_SIZE);
619 if (got < 0)
620 got = 0;
621 if (got & (BLOCK_SIZE - 1)) {
622 printf("Weird values in do_check: probably bugs\n");
623 }
624 got /= BLOCK_SIZE;
625 return got;
626}
627
628static unsigned int currently_testing = 0;
629
630static void alarm_intr(int alnum)
631{
632 if (currently_testing >= ZONES)
633 return;
634 signal(SIGALRM, alarm_intr);
635 alarm(5);
636 if (!currently_testing)
637 return;
638 printf("%d ...", currently_testing);
639 fflush(stdout);
640}
641
642static void check_blocks(void)
643{
644 int try, got;
645 static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
646
647 currently_testing = 0;
648 signal(SIGALRM, alarm_intr);
649 alarm(5);
650 while (currently_testing < ZONES) {
651 if (lseek(DEV, currently_testing * BLOCK_SIZE, SEEK_SET) !=
652 currently_testing * BLOCK_SIZE)
653 error_msg_and_die("seek failed in check_blocks");
654 try = TEST_BUFFER_BLOCKS;
655 if (currently_testing + try > ZONES)
656 try = ZONES - currently_testing;
657 got = do_check(buffer, try, currently_testing);
658 currently_testing += got;
659 if (got == try)
660 continue;
661 if (currently_testing < FIRSTZONE)
662 error_msg_and_die("bad blocks before data-area: cannot make fs");
663 mark_zone(currently_testing);
664 badblocks++;
665 currently_testing++;
666 }
667 if (badblocks > 1)
668 printf("%d bad blocks\n", badblocks);
669 else if (badblocks == 1)
670 printf("one bad block\n");
671}
672
673static void get_list_blocks(filename)
674char *filename;
675
676{
677 FILE *listfile;
678 unsigned long blockno;
679
680 listfile = xfopen(filename, "r");
681 while (!feof(listfile)) {
682 fscanf(listfile, "%ld\n", &blockno);
683 mark_zone(blockno);
684 badblocks++;
685 }
686 if (badblocks > 1)
687 printf("%d bad blocks\n", badblocks);
688 else if (badblocks == 1)
689 printf("one bad block\n");
690}
691
692extern int mkfs_minix_main(int argc, char **argv)
693{
694 int i=1;
695 char *tmp;
696 struct stat statbuf;
697 char *listfile = NULL;
698 int stopIt=FALSE;
699
700 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
701 error_msg_and_die("bad inode size");
702#ifdef BB_FEATURE_MINIX2
703 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
704 error_msg_and_die("bad inode size");
705#endif
706
707 /* Parse options */
708 argv++;
709 while (--argc >= 0 && *argv && **argv) {
710 if (**argv == '-') {
711 stopIt=FALSE;
712 while (i > 0 && *++(*argv) && stopIt==FALSE) {
713 switch (**argv) {
714 case 'c':
715 check = 1;
716 break;
717 case 'i':
718 {
719 char *cp=NULL;
720 if (*(*argv+1) != 0) {
721 cp = ++(*argv);
722 } else {
723 if (--argc == 0) {
724 goto goodbye;
725 }
726 cp = *(++argv);
727 }
728 req_nr_inodes = strtoul(cp, &tmp, 0);
729 if (*tmp)
730 show_usage();
731 stopIt=TRUE;
732 break;
733 }
734 case 'l':
735 if (--argc == 0) {
736 goto goodbye;
737 }
738 listfile = *(++argv);
739 break;
740 case 'n':
741 {
742 char *cp=NULL;
743
744 if (*(*argv+1) != 0) {
745 cp = ++(*argv);
746 } else {
747 if (--argc == 0) {
748 goto goodbye;
749 }
750 cp = *(++argv);
751 }
752 i = strtoul(cp, &tmp, 0);
753 if (*tmp)
754 show_usage();
755 if (i == 14)
756 magic = MINIX_SUPER_MAGIC;
757 else if (i == 30)
758 magic = MINIX_SUPER_MAGIC2;
759 else
760 show_usage();
761 namelen = i;
762 dirsize = i + 2;
763 stopIt=TRUE;
764 break;
765 }
766 case 'v':
767#ifdef BB_FEATURE_MINIX2
768 version2 = 1;
769#else
770 error_msg("%s: not compiled with minix v2 support",
771 device_name);
772 exit(-1);
773#endif
774 break;
775 case '-':
776 case 'h':
777 default:
778goodbye:
779 show_usage();
780 }
781 }
782 } else {
783 if (device_name == NULL)
784 device_name = *argv;
785 else if (BLOCKS == 0)
786 BLOCKS = strtol(*argv, &tmp, 0);
787 else {
788 goto goodbye;
789 }
790 }
791 argv++;
792 }
793
794 if (device_name && !BLOCKS)
795 BLOCKS = get_size(device_name) / 1024;
796 if (!device_name || BLOCKS < 10) {
797 show_usage();
798 }
799#ifdef BB_FEATURE_MINIX2
800 if (version2) {
801 if (namelen == 14)
802 magic = MINIX2_SUPER_MAGIC;
803 else
804 magic = MINIX2_SUPER_MAGIC2;
805 } else
806#endif
807 if (BLOCKS > 65535)
808 BLOCKS = 65535;
809 check_mount(); /* is it already mounted? */
810 tmp = root_block;
811 *(short *) tmp = 1;
812 strcpy(tmp + 2, ".");
813 tmp += dirsize;
814 *(short *) tmp = 1;
815 strcpy(tmp + 2, "..");
816 tmp += dirsize;
817 *(short *) tmp = 2;
818 strcpy(tmp + 2, ".badblocks");
819 DEV = open(device_name, O_RDWR);
820 if (DEV < 0)
821 error_msg_and_die("unable to open %s", device_name);
822 if (fstat(DEV, &statbuf) < 0)
823 error_msg_and_die("unable to stat %s", device_name);
824 if (!S_ISBLK(statbuf.st_mode))
825 check = 0;
826 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
827 error_msg_and_die("will not try to make filesystem on '%s'", device_name);
828 setup_tables();
829 if (check)
830 check_blocks();
831 else if (listfile)
832 get_list_blocks(listfile);
833#ifdef BB_FEATURE_MINIX2
834 if (version2) {
835 make_root_inode2();
836 make_bad_inode2();
837 } else
838#endif
839 {
840 make_root_inode();
841 make_bad_inode();
842 }
843 mark_good_blocks();
844 write_tables();
845 return( 0);
846
847}
diff --git a/mknod.c b/mknod.c
deleted file mode 100644
index b4d4b82a1..000000000
--- a/mknod.c
+++ /dev/null
@@ -1,92 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini mknod implementation for busybox
4 *
5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <errno.h>
25#include <fcntl.h>
26#include <unistd.h>
27#include <string.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include "busybox.h"
31
32int mknod_main(int argc, char **argv)
33{
34 char *thisarg;
35 mode_t mode = 0;
36 mode_t perm = 0666;
37 dev_t dev = 0;
38
39 argc--;
40 argv++;
41
42 /* Parse any options */
43 while (argc > 1) {
44 if (**argv != '-')
45 break;
46 thisarg = *argv;
47 thisarg++;
48 switch (*thisarg) {
49 case 'm':
50 argc--;
51 argv++;
52 parse_mode(*argv, &perm);
53 umask(0);
54 break;
55 default:
56 show_usage();
57 }
58 argc--;
59 argv++;
60 }
61 if (argc != 4 && argc != 2) {
62 show_usage();
63 }
64 switch (argv[1][0]) {
65 case 'c':
66 case 'u':
67 mode = S_IFCHR;
68 break;
69 case 'b':
70 mode = S_IFBLK;
71 break;
72 case 'p':
73 mode = S_IFIFO;
74 if (argc!=2) {
75 show_usage();
76 }
77 break;
78 default:
79 show_usage();
80 }
81
82 if (mode == S_IFCHR || mode == S_IFBLK) {
83 dev = (atoi(argv[2]) << 8) | atoi(argv[3]);
84 }
85
86 mode |= perm;
87
88 if (mknod(argv[0], mode, dev) != 0)
89 perror_msg_and_die("%s", argv[0]);
90 return EXIT_SUCCESS;
91}
92
diff --git a/mkswap.c b/mkswap.c
deleted file mode 100644
index c773ecef9..000000000
--- a/mkswap.c
+++ /dev/null
@@ -1,422 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mkswap.c - set up a linux swap device
4 *
5 * (C) 1991 Linus Torvalds. This file may be redistributed as per
6 * the Linux copyright.
7 */
8
9/*
10 * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
11 *
12 * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks]
13 *
14 * -c for readability checking. (Use it unless you are SURE!)
15 * -vN for swap areas version N. (Only N=0,1 known today.)
16 * -f for forcing swap creation even if it would smash partition table.
17 *
18 * The device may be a block device or an image of one, but this isn't
19 * enforced (but it's not much fun on a character device :-).
20 *
21 * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
22 * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995.
23 *
24 * Version 1 swap area code (for kernel 2.1.117), aeb, 981010.
25 *
26 * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb.
27 * V1_MAX_PAGES fixes, jj, 990325.
28 *
29 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
30 * - added Native Language Support
31 *
32 * from util-linux -- adapted for busybox by
33 * Erik Andersen <andersee@debian.org>. I ripped out Native Language
34 * Support, made some stuff smaller, and fitted for life in busybox.
35 *
36 */
37
38#include <stdio.h>
39#include <unistd.h>
40#include <string.h>
41#include <fcntl.h>
42#include <stdlib.h>
43#include <sys/ioctl.h> /* for _IO */
44#include <sys/utsname.h>
45#include <asm/page.h> /* for PAGE_SIZE and PAGE_SHIFT */
46 /* we also get PAGE_SIZE via getpagesize() */
47#include "busybox.h"
48
49#ifndef _IO
50/* pre-1.3.45 */
51static const int BLKGETSIZE = 0x1260;
52#else
53/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
54#define BLKGETSIZE _IO(0x12,96)
55#endif
56
57static char *device_name = NULL;
58static int DEV = -1;
59static long PAGES = 0;
60static int check = 0;
61static int badpages = 0;
62static int version = -1;
63
64#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
65
66/*
67 * The definition of the union swap_header uses the constant PAGE_SIZE.
68 * Unfortunately, on some architectures this depends on the hardware model,
69 * and can only be found at run time -- we use getpagesize().
70 */
71
72static int pagesize;
73static int *signature_page;
74
75static struct swap_header_v1 {
76 char bootbits[1024]; /* Space for disklabel etc. */
77 unsigned int version;
78 unsigned int last_page;
79 unsigned int nr_badpages;
80 unsigned int padding[125];
81 unsigned int badpages[1];
82} *p;
83
84static void init_signature_page(void)
85{
86 pagesize = getpagesize();
87
88#ifdef PAGE_SIZE
89 if (pagesize != PAGE_SIZE)
90 error_msg("Assuming pages of size %d", pagesize);
91#endif
92 signature_page = (int *) xmalloc(pagesize);
93 memset(signature_page, 0, pagesize);
94 p = (struct swap_header_v1 *) signature_page;
95}
96
97static void write_signature(char *sig)
98{
99 char *sp = (char *) signature_page;
100
101 strncpy(sp + pagesize - 10, sig, 10);
102}
103
104#define V0_MAX_PAGES (8 * (pagesize - 10))
105/* Before 2.2.0pre9 */
106#define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1)
107/* Since 2.2.0pre9:
108 error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
109 with variations on
110 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
111 #define SWP_OFFSET(entry) ((entry) >> 8)
112 on the various architectures. Below the result - yuk.
113
114 Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2
115 i386 2^12 o<<8 e>>8 1<<24 1<<19
116 mips 2^12 o<<15 e>>15 1<<17 1<<19
117 alpha 2^13 o<<40 e>>40 1<<24 1<<18
118 m68k 2^12 o<<12 e>>12 1<<20 1<<19
119 sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18}
120 sparc64 2^13 o<<13 e>>13 1<<51 1<<18
121 ppc 2^12 o<<8 e>>8 1<<24 1<<19
122 armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16}
123 armv 2^12 o<<9 e>>9 1<<23 1<<19
124
125 assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
126
127 The bad part is that we need to know this since the kernel will
128 refuse a swap space if it is too large.
129*/
130/* patch from jj - why does this differ from the above? */
131#if defined(__alpha__)
132#define V1_MAX_PAGES ((1 << 24) - 1)
133#elif defined(__mips__)
134#define V1_MAX_PAGES ((1 << 17) - 1)
135#elif defined(__sparc_v9__)
136#define V1_MAX_PAGES ((3 << 29) - 1)
137#elif defined(__sparc__)
138#define V1_MAX_PAGES (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1))
139#else
140#define V1_MAX_PAGES V1_OLD_MAX_PAGES
141#endif
142/* man page now says:
143The maximum useful size of a swap area now depends on the architecture.
144It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
145128GB on alpha and 3TB on sparc64.
146*/
147
148#define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
149
150static void bit_set(unsigned int *addr, unsigned int nr)
151{
152 unsigned int r, m;
153
154 addr += nr / (8 * sizeof(int));
155
156 r = *addr;
157 m = 1 << (nr & (8 * sizeof(int) - 1));
158
159 *addr = r | m;
160}
161
162static int bit_test_and_clear(unsigned int *addr, unsigned int nr)
163{
164 unsigned int r, m;
165
166 addr += nr / (8 * sizeof(int));
167
168 r = *addr;
169 m = 1 << (nr & (8 * sizeof(int) - 1));
170
171 *addr = r & ~m;
172 return (r & m) != 0;
173}
174
175
176static void page_ok(int page)
177{
178 if (version == 0)
179 bit_set(signature_page, page);
180}
181
182static void page_bad(int page)
183{
184 if (version == 0)
185 bit_test_and_clear(signature_page, page);
186 else {
187 if (badpages == MAX_BADPAGES)
188 error_msg_and_die("too many bad pages");
189 p->badpages[badpages] = page;
190 }
191 badpages++;
192}
193
194static void check_blocks(void)
195{
196 unsigned int current_page;
197 int do_seek = 1;
198 char *buffer;
199
200 buffer = xmalloc(pagesize);
201 current_page = 0;
202 while (current_page < PAGES) {
203 if (!check) {
204 page_ok(current_page++);
205 continue;
206 }
207 if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) !=
208 current_page * pagesize)
209 error_msg_and_die("seek failed in check_blocks");
210 if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
211 page_bad(current_page++);
212 continue;
213 }
214 page_ok(current_page++);
215 }
216 if (badpages == 1)
217 printf("one bad page\n");
218 else if (badpages > 1)
219 printf("%d bad pages\n", badpages);
220}
221
222static long valid_offset(int fd, int offset)
223{
224 char ch;
225
226 if (lseek(fd, offset, 0) < 0)
227 return 0;
228 if (read(fd, &ch, 1) < 1)
229 return 0;
230 return 1;
231}
232
233static int find_size(int fd)
234{
235 unsigned int high, low;
236
237 low = 0;
238 for (high = 1; high > 0 && valid_offset(fd, high); high *= 2)
239 low = high;
240 while (low < high - 1) {
241 const int mid = (low + high) / 2;
242
243 if (valid_offset(fd, mid))
244 low = mid;
245 else
246 high = mid;
247 }
248 return (low + 1);
249}
250
251/* return size in pages, to avoid integer overflow */
252static long get_size(const char *file)
253{
254 int fd;
255 long size;
256
257 if ((fd = open(file, O_RDONLY)) < 0)
258 perror_msg_and_die("%s", file);
259 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
260 int sectors_per_page = pagesize / 512;
261
262 size /= sectors_per_page;
263 } else {
264 size = find_size(fd) / pagesize;
265 }
266 close(fd);
267 return size;
268}
269
270int mkswap_main(int argc, char **argv)
271{
272 char *tmp;
273 struct stat statbuf;
274 int sz;
275 int maxpages;
276 int goodpages;
277 int offset;
278 int force = 0;
279
280 init_signature_page(); /* get pagesize */
281
282 while (argc-- > 1) {
283 argv++;
284 if (argv[0][0] != '-') {
285 if (device_name) {
286 int blocks_per_page = pagesize / 1024;
287
288 PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page;
289 if (*tmp)
290 show_usage();
291 } else
292 device_name = argv[0];
293 } else {
294 switch (argv[0][1]) {
295 case 'c':
296 check = 1;
297 break;
298 case 'f':
299 force = 1;
300 break;
301 case 'v':
302 version = atoi(argv[0] + 2);
303 break;
304 default:
305 show_usage();
306 }
307 }
308 }
309 if (!device_name) {
310 error_msg("error: Nowhere to set up swap on?");
311 show_usage();
312 }
313 sz = get_size(device_name);
314 if (!PAGES) {
315 PAGES = sz;
316 } else if (PAGES > sz && !force) {
317 error_msg("error: size %ld is larger than device size %d",
318 PAGES * (pagesize / 1024), sz * (pagesize / 1024));
319 return EXIT_FAILURE;
320 }
321
322 if (version == -1) {
323 if (PAGES <= V0_MAX_PAGES)
324 version = 0;
325 else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
326 version = 0;
327 else if (pagesize < 2048)
328 version = 0;
329 else
330 version = 1;
331 }
332 if (version != 0 && version != 1) {
333 error_msg("error: unknown version %d", version);
334 show_usage();
335 }
336 if (PAGES < 10) {
337 error_msg("error: swap area needs to be at least %ldkB",
338 (long) (10 * pagesize / 1024));
339 show_usage();
340 }
341#if 0
342 maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
343#else
344 if (!version)
345 maxpages = V0_MAX_PAGES;
346 else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1))
347 maxpages = V1_MAX_PAGES;
348 else {
349 maxpages = V1_OLD_MAX_PAGES;
350 if (maxpages > V1_MAX_PAGES)
351 maxpages = V1_MAX_PAGES;
352 }
353#endif
354 if (PAGES > maxpages) {
355 PAGES = maxpages;
356 error_msg("warning: truncating swap area to %ldkB",
357 PAGES * pagesize / 1024);
358 }
359
360 DEV = open(device_name, O_RDWR);
361 if (DEV < 0 || fstat(DEV, &statbuf) < 0)
362 perror_msg_and_die("%s", device_name);
363 if (!S_ISBLK(statbuf.st_mode))
364 check = 0;
365 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
366 error_msg_and_die("Will not try to make swapdevice on '%s'", device_name);
367
368#ifdef __sparc__
369 if (!force && version == 0) {
370 /* Don't overwrite partition table unless forced */
371 unsigned char *buffer = (unsigned char *) signature_page;
372 unsigned short *q, sum;
373
374 if (read(DEV, buffer, 512) != 512)
375 error_msg_and_die("fatal: first page unreadable");
376 if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
377 q = (unsigned short *) (buffer + 510);
378 for (sum = 0; q >= (unsigned short *) buffer;)
379 sum ^= *q--;
380 if (!sum) {
381 error_msg("Device '%s' contains a valid Sun disklabel.\n"
382"This probably means creating v0 swap would destroy your partition table\n"
383"No swap created. If you really want to create swap v0 on that device, use\n"
384"the -f option to force it.", device_name);
385 return EXIT_FAILURE;
386 }
387 }
388 }
389#endif
390
391 if (version == 0 || check)
392 check_blocks();
393 if (version == 0 && !bit_test_and_clear(signature_page, 0))
394 error_msg_and_die("fatal: first page unreadable");
395 if (version == 1) {
396 p->version = version;
397 p->last_page = PAGES - 1;
398 p->nr_badpages = badpages;
399 }
400
401 goodpages = PAGES - badpages - 1;
402 if (goodpages <= 0)
403 error_msg_and_die("Unable to set up swap-space: unreadable");
404 printf("Setting up swapspace version %d, size = %ld bytes\n",
405 version, (long) (goodpages * pagesize));
406 write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
407
408 offset = ((version == 0) ? 0 : 1024);
409 if (lseek(DEV, offset, SEEK_SET) != offset)
410 error_msg_and_die("unable to rewind swap-device");
411 if (write(DEV, (char *) signature_page + offset, pagesize - offset)
412 != pagesize - offset)
413 error_msg_and_die("unable to write signature page");
414
415 /*
416 * A subsequent swapon() will fail if the signature
417 * is not actually on disk. (This is a kernel bug.)
418 */
419 if (fsync(DEV))
420 error_msg_and_die("fsync failed");
421 return EXIT_SUCCESS;
422}
diff --git a/mktemp.c b/mktemp.c
deleted file mode 100644
index bc47d0af0..000000000
--- a/mktemp.c
+++ /dev/null
@@ -1,40 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini mktemp implementation for busybox
4 *
5 *
6 * Copyright (C) 2000 by Daniel Jacobowitz
7 * Written by Daniel Jacobowitz <dan@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <errno.h>
27#include <string.h>
28#include <unistd.h>
29#include <stdlib.h>
30#include "busybox.h"
31
32extern int mktemp_main(int argc, char **argv)
33{
34 if (argc != 2 && (argc != 3 || strcmp(argv[1], "-q")))
35 show_usage();
36 if(mkstemp(argv[argc-1]) < 0)
37 return EXIT_FAILURE;
38 (void) puts(argv[argc-1]);
39 return EXIT_SUCCESS;
40}
diff --git a/modprobe.c b/modprobe.c
deleted file mode 100644
index 05b40c53f..000000000
--- a/modprobe.c
+++ /dev/null
@@ -1,121 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * really dumb modprobe implementation for busybox
4 * Copyright (C) 2001 Lineo, davidm@lineo.com
5 */
6
7#include <stdio.h>
8#include <getopt.h>
9#include <stdlib.h>
10#include <unistd.h>
11#include <syslog.h>
12#include <string.h>
13#include "busybox.h"
14
15static char cmd[128];
16
17extern int modprobe_main(int argc, char** argv)
18{
19 int ch, rc = 0;
20 int loadall = 0, showconfig = 0, debug = 0, autoclean = 0, list = 0;
21 int show_only = 0, quiet = 0, remove_opt = 0, do_syslog = 0, verbose = 0;
22 char *load_type = NULL, *config = NULL;
23
24 while ((ch = getopt(argc, argv, "acdklnqrst:vVC:")) != -1)
25 switch(ch) {
26 case 'a':
27 loadall++;
28 break;
29 case 'c':
30 showconfig++;
31 break;
32 case 'd':
33 debug++;
34 break;
35 case 'k':
36 autoclean++;
37 break;
38 case 'l':
39 list++;
40 break;
41 case 'n':
42 show_only++;
43 break;
44 case 'q':
45 quiet++;
46 break;
47 case 'r':
48 remove_opt++;
49 break;
50 case 's':
51 do_syslog++;
52 break;
53 case 't':
54 load_type = optarg;
55 break;
56 case 'v':
57 verbose++;
58 break;
59 case 'C':
60 config = optarg;
61 break;
62 case 'V':
63 default:
64 show_usage();
65 break;
66 }
67
68 if (load_type || config) {
69 fprintf(stderr, "-t and -C not supported\n");
70 exit(EXIT_FAILURE);
71 }
72
73 if (showconfig)
74 exit(EXIT_SUCCESS);
75
76 if (list)
77 exit(EXIT_SUCCESS);
78
79 if (remove_opt) {
80 do {
81 sprintf(cmd, "rmmod %s %s %s",
82 optind >= argc ? "-a" : "",
83 do_syslog ? "-s" : "",
84 optind < argc ? argv[optind] : "");
85 if (do_syslog)
86 syslog(LOG_INFO, "%s", cmd);
87 if (show_only || verbose)
88 printf("%s\n", cmd);
89 if (!show_only)
90 rc = system(cmd);
91 } while (++optind < argc);
92 exit(EXIT_SUCCESS);
93 }
94
95 if (optind >= argc) {
96 fprintf(stderr, "No module or pattern provided\n");
97 exit(EXIT_FAILURE);
98 }
99
100 sprintf(cmd, "insmod %s %s %s",
101 do_syslog ? "-s" : "",
102 quiet ? "-q" : "",
103 autoclean ? "-k" : "");
104 while (optind < argc) {
105 strcat(cmd, argv[optind]);
106 strcat(cmd, " ");
107 optind++;
108 }
109 if (do_syslog)
110 syslog(LOG_INFO, "%s", cmd);
111 if (show_only || verbose)
112 printf("%s\n", cmd);
113 if (!show_only)
114 rc = system(cmd);
115 else
116 rc = 0;
117
118 exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
119}
120
121
diff --git a/modutils/Makefile b/modutils/Makefile
new file mode 100644
index 000000000..7a8d4664e
--- /dev/null
+++ b/modutils/Makefile
@@ -0,0 +1,39 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := modutils.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27
28obj-$(CONFIG_INSMOD) += insmod.o
29obj-$(CONFIG_LSMOD) += lsmod.o
30obj-$(CONFIG_MODPROBE) += modprobe.o
31obj-$(CONFIG_RMMOD) += rmmod.o
32
33
34# Hand off to toplevel Rules.mak
35include $(TOPDIR)/Rules.mak
36
37clean:
38 rm -f $(L_TARGET) *.o core
39
diff --git a/modutils/config.in b/modutils/config.in
new file mode 100644
index 000000000..fc00e333a
--- /dev/null
+++ b/modutils/config.in
@@ -0,0 +1,22 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Module Utilities'
8
9
10bool 'insmod' CONFIG_INSMOD
11bool 'lsmod' CONFIG_LSMOD
12bool 'modprobe' CONFIG_MODPROBE
13bool 'rmmod' CONFIG_RMMOD
14
15if [ "$CONFIG_INSMOD" = "y" ]; then
16 bool 'Support insmod/lsmod/rmmod for post 2.1 kernels' CONFIG_FEATURE_NEW_MODULE_INTERFACE
17 bool 'Support insmod/lsmod/rmmod for pre 2.1 kernels' CONFIG_FEATURE_OLD_MODULE_INTERFACE
18 bool 'Support module version checking' CONFIG_FEATURE_INSMOD_VERSION_CHECKING
19fi
20
21endmenu
22
diff --git a/modutils/insmod.c b/modutils/insmod.c
index 6b81ca754..c21f22b74 100644
--- a/modutils/insmod.c
+++ b/modutils/insmod.c
@@ -5,9 +5,8 @@
5 * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, 5 * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k,
6 * and MIPS. 6 * and MIPS.
7 * 7 *
8 * 8 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
9 * Copyright (C) 1999,2000,2001 by Lineo, inc. 9 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
10 * Written by Erik Andersen <andersen@lineo.com>
11 * and Ron Alder <alder@lineo.com> 10 * and Ron Alder <alder@lineo.com>
12 * 11 *
13 * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4 12 * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
@@ -22,7 +21,7 @@
22 * PowerPC specific code stolen from modutils-2.3.16, 21 * PowerPC specific code stolen from modutils-2.3.16,
23 * written by Paul Mackerras, Copyright 1996, 1997 Linux International. 22 * written by Paul Mackerras, Copyright 1996, 1997 Linux International.
24 * I've only tested the code on mpc8xx platforms in big-endian mode. 23 * I've only tested the code on mpc8xx platforms in big-endian mode.
25 * Did some cleanup and added BB_USE_xxx_ENTRIES... 24 * Did some cleanup and added CONFIG_USE_xxx_ENTRIES...
26 * 25 *
27 * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001. 26 * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001.
28 * based on modutils-2.4.2 27 * based on modutils-2.4.2
@@ -66,39 +65,39 @@
66#include <sys/utsname.h> 65#include <sys/utsname.h>
67#include "busybox.h" 66#include "busybox.h"
68 67
69#ifdef BB_FEATURE_NEW_MODULE_INTERFACE 68#ifdef CONFIG_FEATURE_NEW_MODULE_INTERFACE
70# undef BB_FEATURE_OLD_MODULE_INTERFACE 69# undef CONFIG_FEATURE_OLD_MODULE_INTERFACE
71# define new_sys_init_module init_module 70# define new_sys_init_module init_module
72#else 71#else
73# define old_sys_init_module init_module 72# define old_sys_init_module init_module
74#endif 73#endif
75 74
76#ifdef BB_FEATURE_INSMOD_LOADINKMEM 75#ifdef CONFIG_FEATURE_INSMOD_LOADINKMEM
77#define LOADBITS 0 76#define LOADBITS 0
78#else 77#else
79#define LOADBITS 1 78#define LOADBITS 1
80#endif 79#endif
81 80
82#if defined(__powerpc__) 81#if defined(__powerpc__)
83#define BB_USE_PLT_ENTRIES 82#define CONFIG_USE_PLT_ENTRIES
84#define BB_PLT_ENTRY_SIZE 16 83#define CONFIG_PLT_ENTRY_SIZE 16
85#endif 84#endif
86 85
87#if defined(__arm__) 86#if defined(__arm__)
88#define BB_USE_PLT_ENTRIES 87#define CONFIG_USE_PLT_ENTRIES
89#define BB_PLT_ENTRY_SIZE 8 88#define CONFIG_PLT_ENTRY_SIZE 8
90#define BB_USE_GOT_ENTRIES 89#define CONFIG_USE_GOT_ENTRIES
91#define BB_GOT_ENTRY_SIZE 8 90#define CONFIG_GOT_ENTRY_SIZE 8
92#endif 91#endif
93 92
94#if defined(__sh__) 93#if defined(__sh__)
95#define BB_USE_GOT_ENTRIES 94#define CONFIG_USE_GOT_ENTRIES
96#define BB_GOT_ENTRY_SIZE 4 95#define CONFIG_GOT_ENTRY_SIZE 4
97#endif 96#endif
98 97
99#if defined(__i386__) 98#if defined(__i386__)
100#define BB_USE_GOT_ENTRIES 99#define CONFIG_USE_GOT_ENTRIES
101#define BB_GOT_ENTRY_SIZE 4 100#define CONFIG_GOT_ENTRY_SIZE 4
102#endif 101#endif
103 102
104#if defined(__mips__) 103#if defined(__mips__)
@@ -134,7 +133,7 @@
134#ifndef MODUTILS_MODULE_H 133#ifndef MODUTILS_MODULE_H
135static const int MODUTILS_MODULE_H = 1; 134static const int MODUTILS_MODULE_H = 1;
136 135
137#ident "$Id: insmod.c,v 1.73 2001/08/22 05:41:57 andersen Exp $" 136#ident "$Id: insmod.c,v 1.74 2001/10/24 04:59:54 andersen Exp $"
138 137
139/* This file contains the structures used by the 2.0 and 2.1 kernels. 138/* This file contains the structures used by the 2.0 and 2.1 kernels.
140 We do not use the kernel headers directly because we do not wish 139 We do not use the kernel headers directly because we do not wish
@@ -267,7 +266,7 @@ struct new_module
267 unsigned tgt_long persist_end; 266 unsigned tgt_long persist_end;
268 unsigned tgt_long can_unload; 267 unsigned tgt_long can_unload;
269 unsigned tgt_long runsize; 268 unsigned tgt_long runsize;
270#ifdef BB_FEATURE_NEW_MODULE_INTERFACE 269#ifdef CONFIG_FEATURE_NEW_MODULE_INTERFACE
271 const char *kallsyms_start; /* All symbols for kernel debugging */ 270 const char *kallsyms_start; /* All symbols for kernel debugging */
272 const char *kallsyms_end; 271 const char *kallsyms_end;
273 const char *archdata_start; /* arch specific data for module */ 272 const char *archdata_start; /* arch specific data for module */
@@ -351,7 +350,7 @@ int delete_module(const char *);
351#ifndef MODUTILS_OBJ_H 350#ifndef MODUTILS_OBJ_H
352static const int MODUTILS_OBJ_H = 1; 351static const int MODUTILS_OBJ_H = 1;
353 352
354#ident "$Id: insmod.c,v 1.73 2001/08/22 05:41:57 andersen Exp $" 353#ident "$Id: insmod.c,v 1.74 2001/10/24 04:59:54 andersen Exp $"
355 354
356/* The relocatable object is manipulated using elfin types. */ 355/* The relocatable object is manipulated using elfin types. */
357 356
@@ -551,7 +550,7 @@ static struct obj_symbol *obj_find_symbol (struct obj_file *f,
551static ElfW(Addr) obj_symbol_final_value(struct obj_file *f, 550static ElfW(Addr) obj_symbol_final_value(struct obj_file *f,
552 struct obj_symbol *sym); 551 struct obj_symbol *sym);
553 552
554#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING 553#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
555static void obj_set_symbol_compare(struct obj_file *f, 554static void obj_set_symbol_compare(struct obj_file *f,
556 int (*cmp)(const char *, const char *), 555 int (*cmp)(const char *, const char *),
557 unsigned long (*hash)(const char *)); 556 unsigned long (*hash)(const char *));
@@ -643,7 +642,7 @@ static int flag_export = 1;
643 642
644 643
645 644
646#if defined(BB_USE_PLT_ENTRIES) 645#if defined(CONFIG_USE_PLT_ENTRIES)
647struct arch_plt_entry 646struct arch_plt_entry
648{ 647{
649 int offset; 648 int offset;
@@ -652,7 +651,7 @@ struct arch_plt_entry
652}; 651};
653#endif 652#endif
654 653
655#if defined(BB_USE_GOT_ENTRIES) 654#if defined(CONFIG_USE_GOT_ENTRIES)
656struct arch_got_entry { 655struct arch_got_entry {
657 int offset; 656 int offset;
658 unsigned offset_done:1; 657 unsigned offset_done:1;
@@ -671,10 +670,10 @@ struct mips_hi16
671 670
672struct arch_file { 671struct arch_file {
673 struct obj_file root; 672 struct obj_file root;
674#if defined(BB_USE_PLT_ENTRIES) 673#if defined(CONFIG_USE_PLT_ENTRIES)
675 struct obj_section *plt; 674 struct obj_section *plt;
676#endif 675#endif
677#if defined(BB_USE_GOT_ENTRIES) 676#if defined(CONFIG_USE_GOT_ENTRIES)
678 struct obj_section *got; 677 struct obj_section *got;
679#endif 678#endif
680#if defined(__mips__) 679#if defined(__mips__)
@@ -684,10 +683,10 @@ struct arch_file {
684 683
685struct arch_symbol { 684struct arch_symbol {
686 struct obj_symbol root; 685 struct obj_symbol root;
687#if defined(BB_USE_PLT_ENTRIES) 686#if defined(CONFIG_USE_PLT_ENTRIES)
688 struct arch_plt_entry pltent; 687 struct arch_plt_entry pltent;
689#endif 688#endif
690#if defined(BB_USE_GOT_ENTRIES) 689#if defined(CONFIG_USE_GOT_ENTRIES)
691 struct arch_got_entry gotent; 690 struct arch_got_entry gotent;
692#endif 691#endif
693}; 692};
@@ -746,10 +745,10 @@ static struct obj_file *arch_new_file(void)
746 struct arch_file *f; 745 struct arch_file *f;
747 f = xmalloc(sizeof(*f)); 746 f = xmalloc(sizeof(*f));
748 747
749#if defined(BB_USE_PLT_ENTRIES) 748#if defined(CONFIG_USE_PLT_ENTRIES)
750 f->plt = NULL; 749 f->plt = NULL;
751#endif 750#endif
752#if defined(BB_USE_GOT_ENTRIES) 751#if defined(CONFIG_USE_GOT_ENTRIES)
753 f->got = NULL; 752 f->got = NULL;
754#endif 753#endif
755#if defined(__mips__) 754#if defined(__mips__)
@@ -769,10 +768,10 @@ static struct obj_symbol *arch_new_symbol(void)
769 struct arch_symbol *sym; 768 struct arch_symbol *sym;
770 sym = xmalloc(sizeof(*sym)); 769 sym = xmalloc(sizeof(*sym));
771 770
772#if defined(BB_USE_PLT_ENTRIES) 771#if defined(CONFIG_USE_PLT_ENTRIES)
773 memset(&sym->pltent, 0, sizeof(sym->pltent)); 772 memset(&sym->pltent, 0, sizeof(sym->pltent));
774#endif 773#endif
775#if defined(BB_USE_GOT_ENTRIES) 774#if defined(CONFIG_USE_GOT_ENTRIES)
776 memset(&sym->gotent, 0, sizeof(sym->gotent)); 775 memset(&sym->gotent, 0, sizeof(sym->gotent));
777#endif 776#endif
778 777
@@ -793,10 +792,10 @@ arch_apply_relocation(struct obj_file *f,
793 792
794 ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset); 793 ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
795 ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset; 794 ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
796#if defined(BB_USE_GOT_ENTRIES) 795#if defined(CONFIG_USE_GOT_ENTRIES)
797 ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0; 796 ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
798#endif 797#endif
799#if defined(BB_USE_PLT_ENTRIES) 798#if defined(CONFIG_USE_PLT_ENTRIES)
800 ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; 799 ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
801 struct arch_plt_entry *pe; 800 struct arch_plt_entry *pe;
802 unsigned long *ip; 801 unsigned long *ip;
@@ -984,7 +983,7 @@ arch_apply_relocation(struct obj_file *f,
984#elif defined(__i386__) 983#elif defined(__i386__)
985#endif 984#endif
986 985
987#if defined(BB_USE_PLT_ENTRIES) 986#if defined(CONFIG_USE_PLT_ENTRIES)
988 987
989#if defined(__arm__) 988#if defined(__arm__)
990 case R_ARM_PC24: 989 case R_ARM_PC24:
@@ -1037,7 +1036,7 @@ arch_apply_relocation(struct obj_file *f,
1037 *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc); 1036 *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
1038#endif 1037#endif
1039 break; 1038 break;
1040#endif /* BB_USE_PLT_ENTRIES */ 1039#endif /* CONFIG_USE_PLT_ENTRIES */
1041 1040
1042#if defined(__arm__) 1041#if defined(__arm__)
1043#elif defined(__sh__) 1042#elif defined(__sh__)
@@ -1072,7 +1071,7 @@ arch_apply_relocation(struct obj_file *f,
1072 break; 1071 break;
1073#endif 1072#endif
1074 1073
1075#if defined(BB_USE_GOT_ENTRIES) 1074#if defined(CONFIG_USE_GOT_ENTRIES)
1076 1075
1077#if !defined(__68k__) 1076#if !defined(__68k__)
1078#if defined(__sh__) 1077#if defined(__sh__)
@@ -1130,7 +1129,7 @@ arch_apply_relocation(struct obj_file *f,
1130 break; 1129 break;
1131#endif // __mc68000__ 1130#endif // __mc68000__
1132 1131
1133#endif /* BB_USE_GOT_ENTRIES */ 1132#endif /* CONFIG_USE_GOT_ENTRIES */
1134 1133
1135 default: 1134 default:
1136 printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info)); 1135 printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info));
@@ -1143,13 +1142,13 @@ arch_apply_relocation(struct obj_file *f,
1143 1142
1144static int arch_create_got(struct obj_file *f) 1143static int arch_create_got(struct obj_file *f)
1145{ 1144{
1146#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) 1145#if defined(CONFIG_USE_GOT_ENTRIES) || defined(CONFIG_USE_PLT_ENTRIES)
1147 struct arch_file *ifile = (struct arch_file *) f; 1146 struct arch_file *ifile = (struct arch_file *) f;
1148 int i; 1147 int i;
1149#if defined(BB_USE_GOT_ENTRIES) 1148#if defined(CONFIG_USE_GOT_ENTRIES)
1150 int got_offset = 0, gotneeded = 0; 1149 int got_offset = 0, gotneeded = 0;
1151#endif 1150#endif
1152#if defined(BB_USE_PLT_ENTRIES) 1151#if defined(CONFIG_USE_PLT_ENTRIES)
1153 int plt_offset = 0, pltneeded = 0; 1152 int plt_offset = 0, pltneeded = 0;
1154#endif 1153#endif
1155 struct obj_section *relsec, *symsec, *strsec; 1154 struct obj_section *relsec, *symsec, *strsec;
@@ -1226,18 +1225,18 @@ static int arch_create_got(struct obj_file *f)
1226 name = f->sections[extsym->st_shndx]->name; 1225 name = f->sections[extsym->st_shndx]->name;
1227 } 1226 }
1228 intsym = (struct arch_symbol *) obj_find_symbol(f, name); 1227 intsym = (struct arch_symbol *) obj_find_symbol(f, name);
1229#if defined(BB_USE_GOT_ENTRIES) 1228#if defined(CONFIG_USE_GOT_ENTRIES)
1230 if (!intsym->gotent.offset_done) { 1229 if (!intsym->gotent.offset_done) {
1231 intsym->gotent.offset_done = 1; 1230 intsym->gotent.offset_done = 1;
1232 intsym->gotent.offset = got_offset; 1231 intsym->gotent.offset = got_offset;
1233 got_offset += BB_GOT_ENTRY_SIZE; 1232 got_offset += CONFIG_GOT_ENTRY_SIZE;
1234 } 1233 }
1235#endif 1234#endif
1236#if defined(BB_USE_PLT_ENTRIES) 1235#if defined(CONFIG_USE_PLT_ENTRIES)
1237 if (pltneeded && intsym->pltent.allocated == 0) { 1236 if (pltneeded && intsym->pltent.allocated == 0) {
1238 intsym->pltent.allocated = 1; 1237 intsym->pltent.allocated = 1;
1239 intsym->pltent.offset = plt_offset; 1238 intsym->pltent.offset = plt_offset;
1240 plt_offset += BB_PLT_ENTRY_SIZE; 1239 plt_offset += CONFIG_PLT_ENTRY_SIZE;
1241 intsym->pltent.inited = 0; 1240 intsym->pltent.inited = 0;
1242 pltneeded = 0; 1241 pltneeded = 0;
1243 } 1242 }
@@ -1245,7 +1244,7 @@ static int arch_create_got(struct obj_file *f)
1245 } 1244 }
1246 } 1245 }
1247 1246
1248#if defined(BB_USE_GOT_ENTRIES) 1247#if defined(CONFIG_USE_GOT_ENTRIES)
1249 if (got_offset) { 1248 if (got_offset) {
1250 struct obj_section* myrelsec = obj_find_section(f, ".got"); 1249 struct obj_section* myrelsec = obj_find_section(f, ".got");
1251 1250
@@ -1253,7 +1252,7 @@ static int arch_create_got(struct obj_file *f)
1253 obj_extend_section(myrelsec, got_offset); 1252 obj_extend_section(myrelsec, got_offset);
1254 } else { 1253 } else {
1255 myrelsec = obj_create_alloced_section(f, ".got", 1254 myrelsec = obj_create_alloced_section(f, ".got",
1256 BB_GOT_ENTRY_SIZE, 1255 CONFIG_GOT_ENTRY_SIZE,
1257 got_offset); 1256 got_offset);
1258 assert(myrelsec); 1257 assert(myrelsec);
1259 } 1258 }
@@ -1262,10 +1261,10 @@ static int arch_create_got(struct obj_file *f)
1262 } 1261 }
1263#endif 1262#endif
1264 1263
1265#if defined(BB_USE_PLT_ENTRIES) 1264#if defined(CONFIG_USE_PLT_ENTRIES)
1266 if (plt_offset) 1265 if (plt_offset)
1267 ifile->plt = obj_create_alloced_section(f, ".plt", 1266 ifile->plt = obj_create_alloced_section(f, ".plt",
1268 BB_PLT_ENTRY_SIZE, 1267 CONFIG_PLT_ENTRY_SIZE,
1269 plt_offset); 1268 plt_offset);
1270#endif 1269#endif
1271#endif 1270#endif
@@ -1304,7 +1303,7 @@ static unsigned long obj_elf_hash(const char *name)
1304 return obj_elf_hash_n(name, strlen(name)); 1303 return obj_elf_hash_n(name, strlen(name));
1305} 1304}
1306 1305
1307#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING 1306#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
1308/* String comparison for non-co-versioned kernel and module. */ 1307/* String comparison for non-co-versioned kernel and module. */
1309 1308
1310static int ncv_strcmp(const char *a, const char *b) 1309static int ncv_strcmp(const char *a, const char *b)
@@ -1356,7 +1355,7 @@ obj_set_symbol_compare(struct obj_file *f,
1356 } 1355 }
1357} 1356}
1358 1357
1359#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ 1358#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */
1360 1359
1361static struct obj_symbol * 1360static struct obj_symbol *
1362obj_add_symbol(struct obj_file *f, const char *name, 1361obj_add_symbol(struct obj_file *f, const char *name,
@@ -1787,7 +1786,7 @@ old_process_module_arguments(struct obj_file *f, int argc, char **argv)
1787 return 1; 1786 return 1;
1788} 1787}
1789 1788
1790#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING 1789#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
1791static int old_is_module_checksummed(struct obj_file *f) 1790static int old_is_module_checksummed(struct obj_file *f)
1792{ 1791{
1793 return obj_find_symbol(f, "Using_Versions") != NULL; 1792 return obj_find_symbol(f, "Using_Versions") != NULL;
@@ -1821,9 +1820,9 @@ old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
1821 return a << 16 | b << 8 | c; 1820 return a << 16 | b << 8 | c;
1822} 1821}
1823 1822
1824#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ 1823#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */
1825 1824
1826#ifdef BB_FEATURE_OLD_MODULE_INTERFACE 1825#ifdef CONFIG_FEATURE_OLD_MODULE_INTERFACE
1827 1826
1828/* Fetch all the symbols and divvy them up as appropriate for the modules. */ 1827/* Fetch all the symbols and divvy them up as appropriate for the modules. */
1829 1828
@@ -2033,7 +2032,7 @@ old_init_module(const char *m_name, struct obj_file *f,
2033#define old_create_mod_use_count(x) TRUE 2032#define old_create_mod_use_count(x) TRUE
2034#define old_init_module(x, y, z) TRUE 2033#define old_init_module(x, y, z) TRUE
2035 2034
2036#endif /* BB_FEATURE_OLD_MODULE_INTERFACE */ 2035#endif /* CONFIG_FEATURE_OLD_MODULE_INTERFACE */
2037 2036
2038 2037
2039 2038
@@ -2273,7 +2272,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv)
2273 return 1; 2272 return 1;
2274} 2273}
2275 2274
2276#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING 2275#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
2277static int new_is_module_checksummed(struct obj_file *f) 2276static int new_is_module_checksummed(struct obj_file *f)
2278{ 2277{
2279 const char *p = get_modinfo_value(f, "using_checksums"); 2278 const char *p = get_modinfo_value(f, "using_checksums");
@@ -2309,10 +2308,10 @@ new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
2309 return a << 16 | b << 8 | c; 2308 return a << 16 | b << 8 | c;
2310} 2309}
2311 2310
2312#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ 2311#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */
2313 2312
2314 2313
2315#ifdef BB_FEATURE_NEW_MODULE_INTERFACE 2314#ifdef CONFIG_FEATURE_NEW_MODULE_INTERFACE
2316 2315
2317/* Fetch the loaded modules, and all currently exported symbols. */ 2316/* Fetch the loaded modules, and all currently exported symbols. */
2318 2317
@@ -2601,7 +2600,7 @@ new_init_module(const char *m_name, struct obj_file *f,
2601#define new_create_module_ksymtab(x) 2600#define new_create_module_ksymtab(x)
2602#define query_module(v, w, x, y, z) -1 2601#define query_module(v, w, x, y, z) -1
2603 2602
2604#endif /* BB_FEATURE_NEW_MODULE_INTERFACE */ 2603#endif /* CONFIG_FEATURE_NEW_MODULE_INTERFACE */
2605 2604
2606 2605
2607/*======================================================================*/ 2606/*======================================================================*/
@@ -3155,7 +3154,7 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits)
3155 return f; 3154 return f;
3156} 3155}
3157 3156
3158#ifdef BB_FEATURE_INSMOD_LOADINKMEM 3157#ifdef CONFIG_FEATURE_INSMOD_LOADINKMEM
3159/* 3158/*
3160 * load the unloaded sections directly into the memory allocated by 3159 * load the unloaded sections directly into the memory allocated by
3161 * kernel for the module 3160 * kernel for the module
@@ -3222,7 +3221,7 @@ extern int insmod_main( int argc, char **argv)
3222 char m_name[FILENAME_MAX + 1] = "\0"; 3221 char m_name[FILENAME_MAX + 1] = "\0";
3223 int exit_status = EXIT_FAILURE; 3222 int exit_status = EXIT_FAILURE;
3224 int m_has_modinfo; 3223 int m_has_modinfo;
3225#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING 3224#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
3226 struct utsname uts_info; 3225 struct utsname uts_info;
3227 char m_strversion[STRVERSIONLEN]; 3226 char m_strversion[STRVERSIONLEN];
3228 int m_version; 3227 int m_version;
@@ -3335,7 +3334,7 @@ extern int insmod_main( int argc, char **argv)
3335 else 3334 else
3336 m_has_modinfo = 1; 3335 m_has_modinfo = 1;
3337 3336
3338#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING 3337#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
3339 /* Version correspondence? */ 3338 /* Version correspondence? */
3340 3339
3341 if (uname(&uts_info) < 0) 3340 if (uname(&uts_info) < 0)
@@ -3366,12 +3365,12 @@ extern int insmod_main( int argc, char **argv)
3366 } 3365 }
3367 } 3366 }
3368 k_crcs = 0; 3367 k_crcs = 0;
3369#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ 3368#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */
3370 3369
3371 k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); 3370 k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL);
3372 3371
3373 if (k_new_syscalls) { 3372 if (k_new_syscalls) {
3374#ifdef BB_FEATURE_NEW_MODULE_INTERFACE 3373#ifdef CONFIG_FEATURE_NEW_MODULE_INTERFACE
3375 if (!new_get_kernel_symbols()) 3374 if (!new_get_kernel_symbols())
3376 goto out; 3375 goto out;
3377 k_crcs = new_is_kernel_checksummed(); 3376 k_crcs = new_is_kernel_checksummed();
@@ -3380,7 +3379,7 @@ extern int insmod_main( int argc, char **argv)
3380 goto out; 3379 goto out;
3381#endif 3380#endif
3382 } else { 3381 } else {
3383#ifdef BB_FEATURE_OLD_MODULE_INTERFACE 3382#ifdef CONFIG_FEATURE_OLD_MODULE_INTERFACE
3384 if (!old_get_kernel_symbols(m_name)) 3383 if (!old_get_kernel_symbols(m_name))
3385 goto out; 3384 goto out;
3386 k_crcs = old_is_kernel_checksummed(); 3385 k_crcs = old_is_kernel_checksummed();
@@ -3390,7 +3389,7 @@ extern int insmod_main( int argc, char **argv)
3390#endif 3389#endif
3391 } 3390 }
3392 3391
3393#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING 3392#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
3394 if (m_has_modinfo) 3393 if (m_has_modinfo)
3395 m_crcs = new_is_module_checksummed(f); 3394 m_crcs = new_is_module_checksummed(f);
3396 else 3395 else
@@ -3398,7 +3397,7 @@ extern int insmod_main( int argc, char **argv)
3398 3397
3399 if (m_crcs != k_crcs) 3398 if (m_crcs != k_crcs)
3400 obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); 3399 obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
3401#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ 3400#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */
3402 3401
3403 /* Let the module know about the kernel symbols. */ 3402 /* Let the module know about the kernel symbols. */
3404 add_kernel_symbols(f); 3403 add_kernel_symbols(f);
diff --git a/modutils/lsmod.c b/modutils/lsmod.c
index 76ed2fdd8..7b6ad14c6 100644
--- a/modutils/lsmod.c
+++ b/modutils/lsmod.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini lsmod implementation for busybox 3 * Mini lsmod implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and 8 * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
9 * Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels 9 * Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
@@ -41,7 +41,7 @@
41 41
42 42
43 43
44#ifdef BB_FEATURE_NEW_MODULE_INTERFACE 44#ifdef CONFIG_FEATURE_NEW_MODULE_INTERFACE
45 45
46struct module_info 46struct module_info
47{ 47{
@@ -142,7 +142,7 @@ extern int lsmod_main(int argc, char **argv)
142 return( 0); 142 return( 0);
143} 143}
144 144
145#else /*BB_FEATURE_OLD_MODULE_INTERFACE*/ 145#else /*CONFIG_FEATURE_OLD_MODULE_INTERFACE*/
146 146
147extern int lsmod_main(int argc, char **argv) 147extern int lsmod_main(int argc, char **argv)
148{ 148{
@@ -163,4 +163,4 @@ extern int lsmod_main(int argc, char **argv)
163 return 1; 163 return 1;
164} 164}
165 165
166#endif /*BB_FEATURE_OLD_MODULE_INTERFACE*/ 166#endif /*CONFIG_FEATURE_OLD_MODULE_INTERFACE*/
diff --git a/modutils/rmmod.c b/modutils/rmmod.c
index 7596d0232..affe975fa 100644
--- a/modutils/rmmod.c
+++ b/modutils/rmmod.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini rmmod implementation for busybox 3 * Mini rmmod implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/more.c b/more.c
deleted file mode 100644
index 780cddf66..000000000
--- a/more.c
+++ /dev/null
@@ -1,217 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini more implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 *
8 * Latest version blended together by Erik Andersen <andersen@lineo.com>,
9 * based on the original more implementation by Bruce, and code from the
10 * Debian boot-floppies team.
11 *
12 * Termios corrects by Vladimir Oleynik <vodz@usa.net>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include <stdio.h>
31#include <fcntl.h>
32#include <signal.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <sys/ioctl.h>
36#include "busybox.h"
37
38static FILE *cin;
39
40#ifdef BB_FEATURE_USE_TERMIOS
41#include <termios.h>
42#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
43#define getTermSettings(fd,argp) tcgetattr(fd, argp);
44
45static struct termios initial_settings, new_settings;
46
47static void set_tty_to_initial_mode(void)
48{
49 setTermSettings(fileno(cin), &initial_settings);
50}
51
52static void gotsig(int sig)
53{
54 putchar('\n');
55 exit(EXIT_FAILURE);
56}
57#endif /* BB_FEATURE_USE_TERMIOS */
58
59
60static int terminal_width = 79; /* not 80 in case terminal has linefold bug */
61static int terminal_height = 24;
62
63
64extern int more_main(int argc, char **argv)
65{
66 int c, lines, input = 0;
67 int please_display_more_prompt = -1;
68 struct stat st;
69 FILE *file;
70 int len, page_height;
71
72#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS
73 struct winsize win = { 0, 0, 0, 0 };
74#endif
75
76 argc--;
77 argv++;
78
79
80 /* not use inputing from terminal if usage: more > outfile */
81 if(isatty(fileno(stdout))) {
82 cin = fopen(CURRENT_TTY, "r");
83 if (!cin)
84 cin = xfopen(CONSOLE_DEV, "r");
85 please_display_more_prompt = 0;
86#ifdef BB_FEATURE_USE_TERMIOS
87 getTermSettings(fileno(cin), &initial_settings);
88 new_settings = initial_settings;
89 new_settings.c_lflag &= ~ICANON;
90 new_settings.c_lflag &= ~ECHO;
91#ifndef linux
92 /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
93 new_settings.c_cc[VMIN] = 1;
94 new_settings.c_cc[VTIME] = 0;
95#endif
96 setTermSettings(fileno(cin), &new_settings);
97 atexit(set_tty_to_initial_mode);
98 (void) signal(SIGINT, gotsig);
99 (void) signal(SIGQUIT, gotsig);
100 (void) signal(SIGTERM, gotsig);
101#endif
102 }
103
104 do {
105 if (argc == 0) {
106 file = stdin;
107 } else
108 file = wfopen(*argv, "r");
109 if(file==0)
110 goto loop;
111
112 fstat(fileno(file), &st);
113
114 if(please_display_more_prompt>0)
115 please_display_more_prompt = 0;
116
117#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS
118 ioctl(fileno(stdout), TIOCGWINSZ, &win);
119 if (win.ws_row > 4)
120 terminal_height = win.ws_row - 2;
121 if (win.ws_col > 0)
122 terminal_width = win.ws_col - 1;
123#endif
124 len=0;
125 lines = 0;
126 page_height = terminal_height;
127 while ((c = getc(file)) != EOF) {
128
129 if (please_display_more_prompt>0) {
130 len = printf("--More-- ");
131 if (file != stdin) {
132#if _FILE_OFFSET_BITS == 64
133 len += printf("(%d%% of %lld bytes)",
134 (int) (100 * ((double) ftell(file) /
135 (double) st.st_size)), (long long)st.st_size);
136#else
137 len += printf("(%d%% of %ld bytes)",
138 (int) (100 * ((double) ftell(file) /
139 (double) st.st_size)), (long)st.st_size);
140#endif
141 }
142
143 fflush(stdout);
144
145 /*
146 * We've just displayed the "--More--" prompt, so now we need
147 * to get input from the user.
148 */
149 input = getc(cin);
150#ifndef BB_FEATURE_USE_TERMIOS
151 printf("\033[A"); /* up cursor */
152#endif
153 /* Erase the "More" message */
154 putc('\r', stdout);
155 while (--len >= 0)
156 putc(' ', stdout);
157 putc('\r', stdout);
158 fflush(stdout);
159 len=0;
160 lines = 0;
161 page_height = terminal_height;
162 please_display_more_prompt = 0;
163
164 if (input == 'q')
165 goto end;
166 }
167
168 /*
169 * There are two input streams to worry about here:
170 *
171 * c : the character we are reading from the file being "mored"
172 * input : a character received from the keyboard
173 *
174 * If we hit a newline in the _file_ stream, we want to test and
175 * see if any characters have been hit in the _input_ stream. This
176 * allows the user to quit while in the middle of a file.
177 */
178 if (c == '\n') {
179 /* increment by just one line if we are at
180 * the end of this line */
181 if (input == '\n')
182 if(please_display_more_prompt==0)
183 please_display_more_prompt = 1;
184 /* Adjust the terminal height for any overlap, so that
185 * no lines get lost off the top. */
186 if (len >= terminal_width) {
187 int quot, rem;
188 quot = len / terminal_width;
189 rem = len - (quot * terminal_width);
190 if (quot) {
191 if (rem)
192 page_height-=quot;
193 else
194 page_height-=(quot-1);
195 }
196 }
197 if (++lines >= page_height) {
198 if(please_display_more_prompt==0)
199 please_display_more_prompt = 1;
200 }
201 len=0;
202 }
203 /*
204 * If we just read a newline from the file being 'mored' and any
205 * key other than a return is hit, scroll by one page
206 */
207 putc(c, stdout);
208 len++;
209 }
210 fclose(file);
211 fflush(stdout);
212loop:
213 argv++;
214 } while (--argc > 0);
215 end:
216 return 0;
217}
diff --git a/mount.c b/mount.c
deleted file mode 100644
index af57a7623..000000000
--- a/mount.c
+++ /dev/null
@@ -1,498 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini mount implementation for busybox
4 *
5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * 3/21/1999 Charles P. Wright <cpwright@cpwright.com>
22 * searches through fstab when -a is passed
23 * will try mounting stuff with all fses when passed -t auto
24 *
25 * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab.
26 *
27 * 1999-10-07 Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
28 * Rewrite of a lot of code. Removed mtab usage (I plan on
29 * putting it back as a compile-time option some time),
30 * major adjustments to option parsing, and some serious
31 * dieting all around.
32 *
33 * 1999-11-06 mtab suppport is back - andersee
34 *
35 * 2000-01-12 Ben Collins <bcollins@debian.org>, Borrowed utils-linux's
36 * mount to add loop support.
37 *
38 * 2000-04-30 Dave Cinege <dcinege@psychosis.com>
39 * Rewrote fstab while loop and lower mount section. Can now do
40 * single mounts from fstab. Can override fstab options for single
41 * mount. Common mount_one call for single mounts and 'all'. Fixed
42 * mtab updating and stale entries. Removed 'remount' default.
43 *
44 */
45
46#include <limits.h>
47#include <stdlib.h>
48#include <unistd.h>
49#include <errno.h>
50#include <string.h>
51#include <stdio.h>
52#include <mntent.h>
53#include <ctype.h>
54#include "busybox.h"
55#if defined BB_FEATURE_USE_DEVPS_PATCH
56# include <linux/devmtab.h> /* For Erik's nifty devmtab device driver */
57#endif
58
59enum {
60 MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */
61 MS_RDONLY = 1, /* Mount read-only */
62 MS_NOSUID = 2, /* Ignore suid and sgid bits */
63 MS_NODEV = 4, /* Disallow access to device special files */
64 MS_NOEXEC = 8, /* Disallow program execution */
65 MS_SYNCHRONOUS = 16, /* Writes are synced at once */
66 MS_REMOUNT = 32, /* Alter flags of a mounted FS */
67 MS_MANDLOCK = 64, /* Allow mandatory locks on an FS */
68 S_QUOTA = 128, /* Quota initialized for file/directory/symlink */
69 S_APPEND = 256, /* Append-only file */
70 S_IMMUTABLE = 512, /* Immutable file */
71 MS_NOATIME = 1024, /* Do not update access times. */
72 MS_NODIRATIME = 2048, /* Do not update directory access times */
73 MS_BIND = 4096, /* Use the new linux 2.4.x "mount --bind" feature */
74};
75
76
77#if defined BB_FEATURE_MOUNT_LOOP
78#include <fcntl.h>
79#include <sys/ioctl.h>
80static int use_loop = FALSE;
81#endif
82
83extern int mount (__const char *__special_file, __const char *__dir,
84 __const char *__fstype, unsigned long int __rwflag,
85 __const void *__data);
86extern int umount (__const char *__special_file);
87extern int umount2 (__const char *__special_file, int __flags);
88
89extern int sysfs( int option, unsigned int fs_index, char * buf);
90
91extern const char mtab_file[]; /* Defined in utility.c */
92
93struct mount_options {
94 const char *name;
95 unsigned long and;
96 unsigned long or;
97};
98
99static const struct mount_options mount_options[] = {
100 {"async", ~MS_SYNCHRONOUS, 0},
101 {"atime", ~0, ~MS_NOATIME},
102 {"defaults", ~0, 0},
103 {"dev", ~MS_NODEV, 0},
104 {"diratime", ~0, ~MS_NODIRATIME},
105 {"exec", ~MS_NOEXEC, 0},
106 {"noatime", ~0, MS_NOATIME},
107 {"nodev", ~0, MS_NODEV},
108 {"nodiratime", ~0, MS_NODIRATIME},
109 {"noexec", ~0, MS_NOEXEC},
110 {"nosuid", ~0, MS_NOSUID},
111 {"remount", ~0, MS_REMOUNT},
112 {"ro", ~0, MS_RDONLY},
113 {"rw", ~MS_RDONLY, 0},
114 {"suid", ~MS_NOSUID, 0},
115 {"sync", ~0, MS_SYNCHRONOUS},
116 {"bind", ~0, MS_BIND},
117 {0, 0, 0}
118};
119
120static int
121do_mount(char *specialfile, char *dir, char *filesystemtype,
122 long flags, void *string_flags, int useMtab, int fakeIt,
123 char *mtab_opts, int mount_all)
124{
125 int status = 0;
126#if defined BB_FEATURE_MOUNT_LOOP
127 char *lofile = NULL;
128#endif
129
130 if (fakeIt == FALSE)
131 {
132#if defined BB_FEATURE_MOUNT_LOOP
133 if (use_loop==TRUE) {
134 int loro = flags & MS_RDONLY;
135
136 lofile = specialfile;
137
138 specialfile = find_unused_loop_device();
139 if (specialfile == NULL) {
140 error_msg_and_die("Could not find a spare loop device");
141 }
142 if (set_loop(specialfile, lofile, 0, &loro)) {
143 error_msg_and_die("Could not setup loop device");
144 }
145 if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */
146 error_msg("WARNING: loop device is read-only");
147 flags |= MS_RDONLY;
148 }
149 }
150#endif
151 status = mount(specialfile, dir, filesystemtype, flags, string_flags);
152 if (status < 0 && errno == EROFS) {
153 error_msg("%s is write-protected, mounting read-only", specialfile);
154 status = mount(specialfile, dir, filesystemtype, flags |= MS_RDONLY, string_flags);
155 }
156 /* Don't whine about already mounted filesystems when mounting all. */
157 if (status < 0 && errno == EBUSY && mount_all)
158 return TRUE;
159 }
160
161
162 /* If the mount was sucessful, do anything needed, then return TRUE */
163 if (status == 0 || fakeIt==TRUE) {
164
165#if defined BB_FEATURE_MTAB_SUPPORT
166 if (useMtab == TRUE) {
167 erase_mtab(specialfile); // Clean any stale entries
168 write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
169 }
170#endif
171 return (TRUE);
172 }
173
174 /* Bummer. mount failed. Clean up */
175#if defined BB_FEATURE_MOUNT_LOOP
176 if (lofile != NULL) {
177 del_loop(specialfile);
178 }
179#endif
180
181 if (errno == EPERM) {
182 error_msg_and_die("permission denied. Are you root?");
183 }
184
185 return (FALSE);
186}
187
188
189
190/* Seperate standard mount options from the nonstandard string options */
191static void
192parse_mount_options(char *options, int *flags, char *strflags)
193{
194 while (options) {
195 int gotone = FALSE;
196 char *comma = strchr(options, ',');
197 const struct mount_options *f = mount_options;
198
199 if (comma)
200 *comma = '\0';
201
202 while (f->name != 0) {
203 if (strcasecmp(f->name, options) == 0) {
204
205 *flags &= f->and;
206 *flags |= f->or;
207 gotone = TRUE;
208 break;
209 }
210 f++;
211 }
212#if defined BB_FEATURE_MOUNT_LOOP
213 if (gotone == FALSE && !strcasecmp("loop", options)) { /* loop device support */
214 use_loop = TRUE;
215 gotone = TRUE;
216 }
217#endif
218 if (*strflags && strflags != '\0' && gotone == FALSE) {
219 char *temp = strflags;
220
221 temp += strlen(strflags);
222 *temp++ = ',';
223 *temp++ = '\0';
224 }
225 if (gotone == FALSE)
226 strcat(strflags, options);
227 if (comma) {
228 *comma = ',';
229 options = ++comma;
230 } else {
231 break;
232 }
233 }
234}
235
236static int
237mount_one(char *blockDevice, char *directory, char *filesystemType,
238 unsigned long flags, char *string_flags, int useMtab, int fakeIt,
239 char *mtab_opts, int whineOnErrors, int mount_all)
240{
241 int status = 0;
242
243#if defined BB_FEATURE_USE_DEVPS_PATCH
244 if (strcmp(filesystemType, "auto") == 0) {
245 static const char *noauto_array[] = { "tmpfs", "shm", "proc", "ramfs", "devpts", "devfs", "usbdevfs", 0 };
246 const char **noauto_fstype;
247 const int num_of_filesystems = sysfs(3, 0, 0);
248 char buf[255];
249 int i=0;
250
251 filesystemType=buf;
252
253 while(i < num_of_filesystems) {
254 sysfs(2, i++, filesystemType);
255 for (noauto_fstype = noauto_array; *noauto_fstype; noauto_fstype++) {
256 if (!strcmp(filesystemType, *noauto_fstype)) {
257 break;
258 }
259 }
260 if (!*noauto_fstype) {
261 status = do_mount(blockDevice, directory, filesystemType,
262 flags | MS_MGC_VAL, string_flags,
263 useMtab, fakeIt, mtab_opts, mount_all);
264 if (status == TRUE)
265 break;
266 }
267 }
268 }
269#else
270 if (strcmp(filesystemType, "auto") == 0) {
271 char buf[255];
272 FILE *f = xfopen("/proc/filesystems", "r");
273
274 while (fgets(buf, sizeof(buf), f) != NULL) {
275 filesystemType = buf;
276 if (*filesystemType == '\t') { // Not a nodev filesystem
277
278 // Add NULL termination to each line
279 while (*filesystemType && *filesystemType != '\n')
280 filesystemType++;
281 *filesystemType = '\0';
282
283 filesystemType = buf;
284 filesystemType++; // hop past tab
285
286 status = do_mount(blockDevice, directory, filesystemType,
287 flags | MS_MGC_VAL, string_flags,
288 useMtab, fakeIt, mtab_opts, mount_all);
289 if (status == TRUE)
290 break;
291 }
292 }
293 fclose(f);
294 }
295#endif
296 else {
297 status = do_mount(blockDevice, directory, filesystemType,
298 flags | MS_MGC_VAL, string_flags, useMtab,
299 fakeIt, mtab_opts, mount_all);
300 }
301
302 if (status == FALSE) {
303 if (whineOnErrors == TRUE) {
304 perror_msg("Mounting %s on %s failed", blockDevice, directory);
305 }
306 return (FALSE);
307 }
308 return (TRUE);
309}
310
311void show_mounts(void)
312{
313#if defined BB_FEATURE_USE_DEVPS_PATCH
314 int fd, i, numfilesystems;
315 char device[] = "/dev/mtab";
316 struct k_mntent *mntentlist;
317
318 /* open device */
319 fd = open(device, O_RDONLY);
320 if (fd < 0)
321 perror_msg_and_die("open failed for `%s'", device);
322
323 /* How many mounted filesystems? We need to know to
324 * allocate enough space for later... */
325 numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS);
326 if (numfilesystems<0)
327 perror_msg_and_die( "\nDEVMTAB_COUNT_MOUNTS");
328 mntentlist = (struct k_mntent *) xcalloc ( numfilesystems, sizeof(struct k_mntent));
329
330 /* Grab the list of mounted filesystems */
331 if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0)
332 perror_msg_and_die( "\nDEVMTAB_GET_MOUNTS");
333
334 for( i = 0 ; i < numfilesystems ; i++) {
335 printf( "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname,
336 mntentlist[i].mnt_dir, mntentlist[i].mnt_type,
337 mntentlist[i].mnt_opts, mntentlist[i].mnt_freq,
338 mntentlist[i].mnt_passno);
339 }
340#ifdef BB_FEATURE_CLEAN_UP
341 /* Don't bother to close files or free memory. Exit
342 * does that automagically, so we can save a few bytes */
343 free( mntentlist);
344 close(fd);
345#endif
346 exit(EXIT_SUCCESS);
347#else
348 FILE *mountTable = setmntent(mtab_file, "r");
349
350 if (mountTable) {
351 struct mntent *m;
352
353 while ((m = getmntent(mountTable)) != 0) {
354 char *blockDevice = m->mnt_fsname;
355 if (strcmp(blockDevice, "/dev/root") == 0) {
356 blockDevice = find_real_root_device_name(blockDevice);
357 }
358 printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
359 m->mnt_type, m->mnt_opts);
360#ifdef BB_FEATURE_CLEAN_UP
361 if(blockDevice != m->mnt_fsname)
362 free(blockDevice);
363#endif
364 }
365 endmntent(mountTable);
366 } else {
367 perror_msg_and_die("%s", mtab_file);
368 }
369 exit(EXIT_SUCCESS);
370#endif
371}
372
373extern int mount_main(int argc, char **argv)
374{
375 struct stat statbuf;
376 char string_flags_buf[1024] = "";
377 char *string_flags = string_flags_buf;
378 char *extra_opts = string_flags_buf;
379 int flags = 0;
380 char *filesystemType = "auto";
381 char *device = xmalloc(PATH_MAX);
382 char *directory = xmalloc(PATH_MAX);
383 int all = FALSE;
384 int fakeIt = FALSE;
385 int useMtab = TRUE;
386 int rc = EXIT_FAILURE;
387 int fstabmount = FALSE;
388 int opt;
389
390 /* Parse options */
391 while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) {
392 switch (opt) {
393 case 'o':
394 parse_mount_options(optarg, &flags, string_flags);
395 break;
396 case 'r':
397 flags |= MS_RDONLY;
398 break;
399 case 't':
400 filesystemType = optarg;
401 break;
402 case 'w':
403 flags &= ~MS_RDONLY;
404 break;
405 case 'a':
406 all = TRUE;
407 break;
408 case 'f':
409 fakeIt = TRUE;
410 break;
411#ifdef BB_FEATURE_MTAB_SUPPORT
412 case 'n':
413 useMtab = FALSE;
414 break;
415#endif
416 case 'v':
417 break; /* ignore -v */
418 }
419 }
420
421 if (!all && optind == argc)
422 show_mounts();
423
424 if (optind < argc) {
425 /* if device is a filename get its real path */
426 if (stat(argv[optind], &statbuf) == 0) {
427 device = simplify_path(argv[optind]);
428 } else {
429 safe_strncpy(device, argv[optind], PATH_MAX);
430 }
431 }
432
433 if (optind + 1 < argc)
434 directory = simplify_path(argv[optind + 1]);
435
436 if (all == TRUE || optind + 1 == argc) {
437 struct mntent *m = NULL;
438 FILE *f = setmntent("/etc/fstab", "r");
439 fstabmount = TRUE;
440
441 if (f == NULL)
442 perror_msg_and_die( "\nCannot read /etc/fstab");
443
444 while ((m = getmntent(f)) != NULL) {
445 if (all == FALSE && optind + 1 == argc && (
446 (strcmp(device, m->mnt_fsname) != 0) &&
447 (strcmp(device, m->mnt_dir) != 0) ) ) {
448 continue;
449 }
450
451 if (all == TRUE && ( // If we're mounting 'all'
452 (strstr(m->mnt_opts, "noauto")) || // and the file system isn't noauto,
453 (strstr(m->mnt_type, "swap")) || // and isn't swap or nfs, then mount it
454 (strstr(m->mnt_type, "nfs")) ) ) {
455 continue;
456 }
457
458 if (all == TRUE || flags == 0) { // Allow single mount to override fstab flags
459 flags = 0;
460 *string_flags = '\0';
461 parse_mount_options(m->mnt_opts, &flags, string_flags);
462 }
463
464 strcpy(device, m->mnt_fsname);
465 strcpy(directory, m->mnt_dir);
466 filesystemType = strdup(m->mnt_type);
467singlemount:
468 string_flags = strdup(string_flags);
469 rc = EXIT_SUCCESS;
470#ifdef BB_NFSMOUNT
471 if (strchr(device, ':') != NULL)
472 filesystemType = "nfs";
473 if (strcmp(filesystemType, "nfs") == 0) {
474 if (nfsmount (device, directory, &flags, &extra_opts,
475 &string_flags, 1)) {
476 perror_msg("nfsmount failed");
477 rc = EXIT_FAILURE;
478 }
479 }
480#endif
481 if (!mount_one(device, directory, filesystemType, flags,
482 string_flags, useMtab, fakeIt, extra_opts, TRUE, all))
483 rc = EXIT_FAILURE;
484
485 if (all == FALSE)
486 break;
487 }
488 if (fstabmount == TRUE)
489 endmntent(f);
490
491 if (all == FALSE && fstabmount == TRUE && m == NULL)
492 fprintf(stderr, "Can't find %s in /etc/fstab\n", device);
493
494 return rc;
495 }
496
497 goto singlemount;
498}
diff --git a/msh.c b/msh.c
deleted file mode 100644
index 5c4ec1019..000000000
--- a/msh.c
+++ /dev/null
@@ -1,4870 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Minix shell port for busybox
4 *
5 * This version of the Minix shell was adapted for use in busybox
6 * by Erik Andersen <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Original copyright notice is retained at the end of this file.
23 */
24
25#include <ctype.h>
26#include <dirent.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <limits.h>
30#include <setjmp.h>
31#include <signal.h>
32#include <stddef.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <time.h>
37#include <unistd.h>
38#include <sys/stat.h>
39#include <sys/times.h>
40#include <sys/types.h>
41#include <sys/wait.h>
42
43#include "cmdedit.h"
44#include "busybox.h"
45
46
47/* -------- sh.h -------- */
48/*
49 * shell
50 */
51
52#define LINELIM 2100
53#define NPUSH 8 /* limit to input nesting */
54
55#define NOFILE 20 /* Number of open files */
56#define NUFILE 10 /* Number of user-accessible files */
57#define FDBASE 10 /* First file usable by Shell */
58
59/*
60 * values returned by wait
61 */
62#define WAITSIG(s) ((s)&0177)
63#define WAITVAL(s) (((s)>>8)&0377)
64#define WAITCORE(s) (((s)&0200)!=0)
65
66/*
67 * library and system defintions
68 */
69typedef void xint; /* base type of jmp_buf, for not broken compilers */
70
71/*
72 * shell components
73 */
74
75#define QUOTE 0200
76
77#define NOBLOCK ((struct op *)NULL)
78#define NOWORD ((char *)NULL)
79#define NOWORDS ((char **)NULL)
80#define NOPIPE ((int *)NULL)
81
82/*
83 * Description of a command or an operation on commands.
84 * Might eventually use a union.
85 */
86struct op {
87 int type; /* operation type, see below */
88 char **words; /* arguments to a command */
89 struct ioword **ioact; /* IO actions (eg, < > >>) */
90 struct op *left;
91 struct op *right;
92 char *str; /* identifier for case and for */
93};
94
95#define TCOM 1 /* command */
96#define TPAREN 2 /* (c-list) */
97#define TPIPE 3 /* a | b */
98#define TLIST 4 /* a [&;] b */
99#define TOR 5 /* || */
100#define TAND 6 /* && */
101#define TFOR 7
102#define TDO 8
103#define TCASE 9
104#define TIF 10
105#define TWHILE 11
106#define TUNTIL 12
107#define TELIF 13
108#define TPAT 14 /* pattern in case */
109#define TBRACE 15 /* {c-list} */
110#define TASYNC 16 /* c & */
111
112/*
113 * actions determining the environment of a process
114 */
115#define BIT(i) (1<<(i))
116#define FEXEC BIT(0) /* execute without forking */
117
118/*
119 * flags to control evaluation of words
120 */
121#define DOSUB 1 /* interpret $, `, and quotes */
122#define DOBLANK 2 /* perform blank interpretation */
123#define DOGLOB 4 /* interpret [?* */
124#define DOKEY 8 /* move words with `=' to 2nd arg. list */
125#define DOTRIM 16 /* trim resulting string */
126
127#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
128
129static char **dolv;
130static int dolc;
131static int exstat;
132static char gflg;
133static int interactive; /* Is this an interactive shell */
134static int execflg;
135static int multiline; /* \n changed to ; */
136static struct op *outtree; /* result from parser */
137
138static xint *failpt;
139static xint *errpt;
140static struct brkcon *brklist;
141static int isbreak;
142static int newfile(char *s);
143static char *findeq(char *cp);
144static char *cclass(char *p, int sub);
145static void initarea(void);
146extern int msh_main(int argc, char **argv);
147
148
149struct brkcon {
150 jmp_buf brkpt;
151 struct brkcon *nextlev;
152} ;
153
154/*
155 * redirection
156 */
157struct ioword {
158 short io_unit; /* unit affected */
159 short io_flag; /* action (below) */
160 char *io_name; /* file name */
161};
162#define IOREAD 1 /* < */
163#define IOHERE 2 /* << (here file) */
164#define IOWRITE 4 /* > */
165#define IOCAT 8 /* >> */
166#define IOXHERE 16 /* ${}, ` in << */
167#define IODUP 32 /* >&digit */
168#define IOCLOSE 64 /* >&- */
169
170#define IODEFAULT (-1) /* token for default IO unit */
171
172static struct wdblock *wdlist;
173static struct wdblock *iolist;
174
175/*
176 * parsing & execution environment
177 */
178static struct env {
179 char *linep;
180 struct io *iobase;
181 struct io *iop;
182 xint *errpt;
183 int iofd;
184 struct env *oenv;
185} e;
186
187/*
188 * flags:
189 * -e: quit on error
190 * -k: look for name=value everywhere on command line
191 * -n: no execution
192 * -t: exit after reading and executing one command
193 * -v: echo as read
194 * -x: trace
195 * -u: unset variables net diagnostic
196 */
197static char *flag;
198
199static char *null; /* null value for variable */
200static int intr; /* interrupt pending */
201
202static char *trap[_NSIG+1];
203static char ourtrap[_NSIG+1];
204static int trapset; /* trap pending */
205
206static int heedint; /* heed interrupt signals */
207
208static int yynerrs; /* yacc */
209
210static char line[LINELIM];
211static char *elinep;
212
213/*
214 * other functions
215 */
216static int (*inbuilt(char *s ))(void);
217
218static char *rexecve (char *c , char **v, char **envp );
219static char *space (int n );
220static char *strsave (char *s, int a );
221static char *evalstr (char *cp, int f );
222static char *putn (int n );
223static char *itoa (unsigned u, int n );
224static char *unquote (char *as );
225static struct var *lookup (char *n );
226static int rlookup (char *n );
227static struct wdblock *glob (char *cp, struct wdblock *wb );
228static int my_getc( int ec);
229static int subgetc (int ec, int quoted );
230static char **makenv (void);
231static char **eval (char **ap, int f );
232static int setstatus (int s );
233static int waitfor (int lastpid, int canintr );
234
235static void onintr (int s ); /* SIGINT handler */
236
237static int newenv (int f );
238static void quitenv (void);
239static void err (char *s );
240static int anys (char *s1, char *s2 );
241static int any (int c, char *s );
242static void next (int f );
243static void setdash (void);
244static void onecommand (void);
245static void runtrap (int i );
246static int gmatch (char *s, char *p );
247
248/*
249 * error handling
250 */
251static void leave (void); /* abort shell (or fail in subshell) */
252static void fail (void); /* fail but return to process next command */
253static void warn (char *s );
254static void sig (int i ); /* default signal handler */
255
256
257
258/* -------- area stuff -------- */
259
260#define REGSIZE sizeof(struct region)
261#define GROWBY 256
262//#define SHRINKBY 64
263#undef SHRINKBY
264#define FREE 32767
265#define BUSY 0
266#define ALIGN (sizeof(int)-1)
267
268
269struct region {
270 struct region *next;
271 int area;
272};
273
274
275
276/* -------- grammar stuff -------- */
277typedef union {
278 char *cp;
279 char **wp;
280 int i;
281 struct op *o;
282} YYSTYPE;
283#define WORD 256
284#define LOGAND 257
285#define LOGOR 258
286#define BREAK 259
287#define IF 260
288#define THEN 261
289#define ELSE 262
290#define ELIF 263
291#define FI 264
292#define CASE 265
293#define ESAC 266
294#define FOR 267
295#define WHILE 268
296#define UNTIL 269
297#define DO 270
298#define DONE 271
299#define IN 272
300#define YYERRCODE 300
301
302/* flags to yylex */
303#define CONTIN 01 /* skip new lines to complete command */
304
305#define SYNTAXERR zzerr()
306static struct op *pipeline(int cf );
307static struct op *andor(void);
308static struct op *c_list(void);
309static int synio(int cf );
310static void musthave (int c, int cf );
311static struct op *simple(void);
312static struct op *nested(int type, int mark );
313static struct op *command(int cf );
314static struct op *dogroup(int onlydone );
315static struct op *thenpart(void);
316static struct op *elsepart(void);
317static struct op *caselist(void);
318static struct op *casepart(void);
319static char **pattern(void);
320static char **wordlist(void);
321static struct op *list(struct op *t1, struct op *t2 );
322static struct op *block(int type, struct op *t1, struct op *t2, char **wp );
323static struct op *newtp(void);
324static struct op *namelist(struct op *t );
325static char **copyw(void);
326static void word(char *cp );
327static struct ioword **copyio(void);
328static struct ioword *io (int u, int f, char *cp );
329static void zzerr(void);
330static void yyerror(char *s );
331static int yylex(int cf );
332static int collect(int c, int c1 );
333static int dual(int c );
334static void diag(int ec );
335static char *tree(unsigned size );
336
337/* -------- var.h -------- */
338
339struct var {
340 char *value;
341 char *name;
342 struct var *next;
343 char status;
344};
345#define COPYV 1 /* flag to setval, suggesting copy */
346#define RONLY 01 /* variable is read-only */
347#define EXPORT 02 /* variable is to be exported */
348#define GETCELL 04 /* name & value space was got with getcell */
349
350static struct var *vlist; /* dictionary */
351
352static struct var *homedir; /* home directory */
353static struct var *prompt; /* main prompt */
354static struct var *cprompt; /* continuation prompt */
355static struct var *path; /* search path for commands */
356static struct var *shell; /* shell to interpret command files */
357static struct var *ifs; /* field separators */
358
359static int yyparse (void);
360static struct var *lookup (char *n );
361static void setval (struct var *vp, char *val );
362static void nameval (struct var *vp, char *val, char *name );
363static void export (struct var *vp );
364static void ronly (struct var *vp );
365static int isassign (char *s );
366static int checkname (char *cp );
367static int assign (char *s, int cf );
368static void putvlist (int f, int out );
369static int eqname (char *n1, char *n2 );
370
371static int execute (struct op *t, int *pin, int *pout, int act );
372
373/* -------- io.h -------- */
374/* io buffer */
375struct iobuf {
376 unsigned id; /* buffer id */
377 char buf[512]; /* buffer */
378 char *bufp; /* pointer into buffer */
379 char *ebufp; /* pointer to end of buffer */
380};
381
382/* possible arguments to an IO function */
383struct ioarg {
384 char *aword;
385 char **awordlist;
386 int afile; /* file descriptor */
387 unsigned afid; /* buffer id */
388 long afpos; /* file position */
389 struct iobuf *afbuf; /* buffer for this file */
390};
391//static struct ioarg ioargstack[NPUSH];
392#define AFID_NOBUF (~0)
393#define AFID_ID 0
394
395/* an input generator's state */
396struct io {
397 int (*iofn)();
398 struct ioarg *argp;
399 int peekc;
400 char prev; /* previous character read by readc() */
401 char nlcount; /* for `'s */
402 char xchar; /* for `'s */
403 char task; /* reason for pushed IO */
404};
405//static struct io iostack[NPUSH];
406#define XOTHER 0 /* none of the below */
407#define XDOLL 1 /* expanding ${} */
408#define XGRAVE 2 /* expanding `'s */
409#define XIO 3 /* file IO */
410
411/* in substitution */
412#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
413
414/*
415 * input generators for IO structure
416 */
417static int nlchar (struct ioarg *ap );
418static int strchar (struct ioarg *ap );
419static int qstrchar (struct ioarg *ap );
420static int filechar (struct ioarg *ap );
421static int herechar (struct ioarg *ap );
422static int linechar (struct ioarg *ap );
423static int gravechar (struct ioarg *ap, struct io *iop );
424static int qgravechar (struct ioarg *ap, struct io *iop );
425static int dolchar (struct ioarg *ap );
426static int wdchar (struct ioarg *ap );
427static void scraphere (void);
428static void freehere (int area );
429static void gethere (void);
430static void markhere (char *s, struct ioword *iop );
431static int herein (char *hname, int xdoll );
432static int run (struct ioarg *argp, int (*f)());
433
434/*
435 * IO functions
436 */
437static int eofc (void);
438static int readc (void);
439static void unget (int c );
440static void ioecho (int c );
441static void prs (char *s );
442static void prn (unsigned u );
443static void closef (int i );
444static void closeall (void);
445
446/*
447 * IO control
448 */
449static void pushio (struct ioarg *argp, int (*fn)());
450static int remap (int fd );
451static int openpipe (int *pv );
452static void closepipe (int *pv );
453static struct io *setbase (struct io *ip );
454
455static struct ioarg temparg; /* temporary for PUSHIO */
456#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
457#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
458
459/* -------- word.h -------- */
460
461#define NSTART 16 /* default number of words to allow for initially */
462
463struct wdblock {
464 short w_bsize;
465 short w_nword;
466 /* bounds are arbitrary */
467 char *w_words[1];
468};
469
470static struct wdblock *addword (char *wd, struct wdblock *wb );
471static struct wdblock *newword (int nw );
472static char **getwords (struct wdblock *wb );
473
474/* -------- area.h -------- */
475
476/*
477 * storage allocation
478 */
479static char *getcell (unsigned nbytes );
480static void garbage (void);
481static void setarea (char *cp, int a );
482static int getarea (char *cp );
483static void freearea (int a );
484static void freecell (char *cp );
485static int areanum; /* current allocation area */
486
487#define NEW(type) (type *)getcell(sizeof(type))
488#define DELETE(obj) freecell((char *)obj)
489
490
491/* -------- misc stuff -------- */
492
493static int forkexec (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked );
494static int iosetup (struct ioword *iop, int pipein, int pipeout );
495static void echo(char **wp );
496static struct op **find1case (struct op *t, char *w );
497static struct op *findcase (struct op *t, char *w );
498static void brkset(struct brkcon *bc );
499static int dolabel(void);
500static int dohelp(void);
501static int dochdir(struct op *t );
502static int doshift(struct op *t );
503static int dologin(struct op *t );
504static int doumask(struct op *t );
505static int doexec(struct op *t );
506static int dodot(struct op *t );
507static int dowait(struct op *t );
508static int doread(struct op *t );
509static int doeval(struct op *t );
510static int dotrap(struct op *t );
511static int getsig(char *s );
512static void setsig (int n, void (*f)());
513static int getn(char *as );
514static int dobreak(struct op *t );
515static int docontinue(struct op *t );
516static int brkcontin (char *cp, int val );
517static int doexit(struct op *t );
518static int doexport(struct op *t );
519static int doreadonly(struct op *t );
520static void rdexp (char **wp, void (*f)(), int key);
521static void badid(char *s );
522static int doset(struct op *t );
523static void varput (char *s, int out );
524static int dotimes(void);
525static int expand (char *cp, struct wdblock **wbp, int f );
526static char *blank(int f );
527static int dollar(int quoted );
528static int grave(int quoted );
529static void globname (char *we, char *pp );
530static char *generate (char *start1, char *end1, char *middle, char *end );
531static int anyspcl(struct wdblock *wb );
532static int xstrcmp (char *p1, char *p2 );
533static void glob0 (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *));
534static void glob1 (char *base, char *lim );
535static void glob2 (char *i, char *j );
536static void glob3 (char *i, char *j, char *k );
537static void readhere (char **name, char *s, int ec );
538static void pushio(struct ioarg *argp, int (*fn)());
539static int xxchar(struct ioarg *ap );
540
541struct here {
542 char *h_tag;
543 int h_dosub;
544 struct ioword *h_iop;
545 struct here *h_next;
546};
547
548static char *signame[] = {
549 "Signal 0",
550 "Hangup",
551 (char *)NULL, /* interrupt */
552 "Quit",
553 "Illegal instruction",
554 "Trace/BPT trap",
555 "Abort",
556 "Bus error",
557 "Floating Point Exception",
558 "Killed",
559 "SIGUSR1",
560 "SIGSEGV",
561 "SIGUSR2",
562 (char *)NULL, /* broken pipe */
563 "Alarm clock",
564 "Terminated",
565};
566#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
567
568struct res {
569 char *r_name;
570 int r_val;
571};
572static struct res restab[] = {
573 {"for", FOR},
574 {"case", CASE},
575 {"esac", ESAC},
576 {"while", WHILE},
577 {"do", DO},
578 {"done", DONE},
579 {"if", IF},
580 {"in", IN},
581 {"then", THEN},
582 {"else", ELSE},
583 {"elif", ELIF},
584 {"until", UNTIL},
585 {"fi", FI},
586
587 {";;", BREAK},
588 {"||", LOGOR},
589 {"&&", LOGAND},
590 {"{", '{'},
591 {"}", '}'},
592 {0, 0},
593};
594
595
596struct builtincmd {
597 const char *name;
598 int (*builtinfunc)();
599};
600static const struct builtincmd builtincmds[] = {
601 {".", dodot},
602 {":", dolabel},
603 {"break", dobreak},
604 {"cd", dochdir},
605 {"continue",docontinue},
606 {"eval", doeval},
607 {"exec", doexec},
608 {"exit", doexit},
609 {"export", doexport},
610 {"help", dohelp},
611 {"login", dologin},
612 {"newgrp", dologin},
613 {"read", doread},
614 {"readonly",doreadonly},
615 {"set", doset},
616 {"shift", doshift},
617 {"times", dotimes},
618 {"trap", dotrap},
619 {"umask", doumask},
620 {"wait", dowait},
621 {0,0}
622};
623
624/* Globals */
625extern char **environ; /* environment pointer */
626static char **dolv;
627static int dolc;
628static int exstat;
629static char gflg;
630static int interactive; /* Is this an interactive shell */
631static int execflg;
632static int multiline; /* \n changed to ; */
633static struct op *outtree; /* result from parser */
634static xint *failpt;
635static xint *errpt;
636static struct brkcon *brklist;
637static int isbreak;
638static struct wdblock *wdlist;
639static struct wdblock *iolist;
640static char *trap[_NSIG+1];
641static char ourtrap[_NSIG+1];
642static int trapset; /* trap pending */
643static int yynerrs; /* yacc */
644static char line[LINELIM];
645static struct var *vlist; /* dictionary */
646static struct var *homedir; /* home directory */
647static struct var *prompt; /* main prompt */
648static struct var *cprompt; /* continuation prompt */
649static struct var *path; /* search path for commands */
650static struct var *shell; /* shell to interpret command files */
651static struct var *ifs; /* field separators */
652static struct ioarg ioargstack[NPUSH];
653static struct io iostack[NPUSH];
654static int areanum; /* current allocation area */
655static int intr;
656static int inparse;
657static char flags['z'-'a'+1];
658static char *flag = flags-'a';
659static char *elinep = line+sizeof(line)-5;
660static char *null = "";
661static int heedint =1;
662static struct env e ={line, iostack, iostack-1, (xint *)NULL, FDBASE, (struct env *)NULL};
663static void (*qflag)(int) = SIG_IGN;
664static char shellname[] = "/bin/sh";
665static char search[] = ":/bin:/usr/bin";
666static int startl;
667static int peeksym;
668static int nlseen;
669static int iounit = IODEFAULT;
670static YYSTYPE yylval;
671static struct iobuf sharedbuf = {AFID_NOBUF};
672static struct iobuf mainbuf = {AFID_NOBUF};
673static unsigned bufid = AFID_ID; /* buffer id counter */
674static struct ioarg temparg = {0, 0, 0, AFID_NOBUF, 0};
675static struct here *inhere; /* list of hear docs while parsing */
676static struct here *acthere; /* list of active here documents */
677static struct region *areabot; /* bottom of area */
678static struct region *areatop; /* top of area */
679static struct region *areanxt; /* starting point of scan */
680static void * brktop;
681static void * brkaddr;
682
683
684#ifdef BB_FEATURE_COMMAND_EDITING
685static char * current_prompt;
686#endif
687
688
689/* -------- sh.c -------- */
690/*
691 * shell
692 */
693
694
695extern int msh_main(int argc, char **argv)
696{
697 register int f;
698 register char *s;
699 int cflag;
700 char *name, **ap;
701 int (*iof)();
702
703 initarea();
704 if ((ap = environ) != NULL) {
705 while (*ap)
706 assign(*ap++, !COPYV);
707 for (ap = environ; *ap;)
708 export(lookup(*ap++));
709 }
710 closeall();
711 areanum = 1;
712
713 shell = lookup("SHELL");
714 if (shell->value == null)
715 setval(shell, shellname);
716 export(shell);
717
718 homedir = lookup("HOME");
719 if (homedir->value == null)
720 setval(homedir, "/");
721 export(homedir);
722
723 setval(lookup("$"), itoa(getpid(), 5));
724
725 path = lookup("PATH");
726 if (path->value == null)
727 setval(path, search);
728 export(path);
729
730 ifs = lookup("IFS");
731 if (ifs->value == null)
732 setval(ifs, " \t\n");
733
734 prompt = lookup("PS1");
735#ifdef BB_FEATURE_SH_FANCY_PROMPT
736 if (prompt->value == null)
737#endif
738 setval(prompt, "$ ");
739 if (geteuid() == 0) {
740 setval(prompt, "# ");
741 prompt->status &= ~EXPORT;
742 }
743 cprompt = lookup("PS2");
744#ifdef BB_FEATURE_SH_FANCY_PROMPT
745 if (cprompt->value == null)
746#endif
747 setval(cprompt, "> ");
748
749 iof = filechar;
750 cflag = 0;
751 name = *argv++;
752 if (--argc >= 1) {
753 if(argv[0][0] == '-' && argv[0][1] != '\0') {
754 for (s = argv[0]+1; *s; s++)
755 switch (*s) {
756 case 'c':
757 prompt->status &= ~EXPORT;
758 cprompt->status &= ~EXPORT;
759 setval(prompt, "");
760 setval(cprompt, "");
761 cflag = 1;
762 if (--argc > 0)
763 PUSHIO(aword, *++argv, iof = nlchar);
764 break;
765
766 case 'q':
767 qflag = SIG_DFL;
768 break;
769
770 case 's':
771 /* standard input */
772 break;
773
774 case 't':
775 prompt->status &= ~EXPORT;
776 setval(prompt, "");
777 iof = linechar;
778 break;
779
780 case 'i':
781 interactive++;
782 default:
783 if (*s>='a' && *s<='z')
784 flag[(int)*s]++;
785 }
786 } else {
787 argv--;
788 argc++;
789 }
790 if (iof == filechar && --argc > 0) {
791 setval(prompt, "");
792 setval(cprompt, "");
793 prompt->status &= ~EXPORT;
794 cprompt->status &= ~EXPORT;
795 if (newfile(name = *++argv))
796 exit(1);
797 }
798 }
799 setdash();
800 if (e.iop < iostack) {
801 PUSHIO(afile, 0, iof);
802 if (isatty(0) && isatty(1) && !cflag) {
803 interactive++;
804#ifndef BB_FEATURE_SH_EXTRA_QUIET
805 printf( "\n\n" BB_BANNER " Built-in shell (msh)\n");
806 printf( "Enter 'help' for a list of built-in commands.\n\n");
807#endif
808 }
809 }
810 signal(SIGQUIT, qflag);
811 if (name && name[0] == '-') {
812 interactive++;
813 if ((f = open(".profile", 0)) >= 0)
814 next(remap(f));
815 if ((f = open("/etc/profile", 0)) >= 0)
816 next(remap(f));
817 }
818 if (interactive)
819 signal(SIGTERM, sig);
820 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
821 signal(SIGINT, onintr);
822 dolv = argv;
823 dolc = argc;
824 dolv[0] = name;
825 if (dolc > 1) {
826 for (ap = ++argv; --argc > 0;) {
827 if (assign(*ap = *argv++, !COPYV)) {
828 dolc--; /* keyword */
829 } else {
830 ap++;
831 }
832 }
833 }
834 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
835
836 for (;;) {
837 if (interactive && e.iop <= iostack) {
838#ifdef BB_FEATURE_COMMAND_EDITING
839 current_prompt=prompt->value;
840#else
841 prs(prompt->value);
842#endif
843 }
844 onecommand();
845 }
846}
847
848static void
849setdash()
850{
851 register char *cp;
852 register int c;
853 char m['z'-'a'+1];
854
855 cp = m;
856 for (c='a'; c<='z'; c++)
857 if (flag[c])
858 *cp++ = c;
859 *cp = 0;
860 setval(lookup("-"), m);
861}
862
863static int
864newfile(s)
865register char *s;
866{
867 register int f;
868
869 if (strcmp(s, "-") != 0) {
870 f = open(s, 0);
871 if (f < 0) {
872 prs(s);
873 err(": cannot open");
874 return(1);
875 }
876 } else
877 f = 0;
878 next(remap(f));
879 return(0);
880}
881
882static void
883onecommand()
884{
885 register int i;
886 jmp_buf m1;
887
888 while (e.oenv)
889 quitenv();
890 areanum = 1;
891 freehere(areanum);
892 freearea(areanum);
893 garbage();
894 wdlist = 0;
895 iolist = 0;
896 e.errpt = 0;
897 e.linep = line;
898 yynerrs = 0;
899 multiline = 0;
900 inparse = 1;
901 intr = 0;
902 execflg = 0;
903 setjmp(failpt = m1); /* Bruce Evans' fix */
904 if (setjmp(failpt = m1) || yyparse() || intr) {
905 while (e.oenv)
906 quitenv();
907 scraphere();
908 if (!interactive && intr)
909 leave();
910 inparse = 0;
911 intr = 0;
912 return;
913 }
914 inparse = 0;
915 brklist = 0;
916 intr = 0;
917 execflg = 0;
918 if (!flag['n'])
919 execute(outtree, NOPIPE, NOPIPE, 0);
920 if (!interactive && intr) {
921 execflg = 0;
922 leave();
923 }
924 if ((i = trapset) != 0) {
925 trapset = 0;
926 runtrap(i);
927 }
928}
929
930static void
931fail()
932{
933 longjmp(failpt, 1);
934 /* NOTREACHED */
935}
936
937static void
938leave()
939{
940 if (execflg)
941 fail();
942 scraphere();
943 freehere(1);
944 runtrap(0);
945 exit(exstat);
946 /* NOTREACHED */
947}
948
949static void
950warn(s)
951register char *s;
952{
953 if(*s) {
954 prs(s);
955 exstat = -1;
956 }
957 prs("\n");
958 if (flag['e'])
959 leave();
960}
961
962static void
963err(s)
964char *s;
965{
966 warn(s);
967 if (flag['n'])
968 return;
969 if (!interactive)
970 leave();
971 if (e.errpt)
972 longjmp(e.errpt, 1);
973 closeall();
974 e.iop = e.iobase = iostack;
975}
976
977static int
978newenv(f)
979int f;
980{
981 register struct env *ep;
982
983 if (f) {
984 quitenv();
985 return(1);
986 }
987 ep = (struct env *) space(sizeof(*ep));
988 if (ep == NULL) {
989 while (e.oenv)
990 quitenv();
991 fail();
992 }
993 *ep = e;
994 e.oenv = ep;
995 e.errpt = errpt;
996 return(0);
997}
998
999static void
1000quitenv()
1001{
1002 register struct env *ep;
1003 register int fd;
1004
1005 if ((ep = e.oenv) != NULL) {
1006 fd = e.iofd;
1007 e = *ep;
1008 /* should close `'d files */
1009 DELETE(ep);
1010 while (--fd >= e.iofd)
1011 close(fd);
1012 }
1013}
1014
1015/*
1016 * Is any character from s1 in s2?
1017 */
1018static int
1019anys(s1, s2)
1020register char *s1, *s2;
1021{
1022 while (*s1)
1023 if (any(*s1++, s2))
1024 return(1);
1025 return(0);
1026}
1027
1028/*
1029 * Is character c in s?
1030 */
1031static int
1032any(c, s)
1033register int c;
1034register char *s;
1035{
1036 while (*s)
1037 if (*s++ == c)
1038 return(1);
1039 return(0);
1040}
1041
1042static char *
1043putn(n)
1044register int n;
1045{
1046 return(itoa(n, -1));
1047}
1048
1049static char *
1050itoa(u, n)
1051register unsigned u;
1052int n;
1053{
1054 register char *cp;
1055 static char s[20];
1056 int m;
1057
1058 m = 0;
1059 if (n < 0 && (int) u < 0) {
1060 m++;
1061 u = -u;
1062 }
1063 cp = s+sizeof(s);
1064 *--cp = 0;
1065 do {
1066 *--cp = u%10 + '0';
1067 u /= 10;
1068 } while (--n > 0 || u);
1069 if (m)
1070 *--cp = '-';
1071 return(cp);
1072}
1073
1074static void
1075next(f)
1076int f;
1077{
1078 PUSHIO(afile, f, filechar);
1079}
1080
1081static void
1082onintr(s)
1083int s; /* ANSI C requires a parameter */
1084{
1085 signal(SIGINT, onintr);
1086 intr = 1;
1087 if (interactive) {
1088 if (inparse) {
1089 prs("\n");
1090 fail();
1091 }
1092 }
1093 else if (heedint) {
1094 execflg = 0;
1095 leave();
1096 }
1097}
1098
1099static char *
1100space(n)
1101int n;
1102{
1103 register char *cp;
1104
1105 if ((cp = getcell(n)) == 0)
1106 err("out of string space");
1107 return(cp);
1108}
1109
1110static char *
1111strsave(s, a)
1112register char *s;
1113int a;
1114{
1115 register char *cp, *xp;
1116
1117 if ((cp = space(strlen(s)+1)) != NULL) {
1118 setarea((char *)cp, a);
1119 for (xp = cp; (*xp++ = *s++) != '\0';)
1120 ;
1121 return(cp);
1122 }
1123 return("");
1124}
1125
1126/*
1127 * trap handling
1128 */
1129static void
1130sig(i)
1131register int i;
1132{
1133 trapset = i;
1134 signal(i, sig);
1135}
1136
1137static void runtrap(i)
1138int i;
1139{
1140 char *trapstr;
1141
1142 if ((trapstr = trap[i]) == NULL)
1143 return;
1144 if (i == 0)
1145 trap[i] = 0;
1146 RUN(aword, trapstr, nlchar);
1147}
1148
1149/* -------- var.c -------- */
1150
1151/*
1152 * Find the given name in the dictionary
1153 * and return its value. If the name was
1154 * not previously there, enter it now and
1155 * return a null value.
1156 */
1157static struct var *
1158lookup(n)
1159register char *n;
1160{
1161 register struct var *vp;
1162 register char *cp;
1163 register int c;
1164 static struct var dummy;
1165
1166 if (isdigit(*n)) {
1167 dummy.name = n;
1168 for (c = 0; isdigit(*n) && c < 1000; n++)
1169 c = c*10 + *n-'0';
1170 dummy.status = RONLY;
1171 dummy.value = c <= dolc? dolv[c]: null;
1172 return(&dummy);
1173 }
1174 for (vp = vlist; vp; vp = vp->next)
1175 if (eqname(vp->name, n))
1176 return(vp);
1177 cp = findeq(n);
1178 vp = (struct var *)space(sizeof(*vp));
1179 if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
1180 dummy.name = dummy.value = "";
1181 return(&dummy);
1182 }
1183 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
1184 ;
1185 if (*cp == 0)
1186 *cp = '=';
1187 *++cp = 0;
1188 setarea((char *)vp, 0);
1189 setarea((char *)vp->name, 0);
1190 vp->value = null;
1191 vp->next = vlist;
1192 vp->status = GETCELL;
1193 vlist = vp;
1194 return(vp);
1195}
1196
1197/*
1198 * give variable at `vp' the value `val'.
1199 */
1200static void
1201setval(vp, val)
1202struct var *vp;
1203char *val;
1204{
1205 nameval(vp, val, (char *)NULL);
1206}
1207
1208/*
1209 * if name is not NULL, it must be
1210 * a prefix of the space `val',
1211 * and end with `='.
1212 * this is all so that exporting
1213 * values is reasonably painless.
1214 */
1215static void
1216nameval(vp, val, name)
1217register struct var *vp;
1218char *val, *name;
1219{
1220 register char *cp, *xp;
1221 char *nv;
1222 int fl;
1223
1224 if (vp->status & RONLY) {
1225 for (xp = vp->name; *xp && *xp != '=';)
1226 putc(*xp++, stderr);
1227 err(" is read-only");
1228 return;
1229 }
1230 fl = 0;
1231 if (name == NULL) {
1232 xp = space(strlen(vp->name)+strlen(val)+2);
1233 if (xp == 0)
1234 return;
1235 /* make string: name=value */
1236 setarea((char *)xp, 0);
1237 name = xp;
1238 for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
1239 ;
1240 if (*xp++ == 0)
1241 xp[-1] = '=';
1242 nv = xp;
1243 for (cp = val; (*xp++ = *cp++) != '\0';)
1244 ;
1245 val = nv;
1246 fl = GETCELL;
1247 }
1248 if (vp->status & GETCELL)
1249 freecell(vp->name); /* form new string `name=value' */
1250 vp->name = name;
1251 vp->value = val;
1252 vp->status |= fl;
1253}
1254
1255static void
1256export(vp)
1257struct var *vp;
1258{
1259 vp->status |= EXPORT;
1260}
1261
1262static void
1263ronly(vp)
1264struct var *vp;
1265{
1266 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1267 vp->status |= RONLY;
1268}
1269
1270static int
1271isassign(s)
1272register char *s;
1273{
1274 if (!isalpha((int)*s) && *s != '_')
1275 return(0);
1276 for (; *s != '='; s++)
1277 if (*s == 0 || (!isalnum(*s) && *s != '_'))
1278 return(0);
1279 return(1);
1280}
1281
1282static int
1283assign(s, cf)
1284register char *s;
1285int cf;
1286{
1287 register char *cp;
1288 struct var *vp;
1289
1290 if (!isalpha(*s) && *s != '_')
1291 return(0);
1292 for (cp = s; *cp != '='; cp++)
1293 if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
1294 return(0);
1295 vp = lookup(s);
1296 nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
1297 if (cf != COPYV)
1298 vp->status &= ~GETCELL;
1299 return(1);
1300}
1301
1302static int
1303checkname(cp)
1304register char *cp;
1305{
1306 if (!isalpha(*cp++) && *(cp-1) != '_')
1307 return(0);
1308 while (*cp)
1309 if (!isalnum(*cp++) && *(cp-1) != '_')
1310 return(0);
1311 return(1);
1312}
1313
1314static void
1315putvlist(f, out)
1316register int f, out;
1317{
1318 register struct var *vp;
1319
1320 for (vp = vlist; vp; vp = vp->next)
1321 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1322 if (vp->status & EXPORT)
1323 write(out, "export ", 7);
1324 if (vp->status & RONLY)
1325 write(out, "readonly ", 9);
1326 write(out, vp->name, (int)(findeq(vp->name) - vp->name));
1327 write(out, "\n", 1);
1328 }
1329}
1330
1331static int
1332eqname(n1, n2)
1333register char *n1, *n2;
1334{
1335 for (; *n1 != '=' && *n1 != 0; n1++)
1336 if (*n2++ != *n1)
1337 return(0);
1338 return(*n2 == 0 || *n2 == '=');
1339}
1340
1341static char *
1342findeq(cp)
1343register char *cp;
1344{
1345 while (*cp != '\0' && *cp != '=')
1346 cp++;
1347 return(cp);
1348}
1349
1350/* -------- gmatch.c -------- */
1351/*
1352 * int gmatch(string, pattern)
1353 * char *string, *pattern;
1354 *
1355 * Match a pattern as in sh(1).
1356 */
1357
1358#define CMASK 0377
1359#define QUOTE 0200
1360#define QMASK (CMASK&~QUOTE)
1361#define NOT '!' /* might use ^ */
1362
1363static int
1364gmatch(s, p)
1365register char *s, *p;
1366{
1367 register int sc, pc;
1368
1369 if (s == NULL || p == NULL)
1370 return(0);
1371 while ((pc = *p++ & CMASK) != '\0') {
1372 sc = *s++ & QMASK;
1373 switch (pc) {
1374 case '[':
1375 if ((p = cclass(p, sc)) == NULL)
1376 return(0);
1377 break;
1378
1379 case '?':
1380 if (sc == 0)
1381 return(0);
1382 break;
1383
1384 case '*':
1385 s--;
1386 do {
1387 if (*p == '\0' || gmatch(s, p))
1388 return(1);
1389 } while (*s++ != '\0');
1390 return(0);
1391
1392 default:
1393 if (sc != (pc&~QUOTE))
1394 return(0);
1395 }
1396 }
1397 return(*s == 0);
1398}
1399
1400static char *
1401cclass(p, sub)
1402register char *p;
1403register int sub;
1404{
1405 register int c, d, not, found;
1406
1407 if ((not = *p == NOT) != 0)
1408 p++;
1409 found = not;
1410 do {
1411 if (*p == '\0')
1412 return((char *)NULL);
1413 c = *p & CMASK;
1414 if (p[1] == '-' && p[2] != ']') {
1415 d = p[2] & CMASK;
1416 p++;
1417 } else
1418 d = c;
1419 if (c == sub || (c <= sub && sub <= d))
1420 found = !not;
1421 } while (*++p != ']');
1422 return(found? p+1: (char *)NULL);
1423}
1424
1425
1426/* -------- area.c -------- */
1427
1428/*
1429 * All memory between (char *)areabot and (char *)(areatop+1) is
1430 * exclusively administered by the area management routines.
1431 * It is assumed that sbrk() and brk() manipulate the high end.
1432 */
1433
1434#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
1435
1436static void
1437initarea()
1438{
1439 brkaddr = malloc(65000);
1440 brktop = brkaddr + 65000;
1441
1442 while ((int)sbrk(0) & ALIGN)
1443 sbrk(1);
1444 areabot = (struct region *)sbrk(REGSIZE);
1445
1446 areabot->next = areabot;
1447 areabot->area = BUSY;
1448 areatop = areabot;
1449 areanxt = areabot;
1450}
1451
1452char *
1453getcell(nbytes)
1454unsigned nbytes;
1455{
1456 register int nregio;
1457 register struct region *p, *q;
1458 register int i;
1459
1460 if (nbytes == 0) {
1461 puts("getcell(0)");
1462 abort();
1463 } /* silly and defeats the algorithm */
1464 /*
1465 * round upwards and add administration area
1466 */
1467 nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
1468 for (p = areanxt;;) {
1469 if (p->area > areanum) {
1470 /*
1471 * merge free cells
1472 */
1473 while ((q = p->next)->area > areanum && q != areanxt)
1474 p->next = q->next;
1475 /*
1476 * exit loop if cell big enough
1477 */
1478 if (q >= p + nregio)
1479 goto found;
1480 }
1481 p = p->next;
1482 if (p == areanxt)
1483 break;
1484 }
1485 i = nregio >= GROWBY ? nregio : GROWBY;
1486 p = (struct region *)sbrk(i * REGSIZE);
1487 if (p == (struct region *)-1)
1488 return((char *)NULL);
1489 p--;
1490 if (p != areatop) {
1491 puts("not contig");
1492 abort(); /* allocated areas are contiguous */
1493 }
1494 q = p + i;
1495 p->next = q;
1496 p->area = FREE;
1497 q->next = areabot;
1498 q->area = BUSY;
1499 areatop = q;
1500found:
1501 /*
1502 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
1503 */
1504 areanxt = p + nregio;
1505 if (areanxt < q) {
1506 /*
1507 * split into requested area and rest
1508 */
1509 if (areanxt+1 > q) {
1510 puts("OOM");
1511 abort(); /* insufficient space left for admin */
1512 }
1513 areanxt->next = q;
1514 areanxt->area = FREE;
1515 p->next = areanxt;
1516 }
1517 p->area = areanum;
1518 return((char *)(p+1));
1519}
1520
1521static void
1522freecell(cp)
1523char *cp;
1524{
1525 register struct region *p;
1526
1527 if ((p = (struct region *)cp) != NULL) {
1528 p--;
1529 if (p < areanxt)
1530 areanxt = p;
1531 p->area = FREE;
1532 }
1533}
1534
1535static void
1536freearea(a)
1537register int a;
1538{
1539 register struct region *p, *top;
1540
1541 top = areatop;
1542 for (p = areabot; p != top; p = p->next)
1543 if (p->area >= a)
1544 p->area = FREE;
1545}
1546
1547static void
1548setarea(cp,a)
1549char *cp;
1550int a;
1551{
1552 register struct region *p;
1553
1554 if ((p = (struct region *)cp) != NULL)
1555 (p-1)->area = a;
1556}
1557
1558int
1559getarea(cp)
1560char *cp;
1561{
1562 return ((struct region*)cp-1)->area;
1563}
1564
1565static void
1566garbage()
1567{
1568 register struct region *p, *q, *top;
1569
1570 top = areatop;
1571 for (p = areabot; p != top; p = p->next) {
1572 if (p->area > areanum) {
1573 while ((q = p->next)->area > areanum)
1574 p->next = q->next;
1575 areanxt = p;
1576 }
1577 }
1578#ifdef SHRINKBY
1579 if (areatop >= q + SHRINKBY && q->area > areanum) {
1580 brk((char *)(q+1));
1581 q->next = areabot;
1582 q->area = BUSY;
1583 areatop = q;
1584 }
1585#endif
1586}
1587
1588/* -------- csyn.c -------- */
1589/*
1590 * shell: syntax (C version)
1591 */
1592
1593
1594int
1595yyparse()
1596{
1597 startl = 1;
1598 peeksym = 0;
1599 yynerrs = 0;
1600 outtree = c_list();
1601 musthave('\n', 0);
1602 return(yynerrs!=0);
1603}
1604
1605static struct op *
1606pipeline(cf)
1607int cf;
1608{
1609 register struct op *t, *p;
1610 register int c;
1611
1612 t = command(cf);
1613 if (t != NULL) {
1614 while ((c = yylex(0)) == '|') {
1615 if ((p = command(CONTIN)) == NULL)
1616 SYNTAXERR;
1617 if (t->type != TPAREN && t->type != TCOM) {
1618 /* shell statement */
1619 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1620 }
1621 t = block(TPIPE, t, p, NOWORDS);
1622 }
1623 peeksym = c;
1624 }
1625 return(t);
1626}
1627
1628static struct op *
1629andor()
1630{
1631 register struct op *t, *p;
1632 register int c;
1633
1634 t = pipeline(0);
1635 if (t != NULL) {
1636 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
1637 if ((p = pipeline(CONTIN)) == NULL)
1638 SYNTAXERR;
1639 t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
1640 }
1641 peeksym = c;
1642 }
1643 return(t);
1644}
1645
1646static struct op *
1647c_list()
1648{
1649 register struct op *t, *p;
1650 register int c;
1651
1652 t = andor();
1653 if (t != NULL) {
1654 if((peeksym = yylex(0)) == '&')
1655 t = block(TASYNC, t, NOBLOCK, NOWORDS);
1656 while ((c = yylex(0)) == ';' || c == '&' || (multiline && c == '\n')) {
1657 if ((p = andor()) == NULL)
1658 return(t);
1659 if((peeksym = yylex(0)) == '&')
1660 p = block(TASYNC, p, NOBLOCK, NOWORDS);
1661 t = list(t, p);
1662 }
1663 peeksym = c;
1664 }
1665 return(t);
1666}
1667
1668
1669static int
1670synio(cf)
1671int cf;
1672{
1673 register struct ioword *iop;
1674 register int i;
1675 register int c;
1676
1677 if ((c = yylex(cf)) != '<' && c != '>') {
1678 peeksym = c;
1679 return(0);
1680 }
1681 i = yylval.i;
1682 musthave(WORD, 0);
1683 iop = io(iounit, i, yylval.cp);
1684 iounit = IODEFAULT;
1685 if (i & IOHERE)
1686 markhere(yylval.cp, iop);
1687 return(1);
1688}
1689
1690static void
1691musthave(c, cf)
1692int c, cf;
1693{
1694 if ((peeksym = yylex(cf)) != c)
1695 SYNTAXERR;
1696 peeksym = 0;
1697}
1698
1699static struct op *
1700simple()
1701{
1702 register struct op *t;
1703
1704 t = NULL;
1705 for (;;) {
1706 switch (peeksym = yylex(0)) {
1707 case '<':
1708 case '>':
1709 (void) synio(0);
1710 break;
1711
1712 case WORD:
1713 if (t == NULL) {
1714 t = newtp();
1715 t->type = TCOM;
1716 }
1717 peeksym = 0;
1718 word(yylval.cp);
1719 break;
1720
1721 default:
1722 return(t);
1723 }
1724 }
1725}
1726
1727static struct op *
1728nested(type, mark)
1729int type, mark;
1730{
1731 register struct op *t;
1732
1733 multiline++;
1734 t = c_list();
1735 musthave(mark, 0);
1736 multiline--;
1737 return(block(type, t, NOBLOCK, NOWORDS));
1738}
1739
1740static struct op *
1741command(cf)
1742int cf;
1743{
1744 register struct op *t;
1745 struct wdblock *iosave;
1746 register int c;
1747
1748 iosave = iolist;
1749 iolist = NULL;
1750 if (multiline)
1751 cf |= CONTIN;
1752 while (synio(cf))
1753 cf = 0;
1754 switch (c = yylex(cf)) {
1755 default:
1756 peeksym = c;
1757 if ((t = simple()) == NULL) {
1758 if (iolist == NULL)
1759 return((struct op *)NULL);
1760 t = newtp();
1761 t->type = TCOM;
1762 }
1763 break;
1764
1765 case '(':
1766 t = nested(TPAREN, ')');
1767 break;
1768
1769 case '{':
1770 t = nested(TBRACE, '}');
1771 break;
1772
1773 case FOR:
1774 t = newtp();
1775 t->type = TFOR;
1776 musthave(WORD, 0);
1777 startl = 1;
1778 t->str = yylval.cp;
1779 multiline++;
1780 t->words = wordlist();
1781 if ((c = yylex(0)) != '\n' && c != ';')
1782 peeksym = c;
1783 t->left = dogroup(0);
1784 multiline--;
1785 break;
1786
1787 case WHILE:
1788 case UNTIL:
1789 multiline++;
1790 t = newtp();
1791 t->type = c == WHILE? TWHILE: TUNTIL;
1792 t->left = c_list();
1793 t->right = dogroup(1);
1794 t->words = NULL;
1795 multiline--;
1796 break;
1797
1798 case CASE:
1799 t = newtp();
1800 t->type = TCASE;
1801 musthave(WORD, 0);
1802 t->str = yylval.cp;
1803 startl++;
1804 multiline++;
1805 musthave(IN, CONTIN);
1806 startl++;
1807 t->left = caselist();
1808 musthave(ESAC, 0);
1809 multiline--;
1810 break;
1811
1812 case IF:
1813 multiline++;
1814 t = newtp();
1815 t->type = TIF;
1816 t->left = c_list();
1817 t->right = thenpart();
1818 musthave(FI, 0);
1819 multiline--;
1820 break;
1821 }
1822 while (synio(0))
1823 ;
1824 t = namelist(t);
1825 iolist = iosave;
1826 return(t);
1827}
1828
1829static struct op *
1830dogroup(onlydone)
1831int onlydone;
1832{
1833 register int c;
1834 register struct op *mylist;
1835
1836 c = yylex(CONTIN);
1837 if (c == DONE && onlydone)
1838 return((struct op *)NULL);
1839 if (c != DO)
1840 SYNTAXERR;
1841 mylist = c_list();
1842 musthave(DONE, 0);
1843 return(mylist);
1844}
1845
1846static struct op *
1847thenpart()
1848{
1849 register int c;
1850 register struct op *t;
1851
1852 if ((c = yylex(0)) != THEN) {
1853 peeksym = c;
1854 return((struct op *)NULL);
1855 }
1856 t = newtp();
1857 t->type = 0;
1858 t->left = c_list();
1859 if (t->left == NULL)
1860 SYNTAXERR;
1861 t->right = elsepart();
1862 return(t);
1863}
1864
1865static struct op *
1866elsepart()
1867{
1868 register int c;
1869 register struct op *t;
1870
1871 switch (c = yylex(0)) {
1872 case ELSE:
1873 if ((t = c_list()) == NULL)
1874 SYNTAXERR;
1875 return(t);
1876
1877 case ELIF:
1878 t = newtp();
1879 t->type = TELIF;
1880 t->left = c_list();
1881 t->right = thenpart();
1882 return(t);
1883
1884 default:
1885 peeksym = c;
1886 return((struct op *)NULL);
1887 }
1888}
1889
1890static struct op *
1891caselist()
1892{
1893 register struct op *t;
1894
1895 t = NULL;
1896 while ((peeksym = yylex(CONTIN)) != ESAC)
1897 t = list(t, casepart());
1898 return(t);
1899}
1900
1901static struct op *
1902casepart()
1903{
1904 register struct op *t;
1905
1906 t = newtp();
1907 t->type = TPAT;
1908 t->words = pattern();
1909 musthave(')', 0);
1910 t->left = c_list();
1911 if ((peeksym = yylex(CONTIN)) != ESAC)
1912 musthave(BREAK, CONTIN);
1913 return(t);
1914}
1915
1916static char **
1917pattern()
1918{
1919 register int c, cf;
1920
1921 cf = CONTIN;
1922 do {
1923 musthave(WORD, cf);
1924 word(yylval.cp);
1925 cf = 0;
1926 } while ((c = yylex(0)) == '|');
1927 peeksym = c;
1928 word(NOWORD);
1929 return(copyw());
1930}
1931
1932static char **
1933wordlist()
1934{
1935 register int c;
1936
1937 if ((c = yylex(0)) != IN) {
1938 peeksym = c;
1939 return((char **)NULL);
1940 }
1941 startl = 0;
1942 while ((c = yylex(0)) == WORD)
1943 word(yylval.cp);
1944 word(NOWORD);
1945 peeksym = c;
1946 return(copyw());
1947}
1948
1949/*
1950 * supporting functions
1951 */
1952static struct op *
1953list(t1, t2)
1954register struct op *t1, *t2;
1955{
1956 if (t1 == NULL)
1957 return(t2);
1958 if (t2 == NULL)
1959 return(t1);
1960 return(block(TLIST, t1, t2, NOWORDS));
1961}
1962
1963static struct op *
1964block(type, t1, t2, wp)
1965int type;
1966struct op *t1, *t2;
1967char **wp;
1968{
1969 register struct op *t;
1970
1971 t = newtp();
1972 t->type = type;
1973 t->left = t1;
1974 t->right = t2;
1975 t->words = wp;
1976 return(t);
1977}
1978
1979static int
1980rlookup(n)
1981register char *n;
1982{
1983 register struct res *rp;
1984
1985 for (rp = restab; rp->r_name; rp++)
1986 if (strcmp(rp->r_name, n) == 0)
1987 return(rp->r_val);
1988 return(0);
1989}
1990
1991static struct op *
1992newtp()
1993{
1994 register struct op *t;
1995
1996 t = (struct op *)tree(sizeof(*t));
1997 t->type = 0;
1998 t->words = NULL;
1999 t->ioact = NULL;
2000 t->left = NULL;
2001 t->right = NULL;
2002 t->str = NULL;
2003 return(t);
2004}
2005
2006static struct op *
2007namelist(t)
2008register struct op *t;
2009{
2010 if (iolist) {
2011 iolist = addword((char *)NULL, iolist);
2012 t->ioact = copyio();
2013 } else
2014 t->ioact = NULL;
2015 if (t->type != TCOM) {
2016 if (t->type != TPAREN && t->ioact != NULL) {
2017 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2018 t->ioact = t->left->ioact;
2019 t->left->ioact = NULL;
2020 }
2021 return(t);
2022 }
2023 word(NOWORD);
2024 t->words = copyw();
2025 return(t);
2026}
2027
2028static char **
2029copyw()
2030{
2031 register char **wd;
2032
2033 wd = getwords(wdlist);
2034 wdlist = 0;
2035 return(wd);
2036}
2037
2038static void
2039word(cp)
2040char *cp;
2041{
2042 wdlist = addword(cp, wdlist);
2043}
2044
2045static struct ioword **
2046copyio()
2047{
2048 register struct ioword **iop;
2049
2050 iop = (struct ioword **) getwords(iolist);
2051 iolist = 0;
2052 return(iop);
2053}
2054
2055static struct ioword *
2056io(u, f, cp)
2057int u;
2058int f;
2059char *cp;
2060{
2061 register struct ioword *iop;
2062
2063 iop = (struct ioword *) tree(sizeof(*iop));
2064 iop->io_unit = u;
2065 iop->io_flag = f;
2066 iop->io_name = cp;
2067 iolist = addword((char *)iop, iolist);
2068 return(iop);
2069}
2070
2071static void
2072zzerr()
2073{
2074 yyerror("syntax error");
2075}
2076
2077static void
2078yyerror(s)
2079char *s;
2080{
2081 yynerrs++;
2082 if (interactive && e.iop <= iostack) {
2083 multiline = 0;
2084 while (eofc() == 0 && yylex(0) != '\n')
2085 ;
2086 }
2087 err(s);
2088 fail();
2089}
2090
2091static int
2092yylex(cf)
2093int cf;
2094{
2095 register int c, c1;
2096 int atstart;
2097
2098 if ((c = peeksym) > 0) {
2099 peeksym = 0;
2100 if (c == '\n')
2101 startl = 1;
2102 return(c);
2103 }
2104 nlseen = 0;
2105 e.linep = line;
2106 atstart = startl;
2107 startl = 0;
2108 yylval.i = 0;
2109
2110loop:
2111 while ((c = my_getc(0)) == ' ' || c == '\t')
2112 ;
2113 switch (c) {
2114 default:
2115 if (any(c, "0123456789")) {
2116 unget(c1 = my_getc(0));
2117 if (c1 == '<' || c1 == '>') {
2118 iounit = c - '0';
2119 goto loop;
2120 }
2121 *e.linep++ = c;
2122 c = c1;
2123 }
2124 break;
2125
2126 case '#':
2127 while ((c = my_getc(0)) != 0 && c != '\n')
2128 ;
2129 unget(c);
2130 goto loop;
2131
2132 case 0:
2133 return(c);
2134
2135 case '$':
2136 *e.linep++ = c;
2137 if ((c = my_getc(0)) == '{') {
2138 if ((c = collect(c, '}')) != '\0')
2139 return(c);
2140 goto pack;
2141 }
2142 break;
2143
2144 case '`':
2145 case '\'':
2146 case '"':
2147 if ((c = collect(c, c)) != '\0')
2148 return(c);
2149 goto pack;
2150
2151 case '|':
2152 case '&':
2153 case ';':
2154 if ((c1 = dual(c)) != '\0') {
2155 startl = 1;
2156 return(c1);
2157 }
2158 startl = 1;
2159 return(c);
2160 case '^':
2161 startl = 1;
2162 return('|');
2163 case '>':
2164 case '<':
2165 diag(c);
2166 return(c);
2167
2168 case '\n':
2169 nlseen++;
2170 gethere();
2171 startl = 1;
2172 if (multiline || cf & CONTIN) {
2173 if (interactive && e.iop <= iostack) {
2174#ifdef BB_FEATURE_COMMAND_EDITING
2175 current_prompt=cprompt->value;
2176#else
2177 prs(cprompt->value);
2178#endif
2179 }
2180 if (cf & CONTIN)
2181 goto loop;
2182 }
2183 return(c);
2184
2185 case '(':
2186 case ')':
2187 startl = 1;
2188 return(c);
2189 }
2190
2191 unget(c);
2192
2193pack:
2194 while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n"))
2195 if (e.linep >= elinep)
2196 err("word too long");
2197 else
2198 *e.linep++ = c;
2199 unget(c);
2200 if(any(c, "\"'`$"))
2201 goto loop;
2202 *e.linep++ = '\0';
2203 if (atstart && (c = rlookup(line))!=0) {
2204 startl = 1;
2205 return(c);
2206 }
2207 yylval.cp = strsave(line, areanum);
2208 return(WORD);
2209}
2210
2211static int
2212collect(c, c1)
2213register int c, c1;
2214{
2215 char s[2];
2216
2217 *e.linep++ = c;
2218 while ((c = my_getc(c1)) != c1) {
2219 if (c == 0) {
2220 unget(c);
2221 s[0] = c1;
2222 s[1] = 0;
2223 prs("no closing "); yyerror(s);
2224 return(YYERRCODE);
2225 }
2226 if (interactive && c == '\n' && e.iop <= iostack) {
2227#ifdef BB_FEATURE_COMMAND_EDITING
2228 current_prompt=cprompt->value;
2229#else
2230 prs(cprompt->value);
2231#endif
2232 }
2233 *e.linep++ = c;
2234 }
2235 *e.linep++ = c;
2236 return(0);
2237}
2238
2239static int
2240dual(c)
2241register int c;
2242{
2243 char s[3];
2244 register char *cp = s;
2245
2246 *cp++ = c;
2247 *cp++ = my_getc(0);
2248 *cp = 0;
2249 if ((c = rlookup(s)) == 0)
2250 unget(*--cp);
2251 return(c);
2252}
2253
2254static void
2255diag(ec)
2256register int ec;
2257{
2258 register int c;
2259
2260 c = my_getc(0);
2261 if (c == '>' || c == '<') {
2262 if (c != ec)
2263 zzerr();
2264 yylval.i = ec == '>'? IOWRITE|IOCAT: IOHERE;
2265 c = my_getc(0);
2266 } else
2267 yylval.i = ec == '>'? IOWRITE: IOREAD;
2268 if (c != '&' || yylval.i == IOHERE)
2269 unget(c);
2270 else
2271 yylval.i |= IODUP;
2272}
2273
2274static char *
2275tree(size)
2276unsigned size;
2277{
2278 register char *t;
2279
2280 if ((t = getcell(size)) == NULL) {
2281 prs("command line too complicated\n");
2282 fail();
2283 /* NOTREACHED */
2284 }
2285 return(t);
2286}
2287
2288/* VARARGS1 */
2289/* ARGSUSED */
2290
2291/* -------- exec.c -------- */
2292
2293/*
2294 * execute tree
2295 */
2296
2297
2298static int
2299execute(t, pin, pout, act)
2300register struct op *t;
2301int *pin, *pout;
2302int act;
2303{
2304 register struct op *t1;
2305 volatile int i, rv, a;
2306 char *cp, **wp, **wp2;
2307 struct var *vp;
2308 struct brkcon bc;
2309
2310#if __GNUC__
2311 /* Avoid longjmp clobbering */
2312 (void) &wp;
2313#endif
2314
2315
2316 if (t == NULL)
2317 return(0);
2318 rv = 0;
2319 a = areanum++;
2320 wp = (wp2 = t->words) != NULL
2321 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2322 : NULL;
2323
2324 switch(t->type) {
2325 case TPAREN:
2326 case TCOM:
2327 {
2328 int child;
2329 rv = forkexec(t, pin, pout, act, wp, &child);
2330 if (child) {
2331 exstat = rv;
2332 leave();
2333 }
2334 }
2335 break;
2336
2337 case TPIPE:
2338 {
2339 int pv[2];
2340 if ((rv = openpipe(pv)) < 0)
2341 break;
2342 pv[0] = remap(pv[0]);
2343 pv[1] = remap(pv[1]);
2344 (void) execute(t->left, pin, pv, 0);
2345 rv = execute(t->right, pv, pout, 0);
2346 }
2347 break;
2348
2349 case TLIST:
2350 (void) execute(t->left, pin, pout, 0);
2351 rv = execute(t->right, pin, pout, 0);
2352 break;
2353
2354 case TASYNC:
2355 {
2356 int hinteractive = interactive;
2357
2358 i = vfork();
2359 if (i != 0) {
2360 interactive = hinteractive;
2361 if (i != -1) {
2362 setval(lookup("!"), putn(i));
2363 if (pin != NULL)
2364 closepipe(pin);
2365 if (interactive) {
2366 prs(putn(i));
2367 prs("\n");
2368 }
2369 } else
2370 rv = -1;
2371 setstatus(rv);
2372 } else {
2373 signal(SIGINT, SIG_IGN);
2374 signal(SIGQUIT, SIG_IGN);
2375 if (interactive)
2376 signal(SIGTERM, SIG_DFL);
2377 interactive = 0;
2378 if (pin == NULL) {
2379 close(0);
2380 open("/dev/null", 0);
2381 }
2382 exit(execute(t->left, pin, pout, FEXEC));
2383 }
2384 }
2385 break;
2386
2387 case TOR:
2388 case TAND:
2389 rv = execute(t->left, pin, pout, 0);
2390 if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND))
2391 rv = execute(t1, pin, pout, 0);
2392 break;
2393
2394 case TFOR:
2395 if (wp == NULL) {
2396 wp = dolv+1;
2397 if ((i = dolc) < 0)
2398 i = 0;
2399 } else {
2400 i = -1;
2401 while (*wp++ != NULL)
2402 ;
2403 }
2404 vp = lookup(t->str);
2405 while (setjmp(bc.brkpt))
2406 if (isbreak)
2407 goto broken;
2408 brkset(&bc);
2409 for (t1 = t->left; i-- && *wp != NULL;) {
2410 setval(vp, *wp++);
2411 rv = execute(t1, pin, pout, 0);
2412 }
2413 brklist = brklist->nextlev;
2414 break;
2415
2416 case TWHILE:
2417 case TUNTIL:
2418 while (setjmp(bc.brkpt))
2419 if (isbreak)
2420 goto broken;
2421 brkset(&bc);
2422 t1 = t->left;
2423 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2424 rv = execute(t->right, pin, pout, 0);
2425 brklist = brklist->nextlev;
2426 break;
2427
2428 case TIF:
2429 case TELIF:
2430 if (t->right != NULL) {
2431 rv = !execute(t->left, pin, pout, 0) ?
2432 execute(t->right->left, pin, pout, 0):
2433 execute(t->right->right, pin, pout, 0);
2434 }
2435 break;
2436
2437 case TCASE:
2438 if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0)
2439 cp = "";
2440 if ((t1 = findcase(t->left, cp)) != NULL)
2441 rv = execute(t1, pin, pout, 0);
2442 break;
2443
2444 case TBRACE:
2445/*
2446 if (iopp = t->ioact)
2447 while (*iopp)
2448 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2449 rv = -1;
2450 break;
2451 }
2452*/
2453 if (rv >= 0 && (t1 = t->left))
2454 rv = execute(t1, pin, pout, 0);
2455 break;
2456 }
2457
2458broken:
2459 t->words = wp2;
2460 isbreak = 0;
2461 freehere(areanum);
2462 freearea(areanum);
2463 areanum = a;
2464 if (interactive && intr) {
2465 closeall();
2466 fail();
2467 }
2468 if ((i = trapset) != 0) {
2469 trapset = 0;
2470 runtrap(i);
2471 }
2472 return(rv);
2473}
2474
2475static int
2476forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *pforked)
2477{
2478 int i, rv;
2479 int (*shcom)() = NULL;
2480 register int f;
2481 char *cp = NULL;
2482 struct ioword **iopp;
2483 int resetsig;
2484 char **owp;
2485
2486 int *hpin = pin;
2487 int *hpout = pout;
2488 int hforked;
2489 char *hwp;
2490 int hinteractive;
2491 int hintr;
2492 struct brkcon * hbrklist;
2493 int hexecflg;
2494
2495#if __GNUC__
2496 /* Avoid longjmp clobbering */
2497 (void) &pin;
2498 (void) &pout;
2499 (void) &wp;
2500 (void) &shcom;
2501 (void) &cp;
2502 (void) &resetsig;
2503 (void) &owp;
2504#endif
2505
2506 owp = wp;
2507 resetsig = 0;
2508 *pforked = 0;
2509 rv = -1; /* system-detected error */
2510 if (t->type == TCOM) {
2511 while ((cp = *wp++) != NULL)
2512 ;
2513 cp = *wp;
2514
2515 /* strip all initial assignments */
2516 /* not correct wrt PATH=yyy command etc */
2517 if (flag['x'])
2518 echo (cp ? wp: owp);
2519 if (cp == NULL && t->ioact == NULL) {
2520 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2521 ;
2522 return(setstatus(0));
2523 }
2524 else if (cp != NULL)
2525 shcom = inbuilt(cp);
2526 }
2527 t->words = wp;
2528 f = act;
2529 if (shcom == NULL && (f & FEXEC) == 0) {
2530
2531 hpin = pin;
2532 hpout = pout;
2533 hforked = *pforked;
2534 hwp = *wp;
2535 hinteractive = interactive;
2536 hintr = intr;
2537 hbrklist = brklist;
2538 hexecflg = execflg;
2539
2540 i = vfork();
2541 if (i != 0) {
2542 /* who wrote this crappy non vfork safe shit? */
2543 pin = hpin;
2544 pout = hpout;
2545 *pforked = hforked;
2546 *wp = hwp;
2547 interactive = hinteractive;
2548 intr = hintr;
2549 brklist = hbrklist;
2550 execflg = hexecflg;
2551
2552 *pforked = 0;
2553 if (i == -1)
2554 return(rv);
2555 if (pin != NULL)
2556 closepipe(pin);
2557 return(pout==NULL? setstatus(waitfor(i,0)): 0);
2558 }
2559
2560 if (interactive) {
2561 signal(SIGINT, SIG_IGN);
2562 signal(SIGQUIT, SIG_IGN);
2563 resetsig = 1;
2564 }
2565 interactive = 0;
2566 intr = 0;
2567 (*pforked)++;
2568 brklist = 0;
2569 execflg = 0;
2570 }
2571 if (owp != NULL)
2572 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2573 if (shcom == NULL)
2574 export(lookup(cp));
2575#ifdef COMPIPE
2576 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2577 err("piping to/from shell builtins not yet done");
2578 return(-1);
2579 }
2580#endif
2581 if (pin != NULL) {
2582 dup2(pin[0], 0);
2583 closepipe(pin);
2584 }
2585 if (pout != NULL) {
2586 dup2(pout[1], 1);
2587 closepipe(pout);
2588 }
2589 if ((iopp = t->ioact) != NULL) {
2590 if (shcom != NULL && shcom != doexec) {
2591 prs(cp);
2592 err(": cannot redirect shell command");
2593 return(-1);
2594 }
2595 while (*iopp)
2596 if (iosetup(*iopp++, pin!=NULL, pout!=NULL))
2597 return(rv);
2598 }
2599 if (shcom)
2600 return(setstatus((*shcom)(t)));
2601 /* should use FIOCEXCL */
2602 for (i=FDBASE; i<NOFILE; i++)
2603 close(i);
2604 if (resetsig) {
2605 signal(SIGINT, SIG_DFL);
2606 signal(SIGQUIT, SIG_DFL);
2607 }
2608 if (t->type == TPAREN)
2609 exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2610 if (wp[0] == NULL)
2611 exit(0);
2612
2613 cp = rexecve(wp[0], wp, makenv());
2614 prs(wp[0]); prs(": "); warn(cp);
2615 if (!execflg)
2616 trap[0] = NULL;
2617 leave();
2618 /* NOTREACHED */
2619 exit(1);
2620}
2621
2622/*
2623 * 0< 1> are ignored as required
2624 * within pipelines.
2625 */
2626static int
2627iosetup(iop, pipein, pipeout)
2628register struct ioword *iop;
2629int pipein, pipeout;
2630{
2631 register int u = -1;
2632 char *cp=NULL, *msg;
2633
2634 if (iop->io_unit == IODEFAULT) /* take default */
2635 iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1;
2636 if (pipein && iop->io_unit == 0)
2637 return(0);
2638 if (pipeout && iop->io_unit == 1)
2639 return(0);
2640 msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create";
2641 if ((iop->io_flag & IOHERE) == 0) {
2642 cp = iop->io_name;
2643 if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL)
2644 return(1);
2645 }
2646 if (iop->io_flag & IODUP) {
2647 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2648 prs(cp);
2649 err(": illegal >& argument");
2650 return(1);
2651 }
2652 if (*cp == '-')
2653 iop->io_flag = IOCLOSE;
2654 iop->io_flag &= ~(IOREAD|IOWRITE);
2655 }
2656 switch (iop->io_flag) {
2657 case IOREAD:
2658 u = open(cp, 0);
2659 break;
2660
2661 case IOHERE:
2662 case IOHERE|IOXHERE:
2663 u = herein(iop->io_name, iop->io_flag&IOXHERE);
2664 cp = "here file";
2665 break;
2666
2667 case IOWRITE|IOCAT:
2668 if ((u = open(cp, 1)) >= 0) {
2669 lseek(u, (long)0, 2);
2670 break;
2671 }
2672 case IOWRITE:
2673 u = creat(cp, 0666);
2674 break;
2675
2676 case IODUP:
2677 u = dup2(*cp-'0', iop->io_unit);
2678 break;
2679
2680 case IOCLOSE:
2681 close(iop->io_unit);
2682 return(0);
2683 }
2684 if (u < 0) {
2685 prs(cp);
2686 prs(": cannot ");
2687 warn(msg);
2688 return(1);
2689 } else {
2690 if (u != iop->io_unit) {
2691 dup2(u, iop->io_unit);
2692 close(u);
2693 }
2694 }
2695 return(0);
2696}
2697
2698static void
2699echo(wp)
2700register char **wp;
2701{
2702 register int i;
2703
2704 prs("+");
2705 for (i=0; wp[i]; i++) {
2706 if (i)
2707 prs(" ");
2708 prs(wp[i]);
2709 }
2710 prs("\n");
2711}
2712
2713static struct op **
2714find1case(t, w)
2715struct op *t;
2716char *w;
2717{
2718 register struct op *t1;
2719 struct op **tp;
2720 register char **wp, *cp;
2721
2722 if (t == NULL)
2723 return((struct op **)NULL);
2724 if (t->type == TLIST) {
2725 if ((tp = find1case(t->left, w)) != NULL)
2726 return(tp);
2727 t1 = t->right; /* TPAT */
2728 } else
2729 t1 = t;
2730 for (wp = t1->words; *wp;)
2731 if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp))
2732 return(&t1->left);
2733 return((struct op **)NULL);
2734}
2735
2736static struct op *
2737findcase(t, w)
2738struct op *t;
2739char *w;
2740{
2741 register struct op **tp;
2742
2743 return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL);
2744}
2745
2746/*
2747 * Enter a new loop level (marked for break/continue).
2748 */
2749static void
2750brkset(bc)
2751struct brkcon *bc;
2752{
2753 bc->nextlev = brklist;
2754 brklist = bc;
2755}
2756
2757/*
2758 * Wait for the last process created.
2759 * Print a message for each process found
2760 * that was killed by a signal.
2761 * Ignore interrupt signals while waiting
2762 * unless `canintr' is true.
2763 */
2764static int
2765waitfor(lastpid, canintr)
2766register int lastpid;
2767int canintr;
2768{
2769 register int pid, rv;
2770 int s;
2771 int oheedint = heedint;
2772
2773 heedint = 0;
2774 rv = 0;
2775 do {
2776 pid = wait(&s);
2777 if (pid == -1) {
2778 if (errno != EINTR || canintr)
2779 break;
2780 } else {
2781 if ((rv = WAITSIG(s)) != 0) {
2782 if (rv < NSIGNAL) {
2783 if (signame[rv] != NULL) {
2784 if (pid != lastpid) {
2785 prn(pid);
2786 prs(": ");
2787 }
2788 prs(signame[rv]);
2789 }
2790 } else {
2791 if (pid != lastpid) {
2792 prn(pid);
2793 prs(": ");
2794 }
2795 prs("Signal "); prn(rv); prs(" ");
2796 }
2797 if (WAITCORE(s))
2798 prs(" - core dumped");
2799 if (rv >= NSIGNAL || signame[rv])
2800 prs("\n");
2801 rv = -1;
2802 } else
2803 rv = WAITVAL(s);
2804 }
2805 } while (pid != lastpid);
2806 heedint = oheedint;
2807 if (intr) {
2808 if (interactive) {
2809 if (canintr)
2810 intr = 0;
2811 } else {
2812 if (exstat == 0) exstat = rv;
2813 onintr(0);
2814 }
2815 }
2816 return(rv);
2817}
2818
2819static int
2820setstatus(s)
2821register int s;
2822{
2823 exstat = s;
2824 setval(lookup("?"), putn(s));
2825 return(s);
2826}
2827
2828/*
2829 * PATH-searching interface to execve.
2830 * If getenv("PATH") were kept up-to-date,
2831 * execvp might be used.
2832 */
2833static char *
2834rexecve(c, v, envp)
2835char *c, **v, **envp;
2836{
2837 register int i;
2838 register char *sp, *tp;
2839 int eacces = 0, asis = 0;
2840
2841#ifdef BB_FEATURE_SH_STANDALONE_SHELL
2842 char *name = c;
2843#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
2844 name = get_last_path_component(name);
2845#endif
2846 optind = 1;
2847 if (find_applet_by_name(name)) {
2848 /* We have to exec here since we vforked. Running
2849 * run_applet_by_name() won't work and bad things
2850 * will happen. */
2851 execve("/proc/self/exe", v, envp);
2852 execve("busybox", v, envp);
2853 }
2854#endif
2855
2856 sp = any('/', c)? "": path->value;
2857 asis = *sp == '\0';
2858 while (asis || *sp != '\0') {
2859 asis = 0;
2860 tp = e.linep;
2861 for (; *sp != '\0'; tp++)
2862 if ((*tp = *sp++) == ':') {
2863 asis = *sp == '\0';
2864 break;
2865 }
2866 if (tp != e.linep)
2867 *tp++ = '/';
2868 for (i = 0; (*tp++ = c[i++]) != '\0';)
2869 ;
2870
2871 execve(e.linep, v, envp);
2872 switch (errno) {
2873 case ENOEXEC:
2874 *v = e.linep;
2875 tp = *--v;
2876 *v = e.linep;
2877 execve("/bin/sh", v, envp);
2878 *v = tp;
2879 return("no Shell");
2880
2881 case ENOMEM:
2882 return("program too big");
2883
2884 case E2BIG:
2885 return("argument list too long");
2886
2887 case EACCES:
2888 eacces++;
2889 break;
2890 }
2891 }
2892 return(errno==ENOENT ? "not found" : "cannot execute");
2893}
2894
2895/*
2896 * Run the command produced by generator `f'
2897 * applied to stream `arg'.
2898 */
2899static int
2900run(argp, f)
2901struct ioarg *argp;
2902int (*f)();
2903{
2904 struct op *otree;
2905 struct wdblock *swdlist;
2906 struct wdblock *siolist;
2907 jmp_buf ev, rt;
2908 xint *ofail;
2909 int rv;
2910
2911#if __GNUC__
2912 /* Avoid longjmp clobbering */
2913 (void) &rv;
2914#endif
2915
2916 areanum++;
2917 swdlist = wdlist;
2918 siolist = iolist;
2919 otree = outtree;
2920 ofail = failpt;
2921 rv = -1;
2922 if (newenv(setjmp(errpt = ev)) == 0) {
2923 wdlist = 0;
2924 iolist = 0;
2925 pushio(argp, f);
2926 e.iobase = e.iop;
2927 yynerrs = 0;
2928 if (setjmp(failpt = rt) == 0 && yyparse() == 0)
2929 rv = execute(outtree, NOPIPE, NOPIPE, 0);
2930 quitenv();
2931 }
2932 wdlist = swdlist;
2933 iolist = siolist;
2934 failpt = ofail;
2935 outtree = otree;
2936 freearea(areanum--);
2937 return(rv);
2938}
2939
2940/* -------- do.c -------- */
2941
2942/*
2943 * built-in commands: doX
2944 */
2945
2946static int dohelp()
2947{
2948 int col;
2949 const struct builtincmd *x;
2950
2951 printf("\nBuilt-in commands:\n");
2952 printf("-------------------\n");
2953
2954 for (col=0, x = builtincmds; x->builtinfunc != NULL; x++) {
2955 if (!x->name)
2956 continue;
2957 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
2958 if (col > 60) {
2959 printf("\n");
2960 col = 0;
2961 }
2962 }
2963#ifdef BB_FEATURE_SH_STANDALONE_SHELL
2964 {
2965 int i;
2966 const struct BB_applet *applet;
2967 extern const struct BB_applet applets[];
2968 extern const size_t NUM_APPLETS;
2969
2970 for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) {
2971 if (!applet->name)
2972 continue;
2973
2974 col += printf("%s%s", ((col == 0) ? "\t" : " "),
2975 applet->name);
2976 if (col > 60) {
2977 printf("\n");
2978 col = 0;
2979 }
2980 }
2981 }
2982#endif
2983 printf("\n\n");
2984 return EXIT_SUCCESS;
2985}
2986
2987
2988
2989static int
2990dolabel()
2991{
2992 return(0);
2993}
2994
2995static int
2996dochdir(t)
2997register struct op *t;
2998{
2999 register char *cp, *er;
3000
3001 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
3002 er = ": no home directory";
3003 else if(chdir(cp) < 0)
3004 er = ": bad directory";
3005 else
3006 return(0);
3007 prs(cp != NULL? cp: "cd");
3008 err(er);
3009 return(1);
3010}
3011
3012static int
3013doshift(t)
3014register struct op *t;
3015{
3016 register int n;
3017
3018 n = t->words[1]? getn(t->words[1]): 1;
3019 if(dolc < n) {
3020 err("nothing to shift");
3021 return(1);
3022 }
3023 dolv[n] = dolv[0];
3024 dolv += n;
3025 dolc -= n;
3026 setval(lookup("#"), putn(dolc));
3027 return(0);
3028}
3029
3030/*
3031 * execute login and newgrp directly
3032 */
3033static int
3034dologin(t)
3035struct op *t;
3036{
3037 register char *cp;
3038
3039 if (interactive) {
3040 signal(SIGINT, SIG_DFL);
3041 signal(SIGQUIT, SIG_DFL);
3042 }
3043 cp = rexecve(t->words[0], t->words, makenv());
3044 prs(t->words[0]); prs(": "); err(cp);
3045 return(1);
3046}
3047
3048static int
3049doumask(t)
3050register struct op *t;
3051{
3052 register int i, n;
3053 register char *cp;
3054
3055 if ((cp = t->words[1]) == NULL) {
3056 i = umask(0);
3057 umask(i);
3058 for (n=3*4; (n-=3) >= 0;)
3059 putc('0'+((i>>n)&07), stderr);
3060 putc('\n', stderr);
3061 } else {
3062 for (n=0; *cp>='0' && *cp<='9'; cp++)
3063 n = n*8 + (*cp-'0');
3064 umask(n);
3065 }
3066 return(0);
3067}
3068
3069static int
3070doexec(t)
3071register struct op *t;
3072{
3073 register int i;
3074 jmp_buf ex;
3075 xint *ofail;
3076
3077 t->ioact = NULL;
3078 for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++)
3079 ;
3080 if (i == 0)
3081 return(1);
3082 execflg = 1;
3083 ofail = failpt;
3084 if (setjmp(failpt = ex) == 0)
3085 execute(t, NOPIPE, NOPIPE, FEXEC);
3086 failpt = ofail;
3087 execflg = 0;
3088 return(1);
3089}
3090
3091static int
3092dodot(t)
3093struct op *t;
3094{
3095 register int i;
3096 register char *sp, *tp;
3097 char *cp;
3098
3099 if ((cp = t->words[1]) == NULL)
3100 return(0);
3101 sp = any('/', cp)? ":": path->value;
3102 while (*sp) {
3103 tp = e.linep;
3104 while (*sp && (*tp = *sp++) != ':')
3105 tp++;
3106 if (tp != e.linep)
3107 *tp++ = '/';
3108 for (i = 0; (*tp++ = cp[i++]) != '\0';)
3109 ;
3110 if ((i = open(e.linep, 0)) >= 0) {
3111 exstat = 0;
3112 next(remap(i));
3113 return(exstat);
3114 }
3115 }
3116 prs(cp);
3117 err(": not found");
3118 return(-1);
3119}
3120
3121static int
3122dowait(t)
3123struct op *t;
3124{
3125 register int i;
3126 register char *cp;
3127
3128 if ((cp = t->words[1]) != NULL) {
3129 i = getn(cp);
3130 if (i == 0)
3131 return(0);
3132 } else
3133 i = -1;
3134 setstatus(waitfor(i, 1));
3135 return(0);
3136}
3137
3138static int
3139doread(t)
3140struct op *t;
3141{
3142 register char *cp, **wp;
3143 register int nb = 0;
3144 register int nl = 0;
3145
3146 if (t->words[1] == NULL) {
3147 err("Usage: read name ...");
3148 return(1);
3149 }
3150 for (wp = t->words+1; *wp; wp++) {
3151 for (cp = e.linep; !nl && cp < elinep-1; cp++)
3152 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
3153 (nl = (*cp == '\n')) ||
3154 (wp[1] && any(*cp, ifs->value)))
3155 break;
3156 *cp = 0;
3157 if (nb <= 0)
3158 break;
3159 setval(lookup(*wp), e.linep);
3160 }
3161 return(nb <= 0);
3162}
3163
3164static int
3165doeval(t)
3166register struct op *t;
3167{
3168 return(RUN(awordlist, t->words+1, wdchar));
3169}
3170
3171static int
3172dotrap(t)
3173register struct op *t;
3174{
3175 register int n, i;
3176 register int resetsig;
3177
3178 if (t->words[1] == NULL) {
3179 for (i=0; i<=_NSIG; i++)
3180 if (trap[i]) {
3181 prn(i);
3182 prs(": ");
3183 prs(trap[i]);
3184 prs("\n");
3185 }
3186 return(0);
3187 }
3188 resetsig = isdigit(*t->words[1]);
3189 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3190 n = getsig(t->words[i]);
3191 freecell(trap[n]);
3192 trap[n] = 0;
3193 if (!resetsig) {
3194 if (*t->words[1] != '\0') {
3195 trap[n] = strsave(t->words[1], 0);
3196 setsig(n, sig);
3197 } else
3198 setsig(n, SIG_IGN);
3199 } else {
3200 if (interactive)
3201 if (n == SIGINT)
3202 setsig(n, onintr);
3203 else
3204 setsig(n, n == SIGQUIT ? SIG_IGN
3205 : SIG_DFL);
3206 else
3207 setsig(n, SIG_DFL);
3208 }
3209 }
3210 return(0);
3211}
3212
3213static int
3214getsig(s)
3215char *s;
3216{
3217 register int n;
3218
3219 if ((n = getn(s)) < 0 || n > _NSIG) {
3220 err("trap: bad signal number");
3221 n = 0;
3222 }
3223 return(n);
3224}
3225
3226static void
3227setsig( register int n, void (*f)(int))
3228{
3229 if (n == 0)
3230 return;
3231 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3232 ourtrap[n] = 1;
3233 signal(n, f);
3234 }
3235}
3236
3237static int
3238getn(as)
3239char *as;
3240{
3241 register char *s;
3242 register int n, m;
3243
3244 s = as;
3245 m = 1;
3246 if (*s == '-') {
3247 m = -1;
3248 s++;
3249 }
3250 for (n = 0; isdigit(*s); s++)
3251 n = (n*10) + (*s-'0');
3252 if (*s) {
3253 prs(as);
3254 err(": bad number");
3255 }
3256 return(n*m);
3257}
3258
3259static int
3260dobreak(t)
3261struct op *t;
3262{
3263 return(brkcontin(t->words[1], 1));
3264}
3265
3266static int
3267docontinue(t)
3268struct op *t;
3269{
3270 return(brkcontin(t->words[1], 0));
3271}
3272
3273static int
3274brkcontin(cp, val)
3275register char *cp;
3276int val;
3277{
3278 register struct brkcon *bc;
3279 register int nl;
3280
3281 nl = cp == NULL? 1: getn(cp);
3282 if (nl <= 0)
3283 nl = 999;
3284 do {
3285 if ((bc = brklist) == NULL)
3286 break;
3287 brklist = bc->nextlev;
3288 } while (--nl);
3289 if (nl) {
3290 err("bad break/continue level");
3291 return(1);
3292 }
3293 isbreak = val;
3294 longjmp(bc->brkpt, 1);
3295 /* NOTREACHED */
3296}
3297
3298static int
3299doexit(t)
3300struct op *t;
3301{
3302 register char *cp;
3303
3304 execflg = 0;
3305 if ((cp = t->words[1]) != NULL)
3306 setstatus(getn(cp));
3307 leave();
3308 /* NOTREACHED */
3309 return(0);
3310}
3311
3312static int
3313doexport(t)
3314struct op *t;
3315{
3316 rdexp(t->words+1, export, EXPORT);
3317 return(0);
3318}
3319
3320static int
3321doreadonly(t)
3322struct op *t;
3323{
3324 rdexp(t->words+1, ronly, RONLY);
3325 return(0);
3326}
3327
3328static void
3329rdexp(wp, f, key)
3330register char **wp;
3331void (*f)();
3332int key;
3333{
3334 if (*wp != NULL) {
3335 for (; *wp != NULL; wp++) {
3336 if (isassign(*wp)) {
3337 char *cp;
3338 assign(*wp, COPYV);
3339 for (cp = *wp; *cp != '='; cp++)
3340 ;
3341 *cp = '\0';
3342 }
3343 if (checkname(*wp))
3344 (*f)(lookup(*wp));
3345 else
3346 badid(*wp);
3347 }
3348 } else
3349 putvlist(key, 1);
3350}
3351
3352static void
3353badid(s)
3354register char *s;
3355{
3356 prs(s);
3357 err(": bad identifier");
3358}
3359
3360static int
3361doset(t)
3362register struct op *t;
3363{
3364 register struct var *vp;
3365 register char *cp;
3366 register int n;
3367
3368 if ((cp = t->words[1]) == NULL) {
3369 for (vp = vlist; vp; vp = vp->next)
3370 varput(vp->name, 1);
3371 return(0);
3372 }
3373 if (*cp == '-') {
3374 /* bad: t->words++; */
3375 for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++)
3376 ;
3377 if (*++cp == 0)
3378 flag['x'] = flag['v'] = 0;
3379 else
3380 for (; *cp; cp++)
3381 switch (*cp) {
3382 case 'e':
3383 if (!interactive)
3384 flag['e']++;
3385 break;
3386
3387 default:
3388 if (*cp>='a' && *cp<='z')
3389 flag[(int)*cp]++;
3390 break;
3391 }
3392 setdash();
3393 }
3394 if (t->words[1]) {
3395 t->words[0] = dolv[0];
3396 for (n=1; t->words[n]; n++)
3397 setarea((char *)t->words[n], 0);
3398 dolc = n-1;
3399 dolv = t->words;
3400 setval(lookup("#"), putn(dolc));
3401 setarea((char *)(dolv-1), 0);
3402 }
3403 return(0);
3404}
3405
3406static void
3407varput(s, out)
3408register char *s;
3409int out;
3410{
3411 if (isalnum(*s) || *s == '_') {
3412 write(out, s, strlen(s));
3413 write(out, "\n", 1);
3414 }
3415}
3416
3417
3418/*
3419 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3420 * This file contains code for the times builtin.
3421 */
3422static int dotimes ()
3423{
3424 struct tms buf;
3425 long int clk_tck = sysconf(_SC_CLK_TCK);
3426
3427 times(&buf);
3428 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
3429 (int) (buf.tms_utime / clk_tck / 60),
3430 ((double) buf.tms_utime) / clk_tck,
3431 (int) (buf.tms_stime / clk_tck / 60),
3432 ((double) buf.tms_stime) / clk_tck,
3433 (int) (buf.tms_cutime / clk_tck / 60),
3434 ((double) buf.tms_cutime) / clk_tck,
3435 (int) (buf.tms_cstime / clk_tck / 60),
3436 ((double) buf.tms_cstime) / clk_tck);
3437 return 0;
3438}
3439
3440
3441static int (*inbuilt(char *s))()
3442{
3443 const struct builtincmd *bp;
3444
3445 for (bp = builtincmds; bp->name != NULL; bp++)
3446 if (strcmp(bp->name, s) == 0)
3447 return(bp->builtinfunc);
3448
3449 return((int(*)())NULL);
3450}
3451
3452/* -------- eval.c -------- */
3453
3454/*
3455 * ${}
3456 * `command`
3457 * blank interpretation
3458 * quoting
3459 * glob
3460 */
3461
3462static char ** eval( char **ap, int f)
3463{
3464 struct wdblock *wb;
3465 char **wp;
3466 char **wf;
3467 jmp_buf ev;
3468
3469#if __GNUC__
3470 /* Avoid longjmp clobbering */
3471 (void) &wp;
3472 (void) &ap;
3473#endif
3474 wp = NULL;
3475 wb = NULL;
3476 wf = NULL;
3477 if (newenv(setjmp(errpt = ev)) == 0) {
3478 while (*ap && isassign(*ap))
3479 expand(*ap++, &wb, f & ~DOGLOB);
3480 if (flag['k']) {
3481 for (wf = ap; *wf; wf++) {
3482 if (isassign(*wf))
3483 expand(*wf, &wb, f & ~DOGLOB);
3484 }
3485 }
3486 for (wb = addword((char *)0, wb); *ap; ap++) {
3487 if (!flag['k'] || !isassign(*ap))
3488 expand(*ap, &wb, f & ~DOKEY);
3489 }
3490 wb = addword((char *)0, wb);
3491 wp = getwords(wb);
3492 quitenv();
3493 } else
3494 gflg = 1;
3495 return(gflg? (char **)NULL: wp);
3496}
3497
3498/*
3499 * Make the exported environment from the exported
3500 * names in the dictionary. Keyword assignments
3501 * will already have been done.
3502 */
3503static char **
3504makenv()
3505
3506{
3507 register struct wdblock *wb;
3508 register struct var *vp;
3509
3510 wb = NULL;
3511 for (vp = vlist; vp; vp = vp->next)
3512 if (vp->status & EXPORT)
3513 wb = addword(vp->name, wb);
3514 wb = addword((char *)0, wb);
3515 return(getwords(wb));
3516}
3517
3518static char *
3519evalstr(cp, f)
3520register char *cp;
3521int f;
3522{
3523 struct wdblock *wb;
3524
3525 wb = NULL;
3526 if (expand(cp, &wb, f)) {
3527 if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL)
3528 cp = "";
3529 DELETE(wb);
3530 } else
3531 cp = NULL;
3532 return(cp);
3533}
3534
3535static int
3536expand( char *cp, register struct wdblock **wbp, int f)
3537{
3538 jmp_buf ev;
3539
3540#if __GNUC__
3541 /* Avoid longjmp clobbering */
3542 (void) &cp;
3543#endif
3544 gflg = 0;
3545 if (cp == NULL)
3546 return(0);
3547 if (!anys("$`'\"", cp) &&
3548 !anys(ifs->value, cp) &&
3549 ((f&DOGLOB)==0 || !anys("[*?", cp))) {
3550 cp = strsave(cp, areanum);
3551 if (f & DOTRIM)
3552 unquote(cp);
3553 *wbp = addword(cp, *wbp);
3554 return(1);
3555 }
3556 if (newenv(setjmp(errpt = ev)) == 0) {
3557 PUSHIO(aword, cp, strchar);
3558 e.iobase = e.iop;
3559 while ((cp = blank(f)) && gflg == 0) {
3560 e.linep = cp;
3561 cp = strsave(cp, areanum);
3562 if ((f&DOGLOB) == 0) {
3563 if (f & DOTRIM)
3564 unquote(cp);
3565 *wbp = addword(cp, *wbp);
3566 } else
3567 *wbp = glob(cp, *wbp);
3568 }
3569 quitenv();
3570 } else
3571 gflg = 1;
3572 return(gflg == 0);
3573}
3574
3575/*
3576 * Blank interpretation and quoting
3577 */
3578static char *
3579blank(f)
3580int f;
3581{
3582 register int c, c1;
3583 register char *sp;
3584 int scanequals, foundequals;
3585
3586 sp = e.linep;
3587 scanequals = f & DOKEY;
3588 foundequals = 0;
3589
3590loop:
3591 switch (c = subgetc('"', foundequals)) {
3592 case 0:
3593 if (sp == e.linep)
3594 return(0);
3595 *e.linep++ = 0;
3596 return(sp);
3597
3598 default:
3599 if (f & DOBLANK && any(c, ifs->value))
3600 goto loop;
3601 break;
3602
3603 case '"':
3604 case '\'':
3605 scanequals = 0;
3606 if (INSUB())
3607 break;
3608 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3609 if (c == 0)
3610 break;
3611 if (c == '\'' || !any(c, "$`\""))
3612 c |= QUOTE;
3613 *e.linep++ = c;
3614 }
3615 c = 0;
3616 }
3617 unget(c);
3618 if (!isalpha(c) && c != '_')
3619 scanequals = 0;
3620 for (;;) {
3621 c = subgetc('"', foundequals);
3622 if (c == 0 ||
3623 f & (DOBLANK && any(c, ifs->value)) ||
3624 (!INSUB() && any(c, "\"'"))) {
3625 scanequals = 0;
3626 unget(c);
3627 if (any(c, "\"'"))
3628 goto loop;
3629 break;
3630 }
3631 if (scanequals) {
3632 if (c == '=') {
3633 foundequals = 1;
3634 scanequals = 0;
3635 }
3636 else if (!isalnum(c) && c != '_')
3637 scanequals = 0;
3638 }
3639 *e.linep++ = c;
3640 }
3641 *e.linep++ = 0;
3642 return(sp);
3643}
3644
3645/*
3646 * Get characters, substituting for ` and $
3647 */
3648static int
3649subgetc(ec, quoted)
3650register int ec;
3651int quoted;
3652{
3653 register char c;
3654
3655again:
3656 c = my_getc(ec);
3657 if (!INSUB() && ec != '\'') {
3658 if (c == '`') {
3659 if (grave(quoted) == 0)
3660 return(0);
3661 e.iop->task = XGRAVE;
3662 goto again;
3663 }
3664 if (c == '$' && (c = dollar(quoted)) == 0) {
3665 e.iop->task = XDOLL;
3666 goto again;
3667 }
3668 }
3669 return(c);
3670}
3671
3672/*
3673 * Prepare to generate the string returned by ${} substitution.
3674 */
3675static int
3676dollar(quoted)
3677int quoted;
3678{
3679 int otask;
3680 struct io *oiop;
3681 char *dolp;
3682 register char *s, c, *cp=NULL;
3683 struct var *vp;
3684
3685 c = readc();
3686 s = e.linep;
3687 if (c != '{') {
3688 *e.linep++ = c;
3689 if (isalpha(c) || c == '_') {
3690 while ((c = readc())!=0 && (isalnum(c) || c == '_'))
3691 if (e.linep < elinep)
3692 *e.linep++ = c;
3693 unget(c);
3694 }
3695 c = 0;
3696 } else {
3697 oiop = e.iop;
3698 otask = e.iop->task;
3699 e.iop->task = XOTHER;
3700 while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n')
3701 if (e.linep < elinep)
3702 *e.linep++ = c;
3703 if (oiop == e.iop)
3704 e.iop->task = otask;
3705 if (c != '}') {
3706 err("unclosed ${");
3707 gflg++;
3708 return(c);
3709 }
3710 }
3711 if (e.linep >= elinep) {
3712 err("string in ${} too long");
3713 gflg++;
3714 e.linep -= 10;
3715 }
3716 *e.linep = 0;
3717 if (*s)
3718 for (cp = s+1; *cp; cp++)
3719 if (any(*cp, "=-+?")) {
3720 c = *cp;
3721 *cp++ = 0;
3722 break;
3723 }
3724 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3725 if (dolc > 1) {
3726 /* currently this does not distinguish $* and $@ */
3727 /* should check dollar */
3728 e.linep = s;
3729 PUSHIO(awordlist, dolv+1, dolchar);
3730 return(0);
3731 } else { /* trap the nasty ${=} */
3732 s[0] = '1';
3733 s[1] = 0;
3734 }
3735 }
3736 vp = lookup(s);
3737 if ((dolp = vp->value) == null) {
3738 switch (c) {
3739 case '=':
3740 if (isdigit(*s)) {
3741 err("cannot use ${...=...} with $n");
3742 gflg++;
3743 break;
3744 }
3745 setval(vp, cp);
3746 dolp = vp->value;
3747 break;
3748
3749 case '-':
3750 dolp = strsave(cp, areanum);
3751 break;
3752
3753 case '?':
3754 if (*cp == 0) {
3755 prs("missing value for ");
3756 err(s);
3757 } else
3758 err(cp);
3759 gflg++;
3760 break;
3761 }
3762 } else if (c == '+')
3763 dolp = strsave(cp, areanum);
3764 if (flag['u'] && dolp == null) {
3765 prs("unset variable: ");
3766 err(s);
3767 gflg++;
3768 }
3769 e.linep = s;
3770 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
3771 return(0);
3772}
3773
3774/*
3775 * Run the command in `...` and read its output.
3776 */
3777static int
3778grave(quoted)
3779int quoted;
3780{
3781 register int i;
3782 char *cp;
3783 int pf[2];
3784
3785#if __GNUC__
3786 /* Avoid longjmp clobbering */
3787 (void) &cp;
3788#endif
3789 for (cp = e.iop->argp->aword; *cp != '`'; cp++)
3790 if (*cp == 0) {
3791 err("no closing `");
3792 return(0);
3793 }
3794 if (openpipe(pf) < 0)
3795 return(0);
3796 if ((i = vfork()) == -1) {
3797 closepipe(pf);
3798 err("try again");
3799 return(0);
3800 }
3801 if (i != 0) {
3802 e.iop->argp->aword = ++cp;
3803 close(pf[1]);
3804 PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar);
3805 return(1);
3806 }
3807 *cp = 0;
3808 /* allow trapped signals */
3809 for (i=0; i<=_NSIG; i++)
3810 if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN)
3811 signal(i, SIG_DFL);
3812 dup2(pf[1], 1);
3813 closepipe(pf);
3814 flag['e'] = 0;
3815 flag['v'] = 0;
3816 flag['n'] = 0;
3817 cp = strsave(e.iop->argp->aword, 0);
3818 areanum = 1;
3819 freehere(areanum);
3820 freearea(areanum); /* free old space */
3821 e.oenv = NULL;
3822 e.iop = (e.iobase = iostack) - 1;
3823 unquote(cp);
3824 interactive = 0;
3825 PUSHIO(aword, cp, nlchar);
3826 onecommand();
3827 exit(1);
3828}
3829
3830static char *
3831unquote(as)
3832register char *as;
3833{
3834 register char *s;
3835
3836 if ((s = as) != NULL)
3837 while (*s)
3838 *s++ &= ~QUOTE;
3839 return(as);
3840}
3841
3842/* -------- glob.c -------- */
3843
3844/*
3845 * glob
3846 */
3847
3848#define scopy(x) strsave((x), areanum)
3849#define BLKSIZ 512
3850#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
3851
3852static struct wdblock *cl, *nl;
3853static char spcl[] = "[?*";
3854
3855static struct wdblock *
3856glob(cp, wb)
3857char *cp;
3858struct wdblock *wb;
3859{
3860 register int i;
3861 register char *pp;
3862
3863 if (cp == 0)
3864 return(wb);
3865 i = 0;
3866 for (pp = cp; *pp; pp++)
3867 if (any(*pp, spcl))
3868 i++;
3869 else if (!any(*pp & ~QUOTE, spcl))
3870 *pp &= ~QUOTE;
3871 if (i != 0) {
3872 for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) {
3873 nl = newword(cl->w_nword*2);
3874 for(i=0; i<cl->w_nword; i++) { /* for each argument */
3875 for (pp = cl->w_words[i]; *pp; pp++)
3876 if (any(*pp, spcl)) {
3877 globname(cl->w_words[i], pp);
3878 break;
3879 }
3880 if (*pp == '\0')
3881 nl = addword(scopy(cl->w_words[i]), nl);
3882 }
3883 for(i=0; i<cl->w_nword; i++)
3884 DELETE(cl->w_words[i]);
3885 DELETE(cl);
3886 }
3887 for(i=0; i<cl->w_nword; i++)
3888 unquote(cl->w_words[i]);
3889 glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
3890 if (cl->w_nword) {
3891 for (i=0; i<cl->w_nword; i++)
3892 wb = addword(cl->w_words[i], wb);
3893 DELETE(cl);
3894 return(wb);
3895 }
3896 }
3897 wb = addword(unquote(cp), wb);
3898 return(wb);
3899}
3900
3901static void
3902globname(we, pp)
3903char *we;
3904register char *pp;
3905{
3906 register char *np, *cp;
3907 char *name, *gp, *dp;
3908 int k;
3909 DIR *dirp;
3910 struct dirent *de;
3911 char dname[NAME_MAX+1];
3912 struct stat dbuf;
3913
3914 for (np = we; np != pp; pp--)
3915 if (pp[-1] == '/')
3916 break;
3917 for (dp = cp = space((int)(pp-np)+3); np < pp;)
3918 *cp++ = *np++;
3919 *cp++ = '.';
3920 *cp = '\0';
3921 for (gp = cp = space(strlen(pp)+1); *np && *np != '/';)
3922 *cp++ = *np++;
3923 *cp = '\0';
3924 dirp = opendir(dp);
3925 if (dirp == 0) {
3926 DELETE(dp);
3927 DELETE(gp);
3928 return;
3929 }
3930 dname[NAME_MAX] = '\0';
3931 while ((de=readdir(dirp))!=NULL) {
3932 /* XXX Hmmm... What this could be? (abial) */
3933 /*
3934 if (ent[j].d_ino == 0)
3935 continue;
3936 */
3937 strncpy(dname, de->d_name, NAME_MAX);
3938 if (dname[0] == '.')
3939 if (*gp != '.')
3940 continue;
3941 for(k=0; k<NAME_MAX; k++)
3942 if (any(dname[k], spcl))
3943 dname[k] |= QUOTE;
3944 if (gmatch(dname, gp)) {
3945 name = generate(we, pp, dname, np);
3946 if (*np && !anys(np, spcl)) {
3947 if (stat(name,&dbuf)) {
3948 DELETE(name);
3949 continue;
3950 }
3951 }
3952 nl = addword(name, nl);
3953 }
3954 }
3955 closedir(dirp);
3956 DELETE(dp);
3957 DELETE(gp);
3958}
3959
3960/*
3961 * generate a pathname as below.
3962 * start..end1 / middle end
3963 * the slashes come for free
3964 */
3965static char *
3966generate(start1, end1, middle, end)
3967char *start1;
3968register char *end1;
3969char *middle, *end;
3970{
3971 char *p;
3972 register char *op, *xp;
3973
3974 p = op = space((int)(end1-start1)+strlen(middle)+strlen(end)+2);
3975 for (xp = start1; xp != end1;)
3976 *op++ = *xp++;
3977 for (xp = middle; (*op++ = *xp++) != '\0';)
3978 ;
3979 op--;
3980 for (xp = end; (*op++ = *xp++) != '\0';)
3981 ;
3982 return(p);
3983}
3984
3985static int
3986anyspcl(wb)
3987register struct wdblock *wb;
3988{
3989 register int i;
3990 register char **wd;
3991
3992 wd = wb->w_words;
3993 for (i=0; i<wb->w_nword; i++)
3994 if (anys(spcl, *wd++))
3995 return(1);
3996 return(0);
3997}
3998
3999static int
4000xstrcmp(p1, p2)
4001char *p1, *p2;
4002{
4003 return(strcmp(*(char **)p1, *(char **)p2));
4004}
4005
4006/* -------- word.c -------- */
4007
4008static struct wdblock *
4009newword(nw)
4010register int nw;
4011{
4012 register struct wdblock *wb;
4013
4014 wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *));
4015 wb->w_bsize = nw;
4016 wb->w_nword = 0;
4017 return(wb);
4018}
4019
4020static struct wdblock *
4021addword(wd, wb)
4022char *wd;
4023register struct wdblock *wb;
4024{
4025 register struct wdblock *wb2;
4026 register int nw;
4027
4028 if (wb == NULL)
4029 wb = newword(NSTART);
4030 if ((nw = wb->w_nword) >= wb->w_bsize) {
4031 wb2 = newword(nw * 2);
4032 memcpy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
4033 wb2->w_nword = nw;
4034 DELETE(wb);
4035 wb = wb2;
4036 }
4037 wb->w_words[wb->w_nword++] = wd;
4038 return(wb);
4039}
4040static
4041char **
4042getwords(wb)
4043register struct wdblock *wb;
4044{
4045 register char **wd;
4046 register int nb;
4047
4048 if (wb == NULL)
4049 return((char **)NULL);
4050 if (wb->w_nword == 0) {
4051 DELETE(wb);
4052 return((char **)NULL);
4053 }
4054 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
4055 memcpy((char *)wd, (char *)wb->w_words, nb);
4056 DELETE(wb); /* perhaps should done by caller */
4057 return(wd);
4058}
4059
4060int (*func)(char *, char *);
4061int globv;
4062
4063static void
4064glob0(a0, a1, a2, a3)
4065char *a0;
4066unsigned a1;
4067int a2;
4068int (*a3) (char *, char *);
4069{
4070 func = a3;
4071 globv = a2;
4072 glob1(a0, a0 + a1 * a2);
4073}
4074
4075static void
4076glob1(base, lim)
4077char *base, *lim;
4078{
4079 register char *i, *j;
4080 int v2;
4081 char *lptr, *hptr;
4082 int c;
4083 unsigned n;
4084
4085
4086 v2 = globv;
4087
4088top:
4089 if ((n=(int)(lim-base)) <= v2)
4090 return;
4091 n = v2 * (n / (2*v2));
4092 hptr = lptr = base+n;
4093 i = base;
4094 j = lim-v2;
4095 for(;;) {
4096 if (i < lptr) {
4097 if ((c = (*func)(i, lptr)) == 0) {
4098 glob2(i, lptr -= v2);
4099 continue;
4100 }
4101 if (c < 0) {
4102 i += v2;
4103 continue;
4104 }
4105 }
4106
4107begin:
4108 if (j > hptr) {
4109 if ((c = (*func)(hptr, j)) == 0) {
4110 glob2(hptr += v2, j);
4111 goto begin;
4112 }
4113 if (c > 0) {
4114 if (i == lptr) {
4115 glob3(i, hptr += v2, j);
4116 i = lptr += v2;
4117 goto begin;
4118 }
4119 glob2(i, j);
4120 j -= v2;
4121 i += v2;
4122 continue;
4123 }
4124 j -= v2;
4125 goto begin;
4126 }
4127
4128
4129 if (i == lptr) {
4130 if (lptr-base >= lim-hptr) {
4131 glob1(hptr+v2, lim);
4132 lim = lptr;
4133 } else {
4134 glob1(base, lptr);
4135 base = hptr+v2;
4136 }
4137 goto top;
4138 }
4139
4140
4141 glob3(j, lptr -= v2, i);
4142 j = hptr -= v2;
4143 }
4144}
4145
4146static void
4147glob2(i, j)
4148char *i, *j;
4149{
4150 register char *index1, *index2, c;
4151 int m;
4152
4153 m = globv;
4154 index1 = i;
4155 index2 = j;
4156 do {
4157 c = *index1;
4158 *index1++ = *index2;
4159 *index2++ = c;
4160 } while(--m);
4161}
4162
4163static void
4164glob3(i, j, k)
4165char *i, *j, *k;
4166{
4167 register char *index1, *index2, *index3;
4168 int c;
4169 int m;
4170
4171 m = globv;
4172 index1 = i;
4173 index2 = j;
4174 index3 = k;
4175 do {
4176 c = *index1;
4177 *index1++ = *index3;
4178 *index3++ = *index2;
4179 *index2++ = c;
4180 } while(--m);
4181}
4182
4183/* -------- io.c -------- */
4184
4185/*
4186 * shell IO
4187 */
4188
4189static int my_getc( int ec)
4190{
4191 register int c;
4192
4193 if(e.linep > elinep) {
4194 while((c=readc()) != '\n' && c)
4195 ;
4196 err("input line too long");
4197 gflg++;
4198 return(c);
4199 }
4200 c = readc();
4201 if (ec != '\'' && e.iop->task != XGRAVE) {
4202 if(c == '\\') {
4203 c = readc();
4204 if (c == '\n' && ec != '\"')
4205 return(my_getc(ec));
4206 c |= QUOTE;
4207 }
4208 }
4209 return(c);
4210}
4211
4212static void
4213unget(c)
4214int c;
4215{
4216 if (e.iop >= e.iobase)
4217 e.iop->peekc = c;
4218}
4219
4220static int
4221eofc()
4222
4223{
4224 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
4225}
4226
4227static int
4228readc()
4229{
4230 register int c;
4231
4232 for (; e.iop >= e.iobase; e.iop--)
4233 if ((c = e.iop->peekc) != '\0') {
4234 e.iop->peekc = 0;
4235 return(c);
4236 }
4237 else {
4238 if (e.iop->prev != 0) {
4239 if ((c = (*e.iop->iofn)(e.iop->argp, e.iop)) != '\0') {
4240 if (c == -1) {
4241 e.iop++;
4242 continue;
4243 }
4244 if (e.iop == iostack)
4245 ioecho(c);
4246 return(e.iop->prev = c);
4247 }
4248 else if (e.iop->task == XIO && e.iop->prev != '\n') {
4249 e.iop->prev = 0;
4250 if (e.iop == iostack)
4251 ioecho('\n');
4252 return '\n';
4253 }
4254 }
4255 if (e.iop->task == XIO) {
4256 if (multiline)
4257 return e.iop->prev = 0;
4258 if (interactive && e.iop == iostack+1) {
4259#ifdef BB_FEATURE_COMMAND_EDITING
4260 current_prompt=prompt->value;
4261#else
4262 prs(prompt->value);
4263#endif
4264 }
4265 }
4266 }
4267 if (e.iop >= iostack)
4268 return(0);
4269 leave();
4270 /* NOTREACHED */
4271 return(0);
4272}
4273
4274static void
4275ioecho(c)
4276char c;
4277{
4278 if (flag['v'])
4279 write(2, &c, sizeof c);
4280}
4281
4282static void
4283pushio(argp, fn)
4284struct ioarg *argp;
4285int (*fn)();
4286{
4287 if (++e.iop >= &iostack[NPUSH]) {
4288 e.iop--;
4289 err("Shell input nested too deeply");
4290 gflg++;
4291 return;
4292 }
4293 e.iop->iofn = fn;
4294
4295 if (argp->afid != AFID_NOBUF)
4296 e.iop->argp = argp;
4297 else {
4298 e.iop->argp = ioargstack + (e.iop - iostack);
4299 *e.iop->argp = *argp;
4300 e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf;
4301 if (isatty(e.iop->argp->afile) == 0 &&
4302 (e.iop == &iostack[0] ||
4303 lseek(e.iop->argp->afile, 0L, 1) != -1)) {
4304 if (++bufid == AFID_NOBUF)
4305 bufid = AFID_ID;
4306 e.iop->argp->afid = bufid;
4307 }
4308 }
4309
4310 e.iop->prev = ~'\n';
4311 e.iop->peekc = 0;
4312 e.iop->xchar = 0;
4313 e.iop->nlcount = 0;
4314 if (fn == filechar || fn == linechar)
4315 e.iop->task = XIO;
4316 else if (fn == gravechar || fn == qgravechar)
4317 e.iop->task = XGRAVE;
4318 else
4319 e.iop->task = XOTHER;
4320}
4321
4322static struct io *
4323setbase(ip)
4324struct io *ip;
4325{
4326 register struct io *xp;
4327
4328 xp = e.iobase;
4329 e.iobase = ip;
4330 return(xp);
4331}
4332
4333/*
4334 * Input generating functions
4335 */
4336
4337/*
4338 * Produce the characters of a string, then a newline, then EOF.
4339 */
4340static int
4341nlchar(ap)
4342register struct ioarg *ap;
4343{
4344 register int c;
4345
4346 if (ap->aword == NULL)
4347 return(0);
4348 if ((c = *ap->aword++) == 0) {
4349 ap->aword = NULL;
4350 return('\n');
4351 }
4352 return(c);
4353}
4354
4355/*
4356 * Given a list of words, produce the characters
4357 * in them, with a space after each word.
4358 */
4359static int
4360wdchar(ap)
4361register struct ioarg *ap;
4362{
4363 register char c;
4364 register char **wl;
4365
4366 if ((wl = ap->awordlist) == NULL)
4367 return(0);
4368 if (*wl != NULL) {
4369 if ((c = *(*wl)++) != 0)
4370 return(c & 0177);
4371 ap->awordlist++;
4372 return(' ');
4373 }
4374 ap->awordlist = NULL;
4375 return('\n');
4376}
4377
4378/*
4379 * Return the characters of a list of words,
4380 * producing a space between them.
4381 */
4382static int
4383dolchar(ap)
4384register struct ioarg *ap;
4385{
4386 register char *wp;
4387
4388 if ((wp = *ap->awordlist++) != NULL) {
4389 PUSHIO(aword, wp, *ap->awordlist == NULL? strchar: xxchar);
4390 return(-1);
4391 }
4392 return(0);
4393}
4394
4395static int
4396xxchar(ap)
4397register struct ioarg *ap;
4398{
4399 register int c;
4400
4401 if (ap->aword == NULL)
4402 return(0);
4403 if ((c = *ap->aword++) == '\0') {
4404 ap->aword = NULL;
4405 return(' ');
4406 }
4407 return(c);
4408}
4409
4410/*
4411 * Produce the characters from a single word (string).
4412 */
4413static int
4414strchar(ap)
4415register struct ioarg *ap;
4416{
4417 register int c;
4418
4419 if (ap->aword == NULL || (c = *ap->aword++) == 0)
4420 return(0);
4421 return(c);
4422}
4423
4424/*
4425 * Produce quoted characters from a single word (string).
4426 */
4427static int
4428qstrchar(ap)
4429register struct ioarg *ap;
4430{
4431 register int c;
4432
4433 if (ap->aword == NULL || (c = *ap->aword++) == 0)
4434 return(0);
4435 return(c|QUOTE);
4436}
4437
4438/*
4439 * Return the characters from a file.
4440 */
4441static int
4442filechar(ap)
4443register struct ioarg *ap;
4444{
4445 register int i;
4446 char c;
4447 struct iobuf *bp = ap->afbuf;
4448
4449 if (ap->afid != AFID_NOBUF) {
4450 if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
4451 if (i)
4452 lseek(ap->afile, ap->afpos, 0);
4453 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4454 if (i <= 0) {
4455 closef(ap->afile);
4456 return 0;
4457 }
4458 bp->id = ap->afid;
4459 bp->ebufp = (bp->bufp = bp->buf) + i;
4460 }
4461 ap->afpos++;
4462 return *bp->bufp++ & 0177;
4463 }
4464
4465#ifdef BB_FEATURE_COMMAND_EDITING
4466 if (interactive) {
4467 static char mycommand[BUFSIZ];
4468 static int position = 0, size = 0;
4469
4470 while (size == 0 || position >= size) {
4471 cmdedit_read_input(current_prompt, mycommand);
4472 size = strlen(mycommand);
4473 position = 0;
4474 }
4475 c = mycommand[position];
4476 position++;
4477 return(c);
4478 } else
4479#endif
4480 {
4481 i = safe_read(ap->afile, &c, sizeof(c));
4482 return(i == sizeof(c)? c&0177: (closef(ap->afile), 0));
4483 }
4484}
4485
4486/*
4487 * Return the characters from a here temp file.
4488 */
4489static int
4490herechar(ap)
4491register struct ioarg *ap;
4492{
4493 char c;
4494
4495
4496 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4497 close(ap->afile);
4498 c = 0;
4499 }
4500 return (c);
4501
4502}
4503
4504/*
4505 * Return the characters produced by a process (`...`).
4506 * Quote them if required, and remove any trailing newline characters.
4507 */
4508static int
4509gravechar(ap, iop)
4510struct ioarg *ap;
4511struct io *iop;
4512{
4513 register int c;
4514
4515 if ((c = qgravechar(ap, iop)&~QUOTE) == '\n')
4516 c = ' ';
4517 return(c);
4518}
4519
4520static int
4521qgravechar(ap, iop)
4522register struct ioarg *ap;
4523struct io *iop;
4524{
4525 register int c;
4526
4527 if (iop->xchar) {
4528 if (iop->nlcount) {
4529 iop->nlcount--;
4530 return('\n'|QUOTE);
4531 }
4532 c = iop->xchar;
4533 iop->xchar = 0;
4534 } else if ((c = filechar(ap)) == '\n') {
4535 iop->nlcount = 1;
4536 while ((c = filechar(ap)) == '\n')
4537 iop->nlcount++;
4538 iop->xchar = c;
4539 if (c == 0)
4540 return(c);
4541 iop->nlcount--;
4542 c = '\n';
4543 }
4544 return(c!=0? c|QUOTE: 0);
4545}
4546
4547/*
4548 * Return a single command (usually the first line) from a file.
4549 */
4550static int
4551linechar(ap)
4552register struct ioarg *ap;
4553{
4554 register int c;
4555
4556 if ((c = filechar(ap)) == '\n') {
4557 if (!multiline) {
4558 closef(ap->afile);
4559 ap->afile = -1; /* illegal value */
4560 }
4561 }
4562 return(c);
4563}
4564
4565static void
4566prs(s)
4567register char *s;
4568{
4569 if (*s)
4570 write(2, s, strlen(s));
4571}
4572
4573static void
4574prn(u)
4575unsigned u;
4576{
4577 prs(itoa(u, 0));
4578}
4579
4580static void
4581closef(i)
4582register int i;
4583{
4584 if (i > 2)
4585 close(i);
4586}
4587
4588static void
4589closeall()
4590{
4591 register int u;
4592
4593 for (u=NUFILE; u<NOFILE;)
4594 close(u++);
4595}
4596
4597/*
4598 * remap fd into Shell's fd space
4599 */
4600static int
4601remap(fd)
4602register int fd;
4603{
4604 register int i;
4605 int map[NOFILE];
4606
4607 if (fd < e.iofd) {
4608 for (i=0; i<NOFILE; i++)
4609 map[i] = 0;
4610 do {
4611 map[fd] = 1;
4612 fd = dup(fd);
4613 } while (fd >= 0 && fd < e.iofd);
4614 for (i=0; i<NOFILE; i++)
4615 if (map[i])
4616 close(i);
4617 if (fd < 0)
4618 err("too many files open in shell");
4619 }
4620 return(fd);
4621}
4622
4623static int
4624openpipe(pv)
4625register int *pv;
4626{
4627 register int i;
4628
4629 if ((i = pipe(pv)) < 0)
4630 err("can't create pipe - try again");
4631 return(i);
4632}
4633
4634static void
4635closepipe(pv)
4636register int *pv;
4637{
4638 if (pv != NULL) {
4639 close(*pv++);
4640 close(*pv);
4641 }
4642}
4643
4644/* -------- here.c -------- */
4645
4646/*
4647 * here documents
4648 */
4649
4650static void
4651markhere(s, iop)
4652register char *s;
4653struct ioword *iop;
4654{
4655 register struct here *h, *lh;
4656
4657 h = (struct here *) space(sizeof(struct here));
4658 if (h == 0)
4659 return;
4660 h->h_tag = evalstr(s, DOSUB);
4661 if (h->h_tag == 0)
4662 return;
4663 h->h_iop = iop;
4664 iop->io_name = 0;
4665 h->h_next = NULL;
4666 if (inhere == 0)
4667 inhere = h;
4668 else
4669 for (lh = inhere; lh!=NULL; lh = lh->h_next)
4670 if (lh->h_next == 0) {
4671 lh->h_next = h;
4672 break;
4673 }
4674 iop->io_flag |= IOHERE|IOXHERE;
4675 for (s = h->h_tag; *s; s++)
4676 if (*s & QUOTE) {
4677 iop->io_flag &= ~ IOXHERE;
4678 *s &= ~ QUOTE;
4679 }
4680 h->h_dosub = iop->io_flag & IOXHERE;
4681}
4682
4683static void
4684gethere()
4685{
4686 register struct here *h, *hp;
4687
4688 /* Scan here files first leaving inhere list in place */
4689 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
4690 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub? 0: '\'');
4691
4692 /* Make inhere list active - keep list intact for scraphere */
4693 if (hp != NULL) {
4694 hp->h_next = acthere;
4695 acthere = inhere;
4696 inhere = NULL;
4697 }
4698}
4699
4700static void
4701readhere(name, s, ec)
4702char **name;
4703register char *s;
4704int ec;
4705{
4706 int tf;
4707 char tname[30] = ".msh_XXXXXX";
4708 register int c;
4709 jmp_buf ev;
4710 char myline [LINELIM+1];
4711 char *thenext;
4712
4713 tf = mkstemp(tname);
4714 if (tf < 0)
4715 return;
4716 *name = strsave(tname, areanum);
4717 if (newenv(setjmp(errpt = ev)) != 0)
4718 unlink(tname);
4719 else {
4720 pushio(e.iop->argp, e.iop->iofn);
4721 e.iobase = e.iop;
4722 for (;;) {
4723 if (interactive && e.iop <= iostack) {
4724#ifdef BB_FEATURE_COMMAND_EDITING
4725 current_prompt=cprompt->value;
4726#else
4727 prs(cprompt->value);
4728#endif
4729 }
4730 thenext = myline;
4731 while ((c = my_getc(ec)) != '\n' && c) {
4732 if (ec == '\'')
4733 c &= ~ QUOTE;
4734 if (thenext >= &myline[LINELIM]) {
4735 c = 0;
4736 break;
4737 }
4738 *thenext++ = c;
4739 }
4740 *thenext = 0;
4741 if (strcmp(s, myline) == 0 || c == 0)
4742 break;
4743 *thenext++ = '\n';
4744 write (tf, myline, (int)(thenext-myline));
4745 }
4746 if (c == 0) {
4747 prs("here document `"); prs(s); err("' unclosed");
4748 }
4749 quitenv();
4750 }
4751 close(tf);
4752}
4753
4754/*
4755 * open here temp file.
4756 * if unquoted here, expand here temp file into second temp file.
4757 */
4758static int
4759herein(hname, xdoll)
4760char *hname;
4761int xdoll;
4762{
4763 register int hf;
4764 int tf;
4765
4766#if __GNUC__
4767 /* Avoid longjmp clobbering */
4768 (void) &tf;
4769#endif
4770 if (hname == 0)
4771 return(-1);
4772 hf = open(hname, 0);
4773 if (hf < 0)
4774 return (-1);
4775 if (xdoll) {
4776 char c;
4777 char tname[30] = ".msh_XXXXXX";
4778 jmp_buf ev;
4779
4780 tf = mkstemp(tname);
4781 if (tf < 0)
4782 return (-1);
4783 if (newenv(setjmp(errpt = ev)) == 0) {
4784 PUSHIO(afile, hf, herechar);
4785 setbase(e.iop);
4786 while ((c = subgetc(0, 0)) != 0) {
4787 c &= ~ QUOTE;
4788 write(tf, &c, sizeof c);
4789 }
4790 quitenv();
4791 } else
4792 unlink(tname);
4793 close(tf);
4794 tf = open(tname, 0);
4795 unlink(tname);
4796 return (tf);
4797 } else
4798 return (hf);
4799}
4800
4801static void
4802scraphere()
4803{
4804 register struct here *h;
4805
4806 for (h = inhere; h != NULL; h = h->h_next) {
4807 if (h->h_iop && h->h_iop->io_name)
4808 unlink(h->h_iop->io_name);
4809 }
4810 inhere = NULL;
4811}
4812
4813/* unlink here temp files before a freearea(area) */
4814static void
4815freehere(area)
4816int area;
4817{
4818 register struct here *h, *hl;
4819
4820 hl = NULL;
4821 for (h = acthere; h != NULL; h = h->h_next)
4822 if (getarea((char *) h) >= area) {
4823 if (h->h_iop->io_name != NULL)
4824 unlink(h->h_iop->io_name);
4825 if (hl == NULL)
4826 acthere = h->h_next;
4827 else
4828 hl->h_next = h->h_next;
4829 } else
4830 hl = h;
4831}
4832
4833
4834
4835/*
4836 * Copyright (c) 1987,1997, Prentice Hall
4837 * All rights reserved.
4838 *
4839 * Redistribution and use of the MINIX operating system in source and
4840 * binary forms, with or without modification, are permitted provided
4841 * that the following conditions are met:
4842 *
4843 * Redistributions of source code must retain the above copyright
4844 * notice, this list of conditions and the following disclaimer.
4845 *
4846 * Redistributions in binary form must reproduce the above
4847 * copyright notice, this list of conditions and the following
4848 * disclaimer in the documentation and/or other materials provided
4849 * with the distribution.
4850 *
4851 * Neither the name of Prentice Hall nor the names of the software
4852 * authors or contributors may be used to endorse or promote
4853 * products derived from this software without specific prior
4854 * written permission.
4855 *
4856 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
4857 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
4858 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
4859 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4860 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
4861 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4862 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
4863 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
4864 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4865 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
4866 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
4867 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4868 *
4869 */
4870
diff --git a/mt.c b/mt.c
deleted file mode 100644
index 49dc70ac6..000000000
--- a/mt.c
+++ /dev/null
@@ -1,121 +0,0 @@
1/* vi: set sw=4 ts=4: */
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <sys/mtio.h>
6#include <sys/fcntl.h>
7#include "busybox.h"
8
9struct mt_opcodes {
10 char *name;
11 short value;
12};
13
14/* missing: eod/seod, stoptions, stwrthreshold, densities */
15static const struct mt_opcodes opcodes[] = {
16 {"bsf", MTBSF},
17 {"bsfm", MTBSFM},
18 {"bsr", MTBSR},
19 {"bss", MTBSS},
20 {"datacompression", MTCOMPRESSION},
21 {"eom", MTEOM},
22 {"erase", MTERASE},
23 {"fsf", MTFSF},
24 {"fsfm", MTFSFM},
25 {"fsr", MTFSR},
26 {"fss", MTFSS},
27 {"load", MTLOAD},
28 {"lock", MTLOCK},
29 {"mkpart", MTMKPART},
30 {"nop", MTNOP},
31 {"offline", MTOFFL},
32 {"rewoffline", MTOFFL},
33 {"ras1", MTRAS1},
34 {"ras2", MTRAS2},
35 {"ras3", MTRAS3},
36 {"reset", MTRESET},
37 {"retension", MTRETEN},
38 {"rewind", MTREW},
39 {"seek", MTSEEK},
40 {"setblk", MTSETBLK},
41 {"setdensity", MTSETDENSITY},
42 {"drvbuffer", MTSETDRVBUFFER},
43 {"setpart", MTSETPART},
44 {"tell", MTTELL},
45 {"wset", MTWSM},
46 {"unload", MTUNLOAD},
47 {"unlock", MTUNLOCK},
48 {"eof", MTWEOF},
49 {"weof", MTWEOF},
50 {0, 0}
51};
52
53extern int mt_main(int argc, char **argv)
54{
55 const char *file = "/dev/tape";
56 const struct mt_opcodes *code = opcodes;
57 struct mtop op;
58 struct mtpos position;
59 int fd, mode;
60
61 if (argc < 2) {
62 show_usage();
63 }
64
65 if (strcmp(argv[1], "-f") == 0) {
66 if (argc < 4) {
67 show_usage();
68 }
69 file = argv[2];
70 argv += 2;
71 argc -= 2;
72 }
73
74 while (code->name != 0) {
75 if (strcmp(code->name, argv[1]) == 0)
76 break;
77 code++;
78 }
79
80 if (code->name == 0) {
81 error_msg("unrecognized opcode %s.", argv[1]);
82 return EXIT_FAILURE;
83 }
84
85 op.mt_op = code->value;
86 if (argc >= 3)
87 op.mt_count = atoi(argv[2]);
88 else
89 op.mt_count = 1; /* One, not zero, right? */
90
91 switch (code->value) {
92 case MTWEOF:
93 case MTERASE:
94 case MTWSM:
95 case MTSETDRVBUFFER:
96 mode = O_WRONLY;
97 break;
98
99 default:
100 mode = O_RDONLY;
101 break;
102 }
103
104 if ((fd = open(file, mode, 0)) < 0)
105 perror_msg_and_die("%s", file);
106
107 switch (code->value) {
108 case MTTELL:
109 if (ioctl(fd, MTIOCPOS, &position) < 0)
110 perror_msg_and_die("%s", file);
111 printf ("At block %d.\n", (int) position.mt_blkno);
112 break;
113
114 default:
115 if (ioctl(fd, MTIOCTOP, &op) != 0)
116 perror_msg_and_die("%s", file);
117 break;
118 }
119
120 return EXIT_SUCCESS;
121}
diff --git a/mv.c b/mv.c
deleted file mode 100644
index 1c4a34788..000000000
--- a/mv.c
+++ /dev/null
@@ -1,168 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini mv implementation for busybox
4 *
5 *
6 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <dirent.h>
28#include <errno.h>
29#include <stdlib.h>
30
31#include "busybox.h"
32
33static int flags;
34
35static int manual_rename(const char *source, const char *dest)
36{
37 struct stat source_stat;
38 struct stat dest_stat;
39 int source_exists = 1;
40 int dest_exists = 1;
41
42 if (stat(source, &source_stat) < 0) {
43 if (errno != ENOENT) {
44 perror_msg("unable to stat `%s'", source);
45 return -1;
46 }
47 source_exists = 0;
48 }
49
50 if (stat(dest, &dest_stat) < 0) {
51 if (errno != ENOENT) {
52 perror_msg("unable to stat `%s'", dest);
53 return -1;
54 }
55 dest_exists = 0;
56 }
57
58 if (dest_exists) {
59 if (S_ISDIR(dest_stat.st_mode) &&
60 (!source_exists || !S_ISDIR(source_stat.st_mode))) {
61 error_msg("cannot overwrite directory with non-directory");
62 return -1;
63 }
64
65 if (!S_ISDIR(dest_stat.st_mode) && source_exists &&
66 S_ISDIR(source_stat.st_mode)) {
67 error_msg("cannot overwrite non-directory with directory");
68 return -1;
69 }
70
71 if (unlink(dest) < 0) {
72 perror_msg("cannot remove `%s'", dest);
73 return -1;
74 }
75 }
76
77 if (copy_file(source, dest,
78 FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS) < 0)
79 return -1;
80
81 if (remove_file(source, FILEUTILS_RECUR | FILEUTILS_FORCE) < 0)
82 return -1;
83
84 return 0;
85}
86
87static int move_file(const char *source, const char *dest)
88{
89 struct stat dest_stat;
90 int dest_exists = 1;
91
92 if (stat(dest, &dest_stat) < 0) {
93 if (errno != ENOENT) {
94 perror_msg("unable to stat `%s'", dest);
95 return -1;
96 }
97 dest_exists = 0;
98 }
99
100 if (dest_exists && !(flags & FILEUTILS_FORCE) &&
101 ((access(dest, W_OK) < 0 && isatty(0)) ||
102 (flags & FILEUTILS_INTERACTIVE))) {
103 fprintf(stderr, "mv: overwrite `%s'? ", dest);
104 if (!ask_confirmation())
105 return 0;
106 }
107
108 if (rename(source, dest) < 0) {
109 if (errno == EXDEV)
110 return manual_rename(source, dest);
111
112 perror_msg("unable to rename `%s'", source);
113 return -1;
114 }
115
116 return 0;
117}
118
119extern int mv_main(int argc, char **argv)
120{
121 int status = 0;
122 int opt;
123 int i;
124
125 while ((opt = getopt(argc, argv, "fi")) != -1)
126 switch (opt) {
127 case 'f':
128 flags &= ~FILEUTILS_INTERACTIVE;
129 flags |= FILEUTILS_FORCE;
130 break;
131 case 'i':
132 flags &= ~FILEUTILS_FORCE;
133 flags |= FILEUTILS_INTERACTIVE;
134 break;
135 default:
136 show_usage();
137 }
138
139 if (optind + 2 > argc)
140 show_usage();
141
142 if (optind + 2 == argc) {
143 struct stat dest_stat;
144 int dest_exists = 1;
145
146 if (stat(argv[optind + 1], &dest_stat) < 0) {
147 if (errno != ENOENT)
148 perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
149 dest_exists = 0;
150 }
151
152 if (!dest_exists || !S_ISDIR(dest_stat.st_mode)) {
153 if (move_file(argv[optind], argv[optind + 1]) < 0)
154 status = 1;
155 return status;
156 }
157 }
158
159 for (i = optind; i < argc - 1; i++) {
160 char *dest = concat_path_file(argv[argc - 1],
161 get_last_path_component(argv[i]));
162 if (move_file(argv[i], dest) < 0)
163 status = 1;
164 free(dest);
165 }
166
167 return status;
168}
diff --git a/nc.c b/nc.c
deleted file mode 100644
index 5335872e5..000000000
--- a/nc.c
+++ /dev/null
@@ -1,137 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/* nc: mini-netcat - built from the ground up for LRP
3 Copyright (C) 1998 Charles P. Wright
4
5 0.0.1 6K It works.
6 0.0.2 5K Smaller and you can also check the exit condition if you wish.
7 0.0.3 Uses select()
8
9 19980918 Busy Boxed! Dave Cinege
10 19990512 Uses Select. Charles P. Wright
11 19990513 Fixes stdin stupidity and uses buffers. Charles P. Wright
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27*/
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <netdb.h>
39#include <sys/time.h>
40#include <sys/ioctl.h>
41#include "busybox.h"
42
43int nc_main(int argc, char **argv)
44{
45 int do_listen = 0, lport = 0, tmpfd, opt, sfd;
46 char buf[BUFSIZ];
47
48 struct sockaddr_in address;
49 struct hostent *hostinfo;
50
51 fd_set readfds, testfds;
52
53 while ((opt = getopt(argc, argv, "lp:")) > 0) {
54 switch (opt) {
55 case 'l':
56 do_listen++;
57 break;
58 case 'p':
59 lport = atoi(optarg);
60 break;
61 default:
62 show_usage();
63 }
64 }
65
66 if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
67 show_usage();
68
69 if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
70 perror_msg_and_die("socket");
71
72 address.sin_family = AF_INET;
73
74 if (lport != 0) {
75 memset(&address.sin_addr, 0, sizeof(address.sin_addr));
76 address.sin_port = htons(lport);
77
78 if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
79 perror_msg_and_die("bind");
80 }
81
82 if (do_listen) {
83 socklen_t addrlen = sizeof(address);
84
85 if (listen(sfd, 1) < 0)
86 perror_msg_and_die("listen");
87
88 if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
89 perror_msg_and_die("accept");
90
91 close(sfd);
92 sfd = tmpfd;
93 } else {
94 hostinfo = xgethostbyname(argv[optind]);
95
96 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
97 address.sin_port = htons(atoi(argv[optind+1]));
98
99 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
100 perror_msg_and_die("connect");
101 }
102
103 FD_ZERO(&readfds);
104 FD_SET(sfd, &readfds);
105 FD_SET(STDIN_FILENO, &readfds);
106
107 while (1) {
108 int fd;
109 int ofd;
110 int nread;
111
112 testfds = readfds;
113
114 if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
115 perror_msg_and_die("select");
116
117 for (fd = 0; fd < FD_SETSIZE; fd++) {
118 if (FD_ISSET(fd, &testfds)) {
119 if ((nread = safe_read(fd, buf, sizeof(buf))) < 0)
120 perror_msg_and_die("read");
121
122 if (fd == sfd) {
123 if (nread == 0)
124 exit(0);
125 ofd = STDOUT_FILENO;
126 } else {
127 if (nread == 0)
128 shutdown(sfd, 1);
129 ofd = sfd;
130 }
131
132 if (full_write(ofd, buf, nread) < 0)
133 perror_msg_and_die("write");
134 }
135 }
136 }
137}
diff --git a/networking/Makefile b/networking/Makefile
new file mode 100644
index 000000000..4dd0cdb56
--- /dev/null
+++ b/networking/Makefile
@@ -0,0 +1,45 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := networking.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27
28obj-$(CONFIG_HOSTNAME) += hostname.o
29obj-$(CONFIG_IFCONFIG) += ifconfig.o
30obj-$(CONFIG_NC) += nc.o
31obj-$(CONFIG_NSLOOKUP) += nslookup.o
32obj-$(CONFIG_PING) += ping.o
33obj-$(CONFIG_ROUTE) += route.o
34obj-$(CONFIG_TELNET) += telnet.o
35obj-$(CONFIG_TFTP) += tftp.o
36obj-$(CONFIG_TRACEROUTE) += traceroute.o
37obj-$(CONFIG_WGET) += wget.o
38
39
40# Hand off to toplevel Rules.mak
41include $(TOPDIR)/Rules.mak
42
43clean:
44 rm -f $(L_TARGET) *.o core
45
diff --git a/networking/config.in b/networking/config.in
new file mode 100644
index 000000000..577d925c3
--- /dev/null
+++ b/networking/config.in
@@ -0,0 +1,21 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Networking Utilities'
8
9bool 'hostname' CONFIG_HOSTNAME
10bool 'ifconfig' CONFIG_IFCONFIG
11bool 'nc' CONFIG_NC
12bool 'nslookup' CONFIG_NSLOOKUP
13bool 'ping' CONFIG_PING
14bool 'route' CONFIG_ROUTE
15bool 'telnet' CONFIG_TELNET
16bool 'tftp' CONFIG_TFTP
17bool 'traceroute' CONFIG_TRACEROUTE
18bool 'wget' CONFIG_WGET
19
20endmenu
21
diff --git a/networking/hostname.c b/networking/hostname.c
index d87851509..7a26c1b2c 100644
--- a/networking/hostname.c
+++ b/networking/hostname.c
@@ -1,6 +1,6 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * $Id: hostname.c,v 1.30 2001/06/26 02:06:08 bug1 Exp $ 3 * $Id: hostname.c,v 1.31 2001/10/24 04:59:56 andersen Exp $
4 * Mini hostname implementation for busybox 4 * Mini hostname implementation for busybox
5 * 5 *
6 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org> 6 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
@@ -49,7 +49,7 @@ static void do_sethostname(char *s, int isfile)
49 } else { 49 } else {
50 f = xfopen(s, "r"); 50 f = xfopen(s, "r");
51 fgets(buf, 255, f); 51 fgets(buf, 255, f);
52#ifdef BB_FEATURE_CLEAN_UP 52#ifdef CONFIG_FEATURE_CLEAN_UP
53 fclose(f); 53 fclose(f);
54#endif 54#endif
55 chomp(buf); 55 chomp(buf);
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index c77ea04b1..3beecaf3d 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -15,7 +15,7 @@
15 * Foundation; either version 2 of the License, or (at 15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version. 16 * your option) any later version.
17 * 17 *
18 * $Id: ifconfig.c,v 1.12 2001/08/10 06:02:23 mjn3 Exp $ 18 * $Id: ifconfig.c,v 1.13 2001/10/24 04:59:56 andersen Exp $
19 * 19 *
20 */ 20 */
21 21
@@ -44,7 +44,7 @@
44#include <linux/if_ether.h> 44#include <linux/if_ether.h>
45#include "busybox.h" 45#include "busybox.h"
46 46
47#ifdef BB_FEATURE_IFCONFIG_SLIP 47#ifdef CONFIG_FEATURE_IFCONFIG_SLIP
48#include <linux/if_slip.h> 48#include <linux/if_slip.h>
49#endif 49#endif
50 50
@@ -173,7 +173,7 @@ static const struct arg1opt Arg1Opt[] = {
173 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, 173 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
174 {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)}, 174 {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
175 {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)}, 175 {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
176#ifdef BB_FEATURE_IFCONFIG_HW 176#ifdef CONFIG_FEATURE_IFCONFIG_HW
177 {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)}, 177 {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)},
178#endif 178#endif
179 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, 179 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
@@ -183,7 +183,7 @@ static const struct arg1opt Arg1Opt[] = {
183#ifdef SIOCSOUTFILL 183#ifdef SIOCSOUTFILL
184 {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)}, 184 {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)},
185#endif 185#endif
186#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 186#ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
187 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)}, 187 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)},
188 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)}, 188 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)},
189 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)}, 189 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)},
@@ -199,7 +199,7 @@ static const struct options OptArray[] = {
199 {"dstaddr", N_ARG, ARG_DSTADDR, 0}, 199 {"dstaddr", N_ARG, ARG_DSTADDR, 0},
200 {"netmask", N_ARG, ARG_NETMASK, 0}, 200 {"netmask", N_ARG, ARG_NETMASK, 0},
201 {"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST}, 201 {"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST},
202#ifdef BB_FEATURE_IFCONFIG_HW 202#ifdef CONFIG_FEATURE_IFCONFIG_HW
203 {"hw", N_ARG, ARG_HW, 0}, 203 {"hw", N_ARG, ARG_HW, 0},
204#endif 204#endif
205 {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT}, 205 {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
@@ -209,7 +209,7 @@ static const struct options OptArray[] = {
209#ifdef SIOCSOUTFILL 209#ifdef SIOCSOUTFILL
210 {"outfill", N_ARG, ARG_OUTFILL, 0}, 210 {"outfill", N_ARG, ARG_OUTFILL, 0},
211#endif 211#endif
212#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 212#ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
213 {"mem_start", N_ARG, ARG_MEM_START, 0}, 213 {"mem_start", N_ARG, ARG_MEM_START, 0},
214 {"io_addr", N_ARG, ARG_IO_ADDR, 0}, 214 {"io_addr", N_ARG, ARG_IO_ADDR, 0},
215 {"irq", N_ARG, ARG_IRQ, 0}, 215 {"irq", N_ARG, ARG_IRQ, 0},
@@ -229,11 +229,11 @@ static const struct options OptArray[] = {
229 * A couple of prototypes. 229 * A couple of prototypes.
230 */ 230 */
231 231
232#ifdef BB_FEATURE_IFCONFIG_HW 232#ifdef CONFIG_FEATURE_IFCONFIG_HW
233static int in_ether(char *bufp, struct sockaddr *sap); 233static int in_ether(char *bufp, struct sockaddr *sap);
234#endif 234#endif
235 235
236#ifdef BB_FEATURE_IFCONFIG_STATUS 236#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
237extern int interface_opt_a; 237extern int interface_opt_a;
238extern int display_interfaces(char *ifname); 238extern int display_interfaces(char *ifname);
239#endif 239#endif
@@ -246,7 +246,7 @@ int ifconfig_main(int argc, char **argv)
246{ 246{
247 struct ifreq ifr; 247 struct ifreq ifr;
248 struct sockaddr_in sai; 248 struct sockaddr_in sai;
249#ifdef BB_FEATURE_IFCONFIG_HW 249#ifdef CONFIG_FEATURE_IFCONFIG_HW
250 struct sockaddr sa; 250 struct sockaddr sa;
251#endif 251#endif
252 const struct arg1opt *a1op; 252 const struct arg1opt *a1op;
@@ -266,7 +266,7 @@ int ifconfig_main(int argc, char **argv)
266 ++argv; 266 ++argv;
267 --argc; 267 --argc;
268 268
269#ifdef BB_FEATURE_IFCONFIG_STATUS 269#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
270 if ((argc > 0) && (strcmp(*argv,"-a") == 0)) { 270 if ((argc > 0) && (strcmp(*argv,"-a") == 0)) {
271 interface_opt_a = 1; 271 interface_opt_a = 1;
272 --argc; 272 --argc;
@@ -275,7 +275,7 @@ int ifconfig_main(int argc, char **argv)
275#endif 275#endif
276 276
277 if(argc <= 1) { 277 if(argc <= 1) {
278#ifdef BB_FEATURE_IFCONFIG_STATUS 278#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
279 return display_interfaces(argc ? *argv : NULL); 279 return display_interfaces(argc ? *argv : NULL);
280#else 280#else
281 error_msg_and_die( "ifconfig was not compiled with interface status display support."); 281 error_msg_and_die( "ifconfig was not compiled with interface status display support.");
@@ -333,7 +333,7 @@ int ifconfig_main(int argc, char **argv)
333 HOSTNAME: 333 HOSTNAME:
334 did_flags |= (mask & A_NETMASK); 334 did_flags |= (mask & A_NETMASK);
335 if (mask & A_CAST_HOST_COPY) { 335 if (mask & A_CAST_HOST_COPY) {
336#ifdef BB_FEATURE_IFCONFIG_HW 336#ifdef CONFIG_FEATURE_IFCONFIG_HW
337 if (mask & A_CAST_RESOLVE) { 337 if (mask & A_CAST_RESOLVE) {
338#endif 338#endif
339 safe_strncpy(host, *argv, (sizeof host)); 339 safe_strncpy(host, *argv, (sizeof host));
@@ -348,7 +348,7 @@ int ifconfig_main(int argc, char **argv)
348 continue; 348 continue;
349 } 349 }
350 p = (char *) &sai; 350 p = (char *) &sai;
351#ifdef BB_FEATURE_IFCONFIG_HW 351#ifdef CONFIG_FEATURE_IFCONFIG_HW
352 } else { /* A_CAST_HOST_COPY_IN_ETHER */ 352 } else { /* A_CAST_HOST_COPY_IN_ETHER */
353 /* This is the "hw" arg case. */ 353 /* This is the "hw" arg case. */
354 if (strcmp("ether", *argv) || (*++argv == NULL)) { 354 if (strcmp("ether", *argv) || (*++argv == NULL)) {
@@ -368,7 +368,7 @@ int ifconfig_main(int argc, char **argv)
368 } else { 368 } else {
369 unsigned int i = strtoul(*argv,NULL,0); 369 unsigned int i = strtoul(*argv,NULL,0);
370 p = ((char *)(&ifr)) + a1op->ifr_offset; 370 p = ((char *)(&ifr)) + a1op->ifr_offset;
371#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 371#ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
372 if (mask & A_MAP_TYPE) { 372 if (mask & A_MAP_TYPE) {
373 if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) { 373 if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
374 ++goterr; 374 ++goterr;
@@ -446,7 +446,7 @@ int ifconfig_main(int argc, char **argv)
446 return goterr; 446 return goterr;
447} 447}
448 448
449#ifdef BB_FEATURE_IFCONFIG_HW 449#ifdef CONFIG_FEATURE_IFCONFIG_HW
450/* Input an Ethernet address and convert to binary. */ 450/* Input an Ethernet address and convert to binary. */
451static int 451static int
452in_ether(char *bufp, struct sockaddr *sap) 452in_ether(char *bufp, struct sockaddr *sap)
diff --git a/networking/nslookup.c b/networking/nslookup.c
index 3e32ca9c0..a1a12d992 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini nslookup implementation for busybox 3 * Mini nslookup implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
6 * Written by John Beppu <beppu@lineo.com> 6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -180,4 +180,4 @@ int nslookup_main(int argc, char **argv)
180 return EXIT_SUCCESS; 180 return EXIT_SUCCESS;
181} 181}
182 182
183/* $Id: nslookup.c,v 1.25 2001/10/01 17:50:25 kraai Exp $ */ 183/* $Id: nslookup.c,v 1.26 2001/10/24 04:59:56 andersen Exp $ */
diff --git a/networking/ping.c b/networking/ping.c
index 5ca5dd9e0..476c15cea 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -1,6 +1,6 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * $Id: ping.c,v 1.46 2001/07/17 01:12:36 andersen Exp $ 3 * $Id: ping.c,v 1.47 2001/10/24 04:59:56 andersen Exp $
4 * Mini ping implementation for busybox 4 * Mini ping implementation for busybox
5 * 5 *
6 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org> 6 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
@@ -174,7 +174,7 @@ static int in_cksum(unsigned short *buf, int sz)
174} 174}
175 175
176/* simple version */ 176/* simple version */
177#ifndef BB_FEATURE_FANCY_PING 177#ifndef CONFIG_FEATURE_FANCY_PING
178static char *hostname = NULL; 178static char *hostname = NULL;
179 179
180static void noresp(int ign) 180static void noresp(int ign)
@@ -247,7 +247,7 @@ extern int ping_main(int argc, char **argv)
247 return EXIT_SUCCESS; 247 return EXIT_SUCCESS;
248} 248}
249 249
250#else /* ! BB_FEATURE_FANCY_PING */ 250#else /* ! CONFIG_FEATURE_FANCY_PING */
251/* full(er) version */ 251/* full(er) version */
252static char *hostname = NULL; 252static char *hostname = NULL;
253static struct sockaddr_in pingaddr; 253static struct sockaddr_in pingaddr;
@@ -516,7 +516,7 @@ extern int ping_main(int argc, char **argv)
516 ping(*argv); 516 ping(*argv);
517 return EXIT_SUCCESS; 517 return EXIT_SUCCESS;
518} 518}
519#endif /* ! BB_FEATURE_FANCY_PING */ 519#endif /* ! CONFIG_FEATURE_FANCY_PING */
520 520
521/* 521/*
522 * Copyright (c) 1989 The Regents of the University of California. 522 * Copyright (c) 1989 The Regents of the University of California.
diff --git a/networking/telnet.c b/networking/telnet.c
index ce82a0ee8..57494089d 100644
--- a/networking/telnet.c
+++ b/networking/telnet.c
@@ -137,7 +137,7 @@ static int local_bind(int port);
137/* Some globals */ 137/* Some globals */
138static int one = 1; 138static int one = 1;
139 139
140#ifdef BB_FEATURE_TELNET_TTYPE 140#ifdef CONFIG_FEATURE_TELNET_TTYPE
141static char *ttype; 141static char *ttype;
142#endif 142#endif
143 143
@@ -326,7 +326,7 @@ static void putiac1(byte c)
326} 326}
327#endif 327#endif
328 328
329#ifdef BB_FEATURE_TELNET_TTYPE 329#ifdef CONFIG_FEATURE_TELNET_TTYPE
330static void putiac_subopt(byte c, char *str) 330static void putiac_subopt(byte c, char *str)
331{ 331{
332 int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) 332 int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 )
@@ -453,7 +453,7 @@ static inline void to_sga()
453 return; 453 return;
454} 454}
455 455
456#ifdef BB_FEATURE_TELNET_TTYPE 456#ifdef CONFIG_FEATURE_TELNET_TTYPE
457static inline void to_ttype() 457static inline void to_ttype()
458{ 458{
459 /* Tell server we will (or won't) do TTYPE */ 459 /* Tell server we will (or won't) do TTYPE */
@@ -473,7 +473,7 @@ static void telopt(byte c)
473 { 473 {
474 case TELOPT_ECHO: to_echo(c); break; 474 case TELOPT_ECHO: to_echo(c); break;
475 case TELOPT_SGA: to_sga(c); break; 475 case TELOPT_SGA: to_sga(c); break;
476#ifdef BB_FEATURE_TELNET_TTYPE 476#ifdef CONFIG_FEATURE_TELNET_TTYPE
477 case TELOPT_TTYPE: to_ttype(c); break; 477 case TELOPT_TTYPE: to_ttype(c); break;
478#endif 478#endif
479 default: to_notsup(c); break; 479 default: to_notsup(c); break;
@@ -492,7 +492,7 @@ static int subneg(byte c)
492 case TS_SUB1: 492 case TS_SUB1:
493 if (c == IAC) 493 if (c == IAC)
494 G.telstate = TS_SUB2; 494 G.telstate = TS_SUB2;
495#ifdef BB_FEATURE_TELNET_TTYPE 495#ifdef CONFIG_FEATURE_TELNET_TTYPE
496 else 496 else
497 if (c == TELOPT_TTYPE) 497 if (c == TELOPT_TTYPE)
498 putiac_subopt(TELOPT_TTYPE,ttype); 498 putiac_subopt(TELOPT_TTYPE,ttype);
@@ -537,7 +537,7 @@ extern int telnet_main(int argc, char** argv)
537 int maxfd; 537 int maxfd;
538#endif 538#endif
539 539
540#ifdef BB_FEATURE_TELNET_TTYPE 540#ifdef CONFIG_FEATURE_TELNET_TTYPE
541 ttype = getenv("TERM"); 541 ttype = getenv("TERM");
542#endif 542#endif
543 543
diff --git a/networking/tftp.c b/networking/tftp.c
index 530b3d134..38a6f81f0 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -46,7 +46,7 @@
46 46
47#include "busybox.h" 47#include "busybox.h"
48 48
49//#define BB_FEATURE_TFTP_DEBUG 49//#define CONFIG_FEATURE_TFTP_DEBUG
50 50
51#define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */ 51#define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
52#define TFTP_TIMEOUT 5 /* seconds */ 52#define TFTP_TIMEOUT 5 /* seconds */
@@ -74,7 +74,7 @@ static const char *tftp_error_msg[] = {
74const int tftp_cmd_get = 1; 74const int tftp_cmd_get = 1;
75const int tftp_cmd_put = 2; 75const int tftp_cmd_put = 2;
76 76
77#ifdef BB_FEATURE_TFTP_BLOCKSIZE 77#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
78 78
79static int tftp_blocksize_check(int blocksize, int bufsize) 79static int tftp_blocksize_check(int blocksize, int bufsize)
80{ 80{
@@ -158,11 +158,11 @@ static inline int tftp(const int cmd, const struct hostent *host,
158 int timeout = bb_tftp_num_retries; 158 int timeout = bb_tftp_num_retries;
159 int block_nr = 1; 159 int block_nr = 1;
160 160
161#ifdef BB_FEATURE_TFTP_BLOCKSIZE 161#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
162 int want_option_ack = 0; 162 int want_option_ack = 0;
163#endif 163#endif
164 164
165 RESERVE_BB_BUFFER(buf, tftp_bufsize + 4); /* Opcode + Block # + Data */ 165 RESERVE_CONFIG_BUFFER(buf, tftp_bufsize + 4); /* Opcode + Block # + Data */
166 166
167 tftp_bufsize += 4; 167 tftp_bufsize += 4;
168 168
@@ -230,7 +230,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
230 memcpy(cp, "octet", 6); 230 memcpy(cp, "octet", 6);
231 cp += 6; 231 cp += 6;
232 232
233#ifdef BB_FEATURE_TFTP_BLOCKSIZE 233#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
234 234
235 len = tftp_bufsize - 4; /* data block size */ 235 len = tftp_bufsize - 4; /* data block size */
236 236
@@ -290,7 +290,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
290 290
291 len = cp - buf; 291 len = cp - buf;
292 292
293#ifdef BB_FEATURE_TFTP_DEBUG 293#ifdef CONFIG_FEATURE_TFTP_DEBUG
294 printf("sending %u bytes\n", len); 294 printf("sending %u bytes\n", len);
295 for (cp = buf; cp < &buf[len]; cp++) 295 for (cp = buf; cp < &buf[len]; cp++)
296 printf("%02x ", *cp); 296 printf("%02x ", *cp);
@@ -367,7 +367,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
367 opcode = ntohs(*((unsigned short *) buf)); 367 opcode = ntohs(*((unsigned short *) buf));
368 tmp = ntohs(*((unsigned short *) &buf[2])); 368 tmp = ntohs(*((unsigned short *) &buf[2]));
369 369
370#ifdef BB_FEATURE_TFTP_DEBUG 370#ifdef CONFIG_FEATURE_TFTP_DEBUG
371 printf("received %d bytes: %04x %04x\n", len, opcode, tmp); 371 printf("received %d bytes: %04x %04x\n", len, opcode, tmp);
372#endif 372#endif
373 373
@@ -390,7 +390,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
390 break; 390 break;
391 } 391 }
392 392
393#ifdef BB_FEATURE_TFTP_BLOCKSIZE 393#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
394 if (want_option_ack) { 394 if (want_option_ack) {
395 395
396 want_option_ack = 0; 396 want_option_ack = 0;
@@ -416,7 +416,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
416 else { 416 else {
417 opcode = TFTP_ACK; 417 opcode = TFTP_ACK;
418 } 418 }
419#ifdef BB_FEATURE_TFTP_DEBUG 419#ifdef CONFIG_FEATURE_TFTP_DEBUG
420 printf("using blksize %u\n"); 420 printf("using blksize %u\n");
421#endif 421#endif
422 tftp_bufsize = foo + 4; 422 tftp_bufsize = foo + 4;
@@ -470,10 +470,10 @@ static inline int tftp(const int cmd, const struct hostent *host,
470 } 470 }
471 } 471 }
472 472
473#ifdef BB_FEATURE_CLEAN_UP 473#ifdef CONFIG_FEATURE_CLEAN_UP
474 close(socketfd); 474 close(socketfd);
475 475
476 RELEASE_BB_BUFFER(buf); 476 RELEASE_CONFIG_BUFFER(buf);
477#endif 477#endif
478 478
479 return finished ? EXIT_SUCCESS : EXIT_FAILURE; 479 return finished ? EXIT_SUCCESS : EXIT_FAILURE;
@@ -494,19 +494,19 @@ int tftp_main(int argc, char **argv)
494 494
495 /* figure out what to pass to getopt */ 495 /* figure out what to pass to getopt */
496 496
497#ifdef BB_FEATURE_TFTP_BLOCKSIZE 497#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
498#define BS "b:" 498#define BS "b:"
499#else 499#else
500#define BS 500#define BS
501#endif 501#endif
502 502
503#ifdef BB_FEATURE_TFTP_GET 503#ifdef CONFIG_FEATURE_TFTP_GET
504#define GET "g" 504#define GET "g"
505#else 505#else
506#define GET 506#define GET
507#endif 507#endif
508 508
509#ifdef BB_FEATURE_TFTP_PUT 509#ifdef CONFIG_FEATURE_TFTP_PUT
510#define PUT "p" 510#define PUT "p"
511#else 511#else
512#define PUT 512#define PUT
@@ -514,7 +514,7 @@ int tftp_main(int argc, char **argv)
514 514
515 while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) { 515 while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) {
516 switch (opt) { 516 switch (opt) {
517#ifdef BB_FEATURE_TFTP_BLOCKSIZE 517#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
518 case 'b': 518 case 'b':
519 blocksize = atoi(optarg); 519 blocksize = atoi(optarg);
520 if (!tftp_blocksize_check(blocksize, 0)) { 520 if (!tftp_blocksize_check(blocksize, 0)) {
@@ -522,13 +522,13 @@ int tftp_main(int argc, char **argv)
522 } 522 }
523 break; 523 break;
524#endif 524#endif
525#ifdef BB_FEATURE_TFTP_GET 525#ifdef CONFIG_FEATURE_TFTP_GET
526 case 'g': 526 case 'g':
527 cmd = tftp_cmd_get; 527 cmd = tftp_cmd_get;
528 flags = O_WRONLY | O_CREAT; 528 flags = O_WRONLY | O_CREAT;
529 break; 529 break;
530#endif 530#endif
531#ifdef BB_FEATURE_TFTP_PUT 531#ifdef CONFIG_FEATURE_TFTP_PUT
532 case 'p': 532 case 'p':
533 cmd = tftp_cmd_put; 533 cmd = tftp_cmd_put;
534 flags = O_RDONLY; 534 flags = O_RDONLY;
@@ -558,7 +558,7 @@ int tftp_main(int argc, char **argv)
558 port = atoi(argv[optind + 1]); 558 port = atoi(argv[optind + 1]);
559 } 559 }
560 560
561#ifdef BB_FEATURE_TFTP_DEBUG 561#ifdef CONFIG_FEATURE_TFTP_DEBUG
562 printf("using server \"%s\", remotefile \"%s\", " 562 printf("using server \"%s\", remotefile \"%s\", "
563 "localfile \"%s\".\n", 563 "localfile \"%s\".\n",
564 inet_ntoa(*((struct in_addr *) host->h_addr)), 564 inet_ntoa(*((struct in_addr *) host->h_addr)),
@@ -567,7 +567,7 @@ int tftp_main(int argc, char **argv)
567 567
568 result = tftp(cmd, host, remotefile, fd, port, blocksize); 568 result = tftp(cmd, host, remotefile, fd, port, blocksize);
569 569
570#ifdef BB_FEATURE_CLEAN_UP 570#ifdef CONFIG_FEATURE_CLEAN_UP
571 close(fd); 571 close(fd);
572#endif 572#endif
573 return(result); 573 return(result);
diff --git a/networking/traceroute.c b/networking/traceroute.c
index a3abd0a00..e7d9725af 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -62,9 +62,9 @@
62 * Tue Dec 20 03:50:13 PST 1988 62 * Tue Dec 20 03:50:13 PST 1988
63 */ 63 */
64 64
65#undef BB_FEATURE_TRACEROUTE_VERBOSE 65#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
66//#define BB_FEATURE_TRACEROUTE_VERBOSE 66//#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
67#undef BB_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */ 67#undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
68 68
69#include <stdio.h> 69#include <stdio.h>
70#include <errno.h> 70#include <errno.h>
@@ -213,7 +213,7 @@ static int max_ttl = 30;
213static u_short ident; 213static u_short ident;
214static u_short port = 32768+666; /* start udp dest port # for probe packets */ 214static u_short port = 32768+666; /* start udp dest port # for probe packets */
215 215
216#ifdef BB_FEATURE_TRACEROUTE_VERBOSE 216#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
217static int verbose; 217static int verbose;
218#endif 218#endif
219static int waittime = 5; /* time to wait for response (in seconds) */ 219static int waittime = 5; /* time to wait for response (in seconds) */
@@ -269,7 +269,7 @@ print(u_char *buf, int cc, struct sockaddr_in *from)
269 cc -= hlen; 269 cc -= hlen;
270 270
271 inetname(from); 271 inetname(from);
272#ifdef BB_FEATURE_TRACEROUTE_VERBOSE 272#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
273 if (verbose) 273 if (verbose)
274 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); 274 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
275#endif 275#endif
@@ -319,7 +319,7 @@ wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
319 return(cc); 319 return(cc);
320} 320}
321 321
322#ifdef BB_FEATURE_TRACEROUTE_VERBOSE 322#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
323/* 323/*
324 * Convert an ICMP "type" field to a printable string. 324 * Convert an ICMP "type" field to a printable string.
325 */ 325 */
@@ -353,7 +353,7 @@ packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
353 ip = (struct ip *) buf; 353 ip = (struct ip *) buf;
354 hlen = ip->ip_hl << 2; 354 hlen = ip->ip_hl << 2;
355 if (cc < hlen + ICMP_MINLEN) { 355 if (cc < hlen + ICMP_MINLEN) {
356#ifdef BB_FEATURE_TRACEROUTE_VERBOSE 356#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
357 if (verbose) 357 if (verbose)
358 printf("packet too short (%d bytes) from %s\n", cc, 358 printf("packet too short (%d bytes) from %s\n", cc,
359 inet_ntoa(from->sin_addr)); 359 inet_ntoa(from->sin_addr));
@@ -376,7 +376,7 @@ packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
376 up->dest == htons(port+seq)) 376 up->dest == htons(port+seq))
377 return (type == ICMP_TIMXCEED? -1 : code+1); 377 return (type == ICMP_TIMXCEED? -1 : code+1);
378 } 378 }
379#ifdef BB_FEATURE_TRACEROUTE_VERBOSE 379#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
380 if (verbose) { 380 if (verbose) {
381 int i; 381 int i;
382 u_long *lp = (u_long *)&icp->icmp_ip; 382 u_long *lp = (u_long *)&icp->icmp_ip;
@@ -430,7 +430,7 @@ send_probe(int seq, int ttl)
430 430
431 431
432int 432int
433#ifndef BB_TRACEROUTE 433#ifndef CONFIG_TRACEROUTE
434main(argc, argv) 434main(argc, argv)
435#else 435#else
436traceroute_main(argc, argv) 436traceroute_main(argc, argv)
@@ -454,7 +454,7 @@ traceroute_main(argc, argv)
454 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) 454 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
455 switch(ch) { 455 switch(ch) {
456 case 'd': 456 case 'd':
457#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG 457#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
458 options |= SO_DEBUG; 458 options |= SO_DEBUG;
459#endif 459#endif
460 break; 460 break;
@@ -492,7 +492,7 @@ traceroute_main(argc, argv)
492 error_msg_and_die("tos must be 0 to 255."); 492 error_msg_and_die("tos must be 0 to 255.");
493 break; 493 break;
494 case 'v': 494 case 'v':
495#ifdef BB_FEATURE_TRACEROUTE_VERBOSE 495#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
496 verbose++; 496 verbose++;
497#endif 497#endif
498 break; 498 break;
@@ -537,7 +537,7 @@ traceroute_main(argc, argv)
537 537
538 s = create_icmp_socket(); 538 s = create_icmp_socket();
539 539
540#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG 540#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
541 if (options & SO_DEBUG) 541 if (options & SO_DEBUG)
542 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 542 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
543 (char *)&on, sizeof(on)); 543 (char *)&on, sizeof(on));
@@ -555,7 +555,7 @@ traceroute_main(argc, argv)
555 sizeof(on)) < 0) 555 sizeof(on)) < 0)
556 perror_msg_and_die("IP_HDRINCL"); 556 perror_msg_and_die("IP_HDRINCL");
557#endif IP_HDRINCL 557#endif IP_HDRINCL
558#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG 558#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
559 if (options & SO_DEBUG) 559 if (options & SO_DEBUG)
560 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 560 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
561 (char *)&on, sizeof(on)); 561 (char *)&on, sizeof(on));
diff --git a/networking/wget.c b/networking/wget.c
index 59373d1d9..41b4e30af 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -60,7 +60,7 @@ static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf);
60/* Globals (can be accessed from signal handlers */ 60/* Globals (can be accessed from signal handlers */
61static off_t filesize = 0; /* content-length of the file */ 61static off_t filesize = 0; /* content-length of the file */
62static int chunked = 0; /* chunked transfer encoding */ 62static int chunked = 0; /* chunked transfer encoding */
63#ifdef BB_FEATURE_WGET_STATUSBAR 63#ifdef CONFIG_FEATURE_WGET_STATUSBAR
64static void progressmeter(int flag); 64static void progressmeter(int flag);
65static char *curfile; /* Name of current file being transferred. */ 65static char *curfile; /* Name of current file being transferred. */
66static struct timeval start; /* Time a transfer started. */ 66static struct timeval start; /* Time a transfer started. */
@@ -126,7 +126,7 @@ static char *safe_fgets(char *s, int size, FILE *stream)
126 error_msg_and_die(s); } 126 error_msg_and_die(s); }
127 127
128 128
129#ifdef BB_FEATURE_WGET_AUTHENTICATION 129#ifdef CONFIG_FEATURE_WGET_AUTHENTICATION
130/* 130/*
131 * Base64-encode character string 131 * Base64-encode character string
132 * oops... isn't something similar in uuencode.c? 132 * oops... isn't something similar in uuencode.c?
@@ -245,20 +245,20 @@ int wget_main(int argc, char **argv)
245 /* Guess an output filename */ 245 /* Guess an output filename */
246 if (!fname_out) { 246 if (!fname_out) {
247 fname_out = 247 fname_out =
248#ifdef BB_FEATURE_WGET_STATUSBAR 248#ifdef CONFIG_FEATURE_WGET_STATUSBAR
249 curfile = 249 curfile =
250#endif 250#endif
251 get_last_path_component(target.path); 251 get_last_path_component(target.path);
252 if (fname_out==NULL || strlen(fname_out)<1) { 252 if (fname_out==NULL || strlen(fname_out)<1) {
253 fname_out = 253 fname_out =
254#ifdef BB_FEATURE_WGET_STATUSBAR 254#ifdef CONFIG_FEATURE_WGET_STATUSBAR
255 curfile = 255 curfile =
256#endif 256#endif
257 "index.html"; 257 "index.html";
258 } 258 }
259 if (dir_prefix != NULL) 259 if (dir_prefix != NULL)
260 fname_out = concat_path_file(dir_prefix, fname_out); 260 fname_out = concat_path_file(dir_prefix, fname_out);
261#ifdef BB_FEATURE_WGET_STATUSBAR 261#ifdef CONFIG_FEATURE_WGET_STATUSBAR
262 } else { 262 } else {
263 curfile = get_last_path_component(fname_out); 263 curfile = get_last_path_component(fname_out);
264#endif 264#endif
@@ -316,7 +316,7 @@ int wget_main(int argc, char **argv)
316 316
317 fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host); 317 fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host);
318 318
319#ifdef BB_FEATURE_WGET_AUTHENTICATION 319#ifdef CONFIG_FEATURE_WGET_AUTHENTICATION
320 if (target.user) { 320 if (target.user) {
321 fprintf(sfp, "Authorization: Basic %s\r\n", 321 fprintf(sfp, "Authorization: Basic %s\r\n",
322 base64enc(target.user, buf, sizeof(buf))); 322 base64enc(target.user, buf, sizeof(buf)));
@@ -475,14 +475,14 @@ read_response: if (fgets(buf, sizeof(buf), sfp) == NULL)
475 fgets(buf, sizeof(buf), dfp); 475 fgets(buf, sizeof(buf), dfp);
476 filesize = strtol(buf, (char **) NULL, 16); 476 filesize = strtol(buf, (char **) NULL, 16);
477 } 477 }
478#ifdef BB_FEATURE_WGET_STATUSBAR 478#ifdef CONFIG_FEATURE_WGET_STATUSBAR
479 if (quiet_flag==FALSE) 479 if (quiet_flag==FALSE)
480 progressmeter(-1); 480 progressmeter(-1);
481#endif 481#endif
482 do { 482 do {
483 while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) { 483 while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) {
484 safe_fwrite(buf, 1, n, output); 484 safe_fwrite(buf, 1, n, output);
485#ifdef BB_FEATURE_WGET_STATUSBAR 485#ifdef CONFIG_FEATURE_WGET_STATUSBAR
486 statbytes+=n; 486 statbytes+=n;
487#endif 487#endif
488 if (got_clen) 488 if (got_clen)
@@ -499,7 +499,7 @@ read_response: if (fgets(buf, sizeof(buf), sfp) == NULL)
499 if (n == 0 && ferror(dfp)) 499 if (n == 0 && ferror(dfp))
500 perror_msg_and_die("network read error"); 500 perror_msg_and_die("network read error");
501 } while (chunked); 501 } while (chunked);
502#ifdef BB_FEATURE_WGET_STATUSBAR 502#ifdef CONFIG_FEATURE_WGET_STATUSBAR
503 if (quiet_flag==FALSE) 503 if (quiet_flag==FALSE)
504 progressmeter(1); 504 progressmeter(1);
505#endif 505#endif
@@ -645,7 +645,7 @@ static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf)
645 return atoi(buf); 645 return atoi(buf);
646} 646}
647 647
648#ifdef BB_FEATURE_WGET_STATUSBAR 648#ifdef CONFIG_FEATURE_WGET_STATUSBAR
649/* Stuff below is from BSD rcp util.c, as added to openshh. 649/* Stuff below is from BSD rcp util.c, as added to openshh.
650 * Original copyright notice is retained at the end of this file. 650 * Original copyright notice is retained at the end of this file.
651 * 651 *
@@ -782,7 +782,7 @@ progressmeter(int flag)
782} 782}
783#endif 783#endif
784 784
785/* Original copyright notice which applies to the BB_FEATURE_WGET_STATUSBAR stuff, 785/* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff,
786 * much of which was blatently stolen from openssh. */ 786 * much of which was blatently stolen from openssh. */
787 787
788/*- 788/*-
@@ -817,7 +817,7 @@ progressmeter(int flag)
817 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 817 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
818 * SUCH DAMAGE. 818 * SUCH DAMAGE.
819 * 819 *
820 * $Id: wget.c,v 1.45 2001/07/19 22:28:01 andersen Exp $ 820 * $Id: wget.c,v 1.46 2001/10/24 04:59:56 andersen Exp $
821 */ 821 */
822 822
823 823
diff --git a/nfsmount.c b/nfsmount.c
deleted file mode 100644
index cd722acc3..000000000
--- a/nfsmount.c
+++ /dev/null
@@ -1,977 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * nfsmount.c -- Linux NFS mount
4 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
17 * numbers to be specified on the command line.
18 *
19 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
20 * Omit the call to connect() for Linux version 1.3.11 or later.
21 *
22 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
23 * Implemented the "bg", "fg" and "retry" mount options for NFS.
24 *
25 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
26 * - added Native Language Support
27 *
28 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
29 * plus NFSv3 stuff.
30 */
31
32/*
33 * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
34 */
35
36#include <unistd.h>
37#include <stdio.h>
38#include <string.h>
39#include <errno.h>
40#include <netdb.h>
41#include <sys/socket.h>
42#include <time.h>
43#include <sys/utsname.h>
44#include <netinet/in.h>
45#include <arpa/inet.h>
46#include <stdlib.h>
47#include "busybox.h"
48#undef TRUE
49#undef FALSE
50#include <rpc/rpc.h>
51#include <rpc/pmap_prot.h>
52#include <rpc/pmap_clnt.h>
53#include <linux/nfs.h> /* For the kernels nfs stuff */
54#include "nfsmount.h"
55
56#ifndef NFS_FHSIZE
57static const int NFS_FHSIZE = 32;
58#endif
59#ifndef NFS_PORT
60static const int NFS_PORT = 2049;
61#endif
62
63/* Disable the nls stuff */
64# undef bindtextdomain
65# define bindtextdomain(Domain, Directory) /* empty */
66# undef textdomain
67# define textdomain(Domain) /* empty */
68# define _(Text) (Text)
69# define N_(Text) (Text)
70
71static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
72static const int MS_RDONLY = 1; /* Mount read-only */
73static const int MS_NOSUID = 2; /* Ignore suid and sgid bits */
74static const int MS_NODEV = 4; /* Disallow access to device special files */
75static const int MS_NOEXEC = 8; /* Disallow program execution */
76static const int MS_SYNCHRONOUS = 16; /* Writes are synced at once */
77static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS */
78static const int MS_MANDLOCK = 64; /* Allow mandatory locks on an FS */
79static const int S_QUOTA = 128; /* Quota initialized for file/directory/symlink */
80static const int S_APPEND = 256; /* Append-only file */
81static const int S_IMMUTABLE = 512; /* Immutable file */
82static const int MS_NOATIME = 1024; /* Do not update access times. */
83static const int MS_NODIRATIME = 2048; /* Do not update directory access times */
84
85
86/*
87 * We want to be able to compile mount on old kernels in such a way
88 * that the binary will work well on more recent kernels.
89 * Thus, if necessary we teach nfsmount.c the structure of new fields
90 * that will come later.
91 *
92 * Moreover, the new kernel includes conflict with glibc includes
93 * so it is easiest to ignore the kernel altogether (at compile time).
94 */
95
96/* NOTE: Do not make this into a 'static const int' because the pre-processor
97 * needs to test this value in some #if statements. */
98#define NFS_MOUNT_VERSION 4
99
100struct nfs2_fh {
101 char data[32];
102};
103struct nfs3_fh {
104 unsigned short size;
105 unsigned char data[64];
106};
107
108struct nfs_mount_data {
109 int version; /* 1 */
110 int fd; /* 1 */
111 struct nfs2_fh old_root; /* 1 */
112 int flags; /* 1 */
113 int rsize; /* 1 */
114 int wsize; /* 1 */
115 int timeo; /* 1 */
116 int retrans; /* 1 */
117 int acregmin; /* 1 */
118 int acregmax; /* 1 */
119 int acdirmin; /* 1 */
120 int acdirmax; /* 1 */
121 struct sockaddr_in addr; /* 1 */
122 char hostname[256]; /* 1 */
123 int namlen; /* 2 */
124 unsigned int bsize; /* 3 */
125 struct nfs3_fh root; /* 4 */
126};
127
128/* bits in the flags field */
129
130static const int NFS_MOUNT_SOFT = 0x0001; /* 1 */
131static const int NFS_MOUNT_INTR = 0x0002; /* 1 */
132static const int NFS_MOUNT_SECURE = 0x0004; /* 1 */
133static const int NFS_MOUNT_POSIX = 0x0008; /* 1 */
134static const int NFS_MOUNT_NOCTO = 0x0010; /* 1 */
135static const int NFS_MOUNT_NOAC = 0x0020; /* 1 */
136static const int NFS_MOUNT_TCP = 0x0040; /* 2 */
137static const int NFS_MOUNT_VER3 = 0x0080; /* 3 */
138static const int NFS_MOUNT_KERBEROS = 0x0100; /* 3 */
139static const int NFS_MOUNT_NONLM = 0x0200; /* 3 */
140
141
142#define UTIL_LINUX_VERSION "2.10m"
143#define util_linux_version "util-linux-2.10m"
144
145#define HAVE_inet_aton
146#define HAVE_scsi_h
147#define HAVE_blkpg_h
148#define HAVE_kd_h
149#define HAVE_termcap
150#define HAVE_locale_h
151#define HAVE_libintl_h
152#define ENABLE_NLS
153#define HAVE_langinfo_h
154#define HAVE_progname
155#define HAVE_openpty
156#define HAVE_nanosleep
157#define HAVE_personality
158#define HAVE_tm_gmtoff
159
160static char *nfs_strerror(int status);
161
162#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
163#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
164
165static const int EX_FAIL = 32; /* mount failure */
166static const int EX_BG = 256; /* retry in background (internal only) */
167
168
169/*
170 * nfs_mount_version according to the sources seen at compile time.
171 */
172static int nfs_mount_version;
173
174/*
175 * Unfortunately, the kernel prints annoying console messages
176 * in case of an unexpected nfs mount version (instead of
177 * just returning some error). Therefore we'll have to try
178 * and figure out what version the kernel expects.
179 *
180 * Variables:
181 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
182 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
183 * nfs_mount_version: version this source and running kernel can handle
184 */
185static void
186find_kernel_nfs_mount_version(void)
187{
188 static int kernel_version = 0;
189
190 if (kernel_version)
191 return;
192
193 nfs_mount_version = NFS_MOUNT_VERSION; /* default */
194
195 kernel_version = get_kernel_revision();
196 if (kernel_version) {
197 if (kernel_version < MAKE_VERSION(2,1,32))
198 nfs_mount_version = 1;
199 else if (kernel_version < MAKE_VERSION(2,2,18) ||
200 (kernel_version >= MAKE_VERSION(2,3,0) &&
201 kernel_version < MAKE_VERSION(2,3,99)))
202 nfs_mount_version = 3;
203 else
204 nfs_mount_version = 4; /* since 2.3.99pre4 */
205 }
206 if (nfs_mount_version > NFS_MOUNT_VERSION)
207 nfs_mount_version = NFS_MOUNT_VERSION;
208}
209
210static struct pmap *
211get_mountport(struct sockaddr_in *server_addr,
212 long unsigned prog,
213 long unsigned version,
214 long unsigned proto,
215 long unsigned port)
216{
217struct pmaplist *pmap;
218static struct pmap p = {0, 0, 0, 0};
219
220server_addr->sin_port = PMAPPORT;
221pmap = pmap_getmaps(server_addr);
222
223if (version > MAX_NFSPROT)
224 version = MAX_NFSPROT;
225if (!prog)
226 prog = MOUNTPROG;
227p.pm_prog = prog;
228p.pm_vers = version;
229p.pm_prot = proto;
230p.pm_port = port;
231
232while (pmap) {
233 if (pmap->pml_map.pm_prog != prog)
234 goto next;
235 if (!version && p.pm_vers > pmap->pml_map.pm_vers)
236 goto next;
237 if (version > 2 && pmap->pml_map.pm_vers != version)
238 goto next;
239 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
240 goto next;
241 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
242 (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
243 (port && pmap->pml_map.pm_port != port))
244 goto next;
245 memcpy(&p, &pmap->pml_map, sizeof(p));
246next:
247 pmap = pmap->pml_next;
248}
249if (!p.pm_vers)
250 p.pm_vers = MOUNTVERS;
251if (!p.pm_port)
252 p.pm_port = MOUNTPORT;
253if (!p.pm_prot)
254 p.pm_prot = IPPROTO_TCP;
255return &p;
256}
257
258int nfsmount(const char *spec, const char *node, int *flags,
259 char **extra_opts, char **mount_opts, int running_bg)
260{
261 static char *prev_bg_host;
262 char hostdir[1024];
263 CLIENT *mclient;
264 char *hostname;
265 char *pathname;
266 char *old_opts;
267 char *mounthost=NULL;
268 char new_opts[1024];
269 struct timeval total_timeout;
270 enum clnt_stat clnt_stat;
271 static struct nfs_mount_data data;
272 char *opt, *opteq;
273 int val;
274 struct hostent *hp;
275 struct sockaddr_in server_addr;
276 struct sockaddr_in mount_server_addr;
277 struct pmap* pm_mnt;
278 int msock, fsock;
279 struct timeval retry_timeout;
280 union {
281 struct fhstatus nfsv2;
282 struct mountres3 nfsv3;
283 } status;
284 struct stat statbuf;
285 char *s;
286 int port;
287 int mountport;
288 int proto;
289 int bg;
290 int soft;
291 int intr;
292 int posix;
293 int nocto;
294 int noac;
295 int nolock;
296 int retry;
297 int tcp;
298 int mountprog;
299 int mountvers;
300 int nfsprog;
301 int nfsvers;
302 int retval;
303 time_t t;
304 time_t prevt;
305 time_t timeout;
306
307 find_kernel_nfs_mount_version();
308
309 retval = EX_FAIL;
310 msock = fsock = -1;
311 mclient = NULL;
312 if (strlen(spec) >= sizeof(hostdir)) {
313 error_msg("excessively long host:dir argument");
314 goto fail;
315 }
316 strcpy(hostdir, spec);
317 if ((s = strchr(hostdir, ':'))) {
318 hostname = hostdir;
319 pathname = s + 1;
320 *s = '\0';
321 /* Ignore all but first hostname in replicated mounts
322 until they can be fully supported. (mack@sgi.com) */
323 if ((s = strchr(hostdir, ','))) {
324 *s = '\0';
325 error_msg("warning: multiple hostnames not supported");
326 }
327 } else {
328 error_msg("directory to mount not in host:dir format");
329 goto fail;
330 }
331
332 server_addr.sin_family = AF_INET;
333#ifdef HAVE_inet_aton
334 if (!inet_aton(hostname, &server_addr.sin_addr))
335#endif
336 {
337 if ((hp = gethostbyname(hostname)) == NULL) {
338 herror_msg("%s", hostname);
339 goto fail;
340 } else {
341 if (hp->h_length > sizeof(struct in_addr)) {
342 error_msg("got bad hp->h_length");
343 hp->h_length = sizeof(struct in_addr);
344 }
345 memcpy(&server_addr.sin_addr,
346 hp->h_addr, hp->h_length);
347 }
348 }
349
350 memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
351
352 /* add IP address to mtab options for use when unmounting */
353
354 s = inet_ntoa(server_addr.sin_addr);
355 old_opts = *extra_opts;
356 if (!old_opts)
357 old_opts = "";
358 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
359 error_msg("excessively long option argument");
360 goto fail;
361 }
362 sprintf(new_opts, "%s%saddr=%s",
363 old_opts, *old_opts ? "," : "", s);
364 *extra_opts = xstrdup(new_opts);
365
366 /* Set default options.
367 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
368 * let the kernel decide.
369 * timeo is filled in after we know whether it'll be TCP or UDP. */
370 memset(&data, 0, sizeof(data));
371 data.retrans = 3;
372 data.acregmin = 3;
373 data.acregmax = 60;
374 data.acdirmin = 30;
375 data.acdirmax = 60;
376#if NFS_MOUNT_VERSION >= 2
377 data.namlen = NAME_MAX;
378#endif
379
380 bg = 0;
381 soft = 0;
382 intr = 0;
383 posix = 0;
384 nocto = 0;
385 nolock = 0;
386 noac = 0;
387 retry = 10000; /* 10000 minutes ~ 1 week */
388 tcp = 0;
389
390 mountprog = MOUNTPROG;
391 mountvers = 0;
392 port = 0;
393 mountport = 0;
394 nfsprog = NFS_PROGRAM;
395 nfsvers = 0;
396
397 /* parse options */
398
399 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
400 if ((opteq = strchr(opt, '='))) {
401 val = atoi(opteq + 1);
402 *opteq = '\0';
403 if (!strcmp(opt, "rsize"))
404 data.rsize = val;
405 else if (!strcmp(opt, "wsize"))
406 data.wsize = val;
407 else if (!strcmp(opt, "timeo"))
408 data.timeo = val;
409 else if (!strcmp(opt, "retrans"))
410 data.retrans = val;
411 else if (!strcmp(opt, "acregmin"))
412 data.acregmin = val;
413 else if (!strcmp(opt, "acregmax"))
414 data.acregmax = val;
415 else if (!strcmp(opt, "acdirmin"))
416 data.acdirmin = val;
417 else if (!strcmp(opt, "acdirmax"))
418 data.acdirmax = val;
419 else if (!strcmp(opt, "actimeo")) {
420 data.acregmin = val;
421 data.acregmax = val;
422 data.acdirmin = val;
423 data.acdirmax = val;
424 }
425 else if (!strcmp(opt, "retry"))
426 retry = val;
427 else if (!strcmp(opt, "port"))
428 port = val;
429 else if (!strcmp(opt, "mountport"))
430 mountport = val;
431 else if (!strcmp(opt, "mounthost"))
432 mounthost=xstrndup(opteq+1,
433 strcspn(opteq+1," \t\n\r,"));
434 else if (!strcmp(opt, "mountprog"))
435 mountprog = val;
436 else if (!strcmp(opt, "mountvers"))
437 mountvers = val;
438 else if (!strcmp(opt, "nfsprog"))
439 nfsprog = val;
440 else if (!strcmp(opt, "nfsvers") ||
441 !strcmp(opt, "vers"))
442 nfsvers = val;
443 else if (!strcmp(opt, "proto")) {
444 if (!strncmp(opteq+1, "tcp", 3))
445 tcp = 1;
446 else if (!strncmp(opteq+1, "udp", 3))
447 tcp = 0;
448 else
449 printf(_("Warning: Unrecognized proto= option.\n"));
450 } else if (!strcmp(opt, "namlen")) {
451#if NFS_MOUNT_VERSION >= 2
452 if (nfs_mount_version >= 2)
453 data.namlen = val;
454 else
455#endif
456 printf(_("Warning: Option namlen is not supported.\n"));
457 } else if (!strcmp(opt, "addr"))
458 /* ignore */;
459 else {
460 printf(_("unknown nfs mount parameter: "
461 "%s=%d\n"), opt, val);
462 goto fail;
463 }
464 }
465 else {
466 val = 1;
467 if (!strncmp(opt, "no", 2)) {
468 val = 0;
469 opt += 2;
470 }
471 if (!strcmp(opt, "bg"))
472 bg = val;
473 else if (!strcmp(opt, "fg"))
474 bg = !val;
475 else if (!strcmp(opt, "soft"))
476 soft = val;
477 else if (!strcmp(opt, "hard"))
478 soft = !val;
479 else if (!strcmp(opt, "intr"))
480 intr = val;
481 else if (!strcmp(opt, "posix"))
482 posix = val;
483 else if (!strcmp(opt, "cto"))
484 nocto = !val;
485 else if (!strcmp(opt, "ac"))
486 noac = !val;
487 else if (!strcmp(opt, "tcp"))
488 tcp = val;
489 else if (!strcmp(opt, "udp"))
490 tcp = !val;
491 else if (!strcmp(opt, "lock")) {
492 if (nfs_mount_version >= 3)
493 nolock = !val;
494 else
495 printf(_("Warning: option nolock is not supported.\n"));
496 } else {
497 printf(_("unknown nfs mount option: "
498 "%s%s\n"), val ? "" : "no", opt);
499 goto fail;
500 }
501 }
502 }
503 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
504
505 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
506 | (intr ? NFS_MOUNT_INTR : 0)
507 | (posix ? NFS_MOUNT_POSIX : 0)
508 | (nocto ? NFS_MOUNT_NOCTO : 0)
509 | (noac ? NFS_MOUNT_NOAC : 0);
510#if NFS_MOUNT_VERSION >= 2
511 if (nfs_mount_version >= 2)
512 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
513#endif
514#if NFS_MOUNT_VERSION >= 3
515 if (nfs_mount_version >= 3)
516 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
517#endif
518 if (nfsvers > MAX_NFSPROT) {
519 error_msg("NFSv%d not supported!", nfsvers);
520 return 0;
521 }
522 if (mountvers > MAX_NFSPROT) {
523 error_msg("NFSv%d not supported!", nfsvers);
524 return 0;
525 }
526 if (nfsvers && !mountvers)
527 mountvers = (nfsvers < 3) ? 1 : nfsvers;
528 if (nfsvers && nfsvers < mountvers) {
529 mountvers = nfsvers;
530 }
531
532 /* Adjust options if none specified */
533 if (!data.timeo)
534 data.timeo = tcp ? 70 : 7;
535
536#ifdef NFS_MOUNT_DEBUG
537 printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
538 data.rsize, data.wsize, data.timeo, data.retrans);
539 printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
540 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
541 printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
542 port, bg, retry, data.flags);
543 printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
544 mountprog, mountvers, nfsprog, nfsvers);
545 printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
546 (data.flags & NFS_MOUNT_SOFT) != 0,
547 (data.flags & NFS_MOUNT_INTR) != 0,
548 (data.flags & NFS_MOUNT_POSIX) != 0,
549 (data.flags & NFS_MOUNT_NOCTO) != 0,
550 (data.flags & NFS_MOUNT_NOAC) != 0);
551#if NFS_MOUNT_VERSION >= 2
552 printf("tcp = %d\n",
553 (data.flags & NFS_MOUNT_TCP) != 0);
554#endif
555#endif
556
557 data.version = nfs_mount_version;
558 *mount_opts = (char *) &data;
559
560 if (*flags & MS_REMOUNT)
561 return 0;
562
563 /*
564 * If the previous mount operation on the same host was
565 * backgrounded, and the "bg" for this mount is also set,
566 * give up immediately, to avoid the initial timeout.
567 */
568 if (bg && !running_bg &&
569 prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
570 if (retry > 0)
571 retval = EX_BG;
572 return retval;
573 }
574
575 /* create mount deamon client */
576 /* See if the nfs host = mount host. */
577 if (mounthost) {
578 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
579 mount_server_addr.sin_family = AF_INET;
580 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
581 } else {
582 if ((hp = gethostbyname(mounthost)) == NULL) {
583 herror_msg("%s", mounthost);
584 goto fail;
585 } else {
586 if (hp->h_length > sizeof(struct in_addr)) {
587 error_msg("got bad hp->h_length?");
588 hp->h_length = sizeof(struct in_addr);
589 }
590 mount_server_addr.sin_family = AF_INET;
591 memcpy(&mount_server_addr.sin_addr,
592 hp->h_addr, hp->h_length);
593 }
594 }
595 }
596
597 /*
598 * The following loop implements the mount retries. On the first
599 * call, "running_bg" is 0. When the mount times out, and the
600 * "bg" option is set, the exit status EX_BG will be returned.
601 * For a backgrounded mount, there will be a second call by the
602 * child process with "running_bg" set to 1.
603 *
604 * The case where the mount point is not present and the "bg"
605 * option is set, is treated as a timeout. This is done to
606 * support nested mounts.
607 *
608 * The "retry" count specified by the user is the number of
609 * minutes to retry before giving up.
610 *
611 * Only the first error message will be displayed.
612 */
613 retry_timeout.tv_sec = 3;
614 retry_timeout.tv_usec = 0;
615 total_timeout.tv_sec = 20;
616 total_timeout.tv_usec = 0;
617 timeout = time(NULL) + 60 * retry;
618 prevt = 0;
619 t = 30;
620 val = 1;
621 for (;;) {
622 if (bg && stat(node, &statbuf) == -1) {
623 if (running_bg) {
624 sleep(val); /* 1, 2, 4, 8, 16, 30, ... */
625 val *= 2;
626 if (val > 30)
627 val = 30;
628 }
629 } else {
630 /* be careful not to use too many CPU cycles */
631 if (t - prevt < 30)
632 sleep(30);
633
634 pm_mnt = get_mountport(&mount_server_addr,
635 mountprog,
636 mountvers,
637 proto,
638 mountport);
639
640 /* contact the mount daemon via TCP */
641 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
642 msock = RPC_ANYSOCK;
643
644 switch (pm_mnt->pm_prot) {
645 case IPPROTO_UDP:
646 mclient = clntudp_create(&mount_server_addr,
647 pm_mnt->pm_prog,
648 pm_mnt->pm_vers,
649 retry_timeout,
650 &msock);
651 if (mclient)
652 break;
653 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
654 msock = RPC_ANYSOCK;
655 case IPPROTO_TCP:
656 mclient = clnttcp_create(&mount_server_addr,
657 pm_mnt->pm_prog,
658 pm_mnt->pm_vers,
659 &msock, 0, 0);
660 break;
661 default:
662 mclient = 0;
663 }
664 if (mclient) {
665 /* try to mount hostname:pathname */
666 mclient->cl_auth = authunix_create_default();
667
668 /* make pointers in xdr_mountres3 NULL so
669 * that xdr_array allocates memory for us
670 */
671 memset(&status, 0, sizeof(status));
672
673 if (pm_mnt->pm_vers == 3)
674 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
675 (xdrproc_t) xdr_dirpath,
676 (caddr_t) &pathname,
677 (xdrproc_t) xdr_mountres3,
678 (caddr_t) &status,
679 total_timeout);
680 else
681 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
682 (xdrproc_t) xdr_dirpath,
683 (caddr_t) &pathname,
684 (xdrproc_t) xdr_fhstatus,
685 (caddr_t) &status,
686 total_timeout);
687
688 if (clnt_stat == RPC_SUCCESS)
689 break; /* we're done */
690 if (errno != ECONNREFUSED) {
691 clnt_perror(mclient, "mount");
692 goto fail; /* don't retry */
693 }
694 if (!running_bg && prevt == 0)
695 clnt_perror(mclient, "mount");
696 auth_destroy(mclient->cl_auth);
697 clnt_destroy(mclient);
698 mclient = 0;
699 close(msock);
700 } else {
701 if (!running_bg && prevt == 0)
702 clnt_pcreateerror("mount");
703 }
704 prevt = t;
705 }
706 if (!bg)
707 goto fail;
708 if (!running_bg) {
709 prev_bg_host = xstrdup(hostname);
710 if (retry > 0)
711 retval = EX_BG;
712 goto fail;
713 }
714 t = time(NULL);
715 if (t >= timeout)
716 goto fail;
717 }
718 nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
719
720 if (nfsvers == 2) {
721 if (status.nfsv2.fhs_status != 0) {
722 error_msg("%s:%s failed, reason given by server: %s",
723 hostname, pathname,
724 nfs_strerror(status.nfsv2.fhs_status));
725 goto fail;
726 }
727 memcpy(data.root.data,
728 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
729 NFS_FHSIZE);
730#if NFS_MOUNT_VERSION >= 4
731 data.root.size = NFS_FHSIZE;
732 memcpy(data.old_root.data,
733 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
734 NFS_FHSIZE);
735#endif
736 } else {
737#if NFS_MOUNT_VERSION >= 4
738 fhandle3 *my_fhandle;
739 if (status.nfsv3.fhs_status != 0) {
740 error_msg("%s:%s failed, reason given by server: %s",
741 hostname, pathname,
742 nfs_strerror(status.nfsv3.fhs_status));
743 goto fail;
744 }
745 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
746 memset(data.old_root.data, 0, NFS_FHSIZE);
747 memset(&data.root, 0, sizeof(data.root));
748 data.root.size = my_fhandle->fhandle3_len;
749 memcpy(data.root.data,
750 (char *) my_fhandle->fhandle3_val,
751 my_fhandle->fhandle3_len);
752
753 data.flags |= NFS_MOUNT_VER3;
754#endif
755 }
756
757 /* create nfs socket for kernel */
758
759 if (tcp) {
760 if (nfs_mount_version < 3) {
761 printf(_("NFS over TCP is not supported.\n"));
762 goto fail;
763 }
764 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
765 } else
766 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
767 if (fsock < 0) {
768 perror(_("nfs socket"));
769 goto fail;
770 }
771 if (bindresvport(fsock, 0) < 0) {
772 perror(_("nfs bindresvport"));
773 goto fail;
774 }
775 if (port == 0) {
776 server_addr.sin_port = PMAPPORT;
777 port = pmap_getport(&server_addr, nfsprog, nfsvers,
778 tcp ? IPPROTO_TCP : IPPROTO_UDP);
779 if (port == 0)
780 port = NFS_PORT;
781#ifdef NFS_MOUNT_DEBUG
782 else
783 printf(_("used portmapper to find NFS port\n"));
784#endif
785 }
786#ifdef NFS_MOUNT_DEBUG
787 printf(_("using port %d for nfs deamon\n"), port);
788#endif
789 server_addr.sin_port = htons(port);
790 /*
791 * connect() the socket for kernels 1.3.10 and below only,
792 * to avoid problems with multihomed hosts.
793 * --Swen
794 */
795 if (get_kernel_revision() <= 66314
796 && connect(fsock, (struct sockaddr *) &server_addr,
797 sizeof (server_addr)) < 0) {
798 perror(_("nfs connect"));
799 goto fail;
800 }
801
802 /* prepare data structure for kernel */
803
804 data.fd = fsock;
805 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
806 strncpy(data.hostname, hostname, sizeof(data.hostname));
807
808 /* clean up */
809
810 auth_destroy(mclient->cl_auth);
811 clnt_destroy(mclient);
812 close(msock);
813 return 0;
814
815 /* abort */
816
817fail:
818 if (msock != -1) {
819 if (mclient) {
820 auth_destroy(mclient->cl_auth);
821 clnt_destroy(mclient);
822 }
823 close(msock);
824 }
825 if (fsock != -1)
826 close(fsock);
827 return retval;
828}
829
830/*
831 * We need to translate between nfs status return values and
832 * the local errno values which may not be the same.
833 *
834 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
835 * "after #include <errno.h> the symbol errno is reserved for any use,
836 * it cannot even be used as a struct tag or field name".
837 */
838
839#ifndef EDQUOT
840#define EDQUOT ENOSPC
841#endif
842
843static struct {
844 enum nfs_stat stat;
845 int errnum;
846} nfs_errtbl[] = {
847 { NFS_OK, 0 },
848 { NFSERR_PERM, EPERM },
849 { NFSERR_NOENT, ENOENT },
850 { NFSERR_IO, EIO },
851 { NFSERR_NXIO, ENXIO },
852 { NFSERR_ACCES, EACCES },
853 { NFSERR_EXIST, EEXIST },
854 { NFSERR_NODEV, ENODEV },
855 { NFSERR_NOTDIR, ENOTDIR },
856 { NFSERR_ISDIR, EISDIR },
857#ifdef NFSERR_INVAL
858 { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
859#endif
860 { NFSERR_FBIG, EFBIG },
861 { NFSERR_NOSPC, ENOSPC },
862 { NFSERR_ROFS, EROFS },
863 { NFSERR_NAMETOOLONG, ENAMETOOLONG },
864 { NFSERR_NOTEMPTY, ENOTEMPTY },
865 { NFSERR_DQUOT, EDQUOT },
866 { NFSERR_STALE, ESTALE },
867#ifdef EWFLUSH
868 { NFSERR_WFLUSH, EWFLUSH },
869#endif
870 /* Throw in some NFSv3 values for even more fun (HP returns these) */
871 { 71, EREMOTE },
872
873 { -1, EIO }
874};
875
876static char *nfs_strerror(int status)
877{
878 int i;
879 static char buf[256];
880
881 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
882 if (nfs_errtbl[i].stat == status)
883 return strerror(nfs_errtbl[i].errnum);
884 }
885 sprintf(buf, _("unknown nfs status return value: %d"), status);
886 return buf;
887}
888
889static bool_t
890xdr_fhandle (XDR *xdrs, fhandle objp)
891{
892 //register int32_t *buf;
893
894 if (!xdr_opaque (xdrs, objp, FHSIZE))
895 return FALSE;
896 return TRUE;
897}
898
899bool_t
900xdr_fhstatus (XDR *xdrs, fhstatus *objp)
901{
902 //register int32_t *buf;
903
904 if (!xdr_u_int (xdrs, &objp->fhs_status))
905 return FALSE;
906 switch (objp->fhs_status) {
907 case 0:
908 if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
909 return FALSE;
910 break;
911 default:
912 break;
913 }
914 return TRUE;
915}
916
917bool_t
918xdr_dirpath (XDR *xdrs, dirpath *objp)
919{
920 //register int32_t *buf;
921
922 if (!xdr_string (xdrs, objp, MNTPATHLEN))
923 return FALSE;
924 return TRUE;
925}
926
927bool_t
928xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
929{
930 //register int32_t *buf;
931
932 if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
933 return FALSE;
934 return TRUE;
935}
936
937bool_t
938xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
939{
940 //register int32_t *buf;
941
942 if (!xdr_fhandle3 (xdrs, &objp->fhandle))
943 return FALSE;
944 if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0,
945 sizeof (int), (xdrproc_t) xdr_int))
946 return FALSE;
947 return TRUE;
948}
949
950bool_t
951xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
952{
953 //register int32_t *buf;
954
955 if (!xdr_enum (xdrs, (enum_t *) objp))
956 return FALSE;
957 return TRUE;
958}
959
960bool_t
961xdr_mountres3 (XDR *xdrs, mountres3 *objp)
962{
963 //register int32_t *buf;
964
965 if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
966 return FALSE;
967 switch (objp->fhs_status) {
968 case MNT_OK:
969 if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))
970 return FALSE;
971 break;
972 default:
973 break;
974 }
975 return TRUE;
976}
977
diff --git a/nfsmount.h b/nfsmount.h
deleted file mode 100644
index b3d5a51e6..000000000
--- a/nfsmount.h
+++ /dev/null
@@ -1,242 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * This file was originally generated using rpcgen.
4 * But now we edit it by hand as needed to make it
5 * shut up...
6 */
7
8#ifndef _NFSMOUNT_H_RPCGEN
9#define _NFSMOUNT_H_RPCGEN
10
11#include <rpc/rpc.h>
12
13
14#ifdef __cplusplus
15extern "C" {
16#endif
17
18/*
19 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
20 * unrestricted use provided that this legend is included on all tape
21 * media and as a part of the software program in whole or part. Users
22 * may copy or modify Sun RPC without charge, but are not authorized
23 * to license or distribute it to anyone else except as part of a product or
24 * program developed by the user or with the express written consent of
25 * Sun Microsystems, Inc.
26 *
27 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
28 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
30 *
31 * Sun RPC is provided with no support and without any obligation on the
32 * part of Sun Microsystems, Inc. to assist in its use, correction,
33 * modification or enhancement.
34 *
35 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
36 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
37 * OR ANY PART THEREOF.
38 *
39 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
40 * or profits or other special, indirect and consequential damages, even if
41 * Sun has been advised of the possibility of such damages.
42 *
43 * Sun Microsystems, Inc.
44 * 2550 Garcia Avenue
45 * Mountain View, California 94043
46 */
47/*
48 * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
49 */
50
51/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */
52#ifndef _rpcsvc_mount_h
53#define _rpcsvc_mount_h
54#include <asm/types.h>
55#define MOUNTPORT 635
56#define MNTPATHLEN 1024
57#define MNTNAMLEN 255
58#define FHSIZE 32
59#define FHSIZE3 64
60
61typedef char fhandle[FHSIZE];
62
63typedef struct {
64 u_int fhandle3_len;
65 char *fhandle3_val;
66} fhandle3;
67
68enum mountstat3 {
69 MNT_OK = 0,
70 MNT3ERR_PERM = 1,
71 MNT3ERR_NOENT = 2,
72 MNT3ERR_IO = 5,
73 MNT3ERR_ACCES = 13,
74 MNT3ERR_NOTDIR = 20,
75 MNT3ERR_INVAL = 22,
76 MNT3ERR_NAMETOOLONG = 63,
77 MNT3ERR_NOTSUPP = 10004,
78 MNT3ERR_SERVERFAULT = 10006,
79};
80typedef enum mountstat3 mountstat3;
81
82struct fhstatus {
83 u_int fhs_status;
84 union {
85 fhandle fhs_fhandle;
86 } fhstatus_u;
87};
88typedef struct fhstatus fhstatus;
89
90struct mountres3_ok {
91 fhandle3 fhandle;
92 struct {
93 u_int auth_flavours_len;
94 int *auth_flavours_val;
95 } auth_flavours;
96};
97typedef struct mountres3_ok mountres3_ok;
98
99struct mountres3 {
100 mountstat3 fhs_status;
101 union {
102 mountres3_ok mountinfo;
103 } mountres3_u;
104};
105typedef struct mountres3 mountres3;
106
107typedef char *dirpath;
108
109typedef char *name;
110
111typedef struct mountbody *mountlist;
112
113struct mountbody {
114 name ml_hostname;
115 dirpath ml_directory;
116 mountlist ml_next;
117};
118typedef struct mountbody mountbody;
119
120typedef struct groupnode *groups;
121
122struct groupnode {
123 name gr_name;
124 groups gr_next;
125};
126typedef struct groupnode groupnode;
127
128typedef struct exportnode *exports;
129
130struct exportnode {
131 dirpath ex_dir;
132 groups ex_groups;
133 exports ex_next;
134};
135typedef struct exportnode exportnode;
136
137struct ppathcnf {
138 int pc_link_max;
139 short pc_max_canon;
140 short pc_max_input;
141 short pc_name_max;
142 short pc_path_max;
143 short pc_pipe_buf;
144 u_char pc_vdisable;
145 char pc_xxx;
146 short pc_mask[2];
147};
148typedef struct ppathcnf ppathcnf;
149#endif /*!_rpcsvc_mount_h*/
150
151#define MOUNTPROG 100005
152#define MOUNTVERS 1
153
154#define MOUNTPROC_NULL 0
155extern void * mountproc_null_1(void *, CLIENT *);
156extern void * mountproc_null_1_svc(void *, struct svc_req *);
157#define MOUNTPROC_MNT 1
158extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
159extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
160#define MOUNTPROC_DUMP 2
161extern mountlist * mountproc_dump_1(void *, CLIENT *);
162extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
163#define MOUNTPROC_UMNT 3
164extern void * mountproc_umnt_1(dirpath *, CLIENT *);
165extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
166#define MOUNTPROC_UMNTALL 4
167extern void * mountproc_umntall_1(void *, CLIENT *);
168extern void * mountproc_umntall_1_svc(void *, struct svc_req *);
169#define MOUNTPROC_EXPORT 5
170extern exports * mountproc_export_1(void *, CLIENT *);
171extern exports * mountproc_export_1_svc(void *, struct svc_req *);
172#define MOUNTPROC_EXPORTALL 6
173extern exports * mountproc_exportall_1(void *, CLIENT *);
174extern exports * mountproc_exportall_1_svc(void *, struct svc_req *);
175extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
176
177#define MOUNTVERS_POSIX 2
178
179extern void * mountproc_null_2(void *, CLIENT *);
180extern void * mountproc_null_2_svc(void *, struct svc_req *);
181extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *);
182extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *);
183extern mountlist * mountproc_dump_2(void *, CLIENT *);
184extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *);
185extern void * mountproc_umnt_2(dirpath *, CLIENT *);
186extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *);
187extern void * mountproc_umntall_2(void *, CLIENT *);
188extern void * mountproc_umntall_2_svc(void *, struct svc_req *);
189extern exports * mountproc_export_2(void *, CLIENT *);
190extern exports * mountproc_export_2_svc(void *, struct svc_req *);
191extern exports * mountproc_exportall_2(void *, CLIENT *);
192extern exports * mountproc_exportall_2_svc(void *, struct svc_req *);
193#define MOUNTPROC_PATHCONF 7
194extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *);
195extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *);
196extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
197
198#define MOUNT_V3 3
199
200#define MOUNTPROC3_NULL 0
201extern void * mountproc3_null_3(void *, CLIENT *);
202extern void * mountproc3_null_3_svc(void *, struct svc_req *);
203#define MOUNTPROC3_MNT 1
204extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *);
205extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *);
206#define MOUNTPROC3_DUMP 2
207extern mountlist * mountproc3_dump_3(void *, CLIENT *);
208extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *);
209#define MOUNTPROC3_UMNT 3
210extern void * mountproc3_umnt_3(dirpath *, CLIENT *);
211extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *);
212#define MOUNTPROC3_UMNTALL 4
213extern void * mountproc3_umntall_3(void *, CLIENT *);
214extern void * mountproc3_umntall_3_svc(void *, struct svc_req *);
215#define MOUNTPROC3_EXPORT 5
216extern exports * mountproc3_export_3(void *, CLIENT *);
217extern exports * mountproc3_export_3_svc(void *, struct svc_req *);
218extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
219
220/* the xdr functions */
221
222static bool_t xdr_fhandle (XDR *, fhandle);
223extern bool_t xdr_fhandle3 (XDR *, fhandle3*);
224extern bool_t xdr_mountstat3 (XDR *, mountstat3*);
225extern bool_t xdr_fhstatus (XDR *, fhstatus*);
226extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
227extern bool_t xdr_mountres3 (XDR *, mountres3*);
228extern bool_t xdr_dirpath (XDR *, dirpath*);
229extern bool_t xdr_name (XDR *, name*);
230extern bool_t xdr_mountlist (XDR *, mountlist*);
231extern bool_t xdr_mountbody (XDR *, mountbody*);
232extern bool_t xdr_groups (XDR *, groups*);
233extern bool_t xdr_groupnode (XDR *, groupnode*);
234extern bool_t xdr_exports (XDR *, exports*);
235extern bool_t xdr_exportnode (XDR *, exportnode*);
236extern bool_t xdr_ppathcnf (XDR *, ppathcnf*);
237
238#ifdef __cplusplus
239}
240#endif
241
242#endif /* !_NFSMOUNT_H_RPCGEN */
diff --git a/nslookup.c b/nslookup.c
deleted file mode 100644
index 3e32ca9c0..000000000
--- a/nslookup.c
+++ /dev/null
@@ -1,183 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini nslookup implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by John Beppu <beppu@lineo.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <ctype.h>
25#include <errno.h>
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29
30#include <netdb.h>
31#include <sys/socket.h>
32#include <sys/types.h>
33#include <netinet/in.h>
34#include <resolv.h>
35#include <arpa/inet.h>
36#include "busybox.h"
37
38/*
39 | I'm only implementing non-interactive mode;
40 | I totally forgot nslookup even had an interactive mode.
41 |
42 | [ TODO ]
43 | + find out how to use non-default name servers
44 */
45
46/* only works for IPv4 */
47static int addr_fprint(char *addr)
48{
49 u_int8_t split[4];
50 u_int32_t ip;
51 u_int32_t *x = (u_int32_t *) addr;
52
53 ip = ntohl(*x);
54 split[0] = (ip & 0xff000000) >> 24;
55 split[1] = (ip & 0x00ff0000) >> 16;
56 split[2] = (ip & 0x0000ff00) >> 8;
57 split[3] = (ip & 0x000000ff);
58 printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]);
59 return 0;
60}
61
62/* takes the NULL-terminated array h_addr_list, and
63 * prints its contents appropriately
64 */
65static int addr_list_fprint(char **h_addr_list)
66{
67 int i, j;
68 char *addr_string = (h_addr_list[1])
69 ? "Addresses: " : "Address: ";
70
71 printf("%s ", addr_string);
72 for (i = 0, j = 0; h_addr_list[i]; i++, j++) {
73 addr_fprint(h_addr_list[i]);
74
75 /* real nslookup does this */
76 if (j == 4) {
77 if (h_addr_list[i + 1]) {
78 printf("\n ");
79 }
80 j = 0;
81 } else {
82 if (h_addr_list[i + 1]) {
83 printf(", ");
84 }
85 }
86
87 }
88 printf("\n");
89 return 0;
90}
91
92/* print the results as nslookup would */
93static struct hostent *hostent_fprint(struct hostent *host)
94{
95 if (host) {
96 printf("Name: %s\n", host->h_name);
97 addr_list_fprint(host->h_addr_list);
98 } else {
99 printf("*** Unknown host\n");
100 }
101 return host;
102}
103
104/* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+
105 * into a u_int32_t
106 */
107static u_int32_t str_to_addr(const char *addr)
108{
109 u_int32_t split[4];
110 u_int32_t ip;
111
112 sscanf(addr, "%d.%d.%d.%d",
113 &split[0], &split[1], &split[2], &split[3]);
114
115 /* assuming sscanf worked */
116 ip = (split[0] << 24) |
117 (split[1] << 16) | (split[2] << 8) | (split[3]);
118
119 return htonl(ip);
120}
121
122/* gethostbyaddr wrapper */
123static struct hostent *gethostbyaddr_wrapper(const char *address)
124{
125 struct in_addr addr;
126
127 addr.s_addr = str_to_addr(address);
128 return gethostbyaddr((char *) &addr, 4, AF_INET); /* IPv4 only for now */
129}
130
131#ifdef __UCLIBC__
132#warning FIXME after fixing uClibc to define struct _res
133static inline void server_print(void)
134{
135 printf("Server: %s\n", "default");
136 printf("Address: %s\n\n", "default");
137}
138#else
139/* lookup the default nameserver and display it */
140static inline void server_print(void)
141{
142 struct sockaddr_in def = _res.nsaddr_list[0];
143 char *ip = inet_ntoa(def.sin_addr);
144
145 hostent_fprint(gethostbyaddr_wrapper(ip));
146 printf("\n");
147}
148#endif
149
150/* naive function to check whether char *s is an ip address */
151static int is_ip_address(const char *s)
152{
153 while (*s) {
154 if ((isdigit(*s)) || (*s == '.')) {
155 s++;
156 continue;
157 }
158 return 0;
159 }
160 return 1;
161}
162
163/* ________________________________________________________________________ */
164int nslookup_main(int argc, char **argv)
165{
166 struct hostent *host;
167
168 if (argc < 2 || *argv[1]=='-') {
169 show_usage();
170 }
171
172 res_init();
173 server_print();
174 if (is_ip_address(argv[1])) {
175 host = gethostbyaddr_wrapper(argv[1]);
176 } else {
177 host = xgethostbyname(argv[1]);
178 }
179 hostent_fprint(host);
180 return EXIT_SUCCESS;
181}
182
183/* $Id: nslookup.c,v 1.25 2001/10/01 17:50:25 kraai Exp $ */
diff --git a/pidof.c b/pidof.c
deleted file mode 100644
index 50dffd387..000000000
--- a/pidof.c
+++ /dev/null
@@ -1,79 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * pidof implementation for busybox
4 *
5 * Copyright (C) 2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <errno.h>
28#include <unistd.h>
29#include <signal.h>
30#include <ctype.h>
31#include <string.h>
32#include <unistd.h>
33#include "busybox.h"
34
35
36extern int pidof_main(int argc, char **argv)
37{
38 int opt;
39
40
41 /* do normal option parsing */
42 while ((opt = getopt(argc, argv, "ne:f:")) > 0) {
43 switch (opt) {
44#if 0
45 case 'g':
46 break;
47 case 'e':
48 break;
49#endif
50 default:
51 show_usage();
52 }
53 }
54
55 /* if we didn't get a process name, then we need to choke and die here */
56 if (argv[optind] == NULL)
57 show_usage();
58
59 /* Looks like everything is set to go. */
60 while(optind < argc) {
61 pid_t* pidList;
62
63 pidList = find_pid_by_name( argv[optind]);
64 if (!pidList || *pidList<=0) {
65 break;
66 }
67
68 for(; pidList && *pidList!=0; pidList++) {
69 printf("%ld ", (long)*pidList);
70 }
71 /* Note that we don't bother to free the memory
72 * allocated in find_pid_by_name(). It will be freed
73 * upon exit, so we can save a byte or two */
74 optind++;
75 }
76 printf("\n");
77
78 return EXIT_SUCCESS;
79}
diff --git a/ping.c b/ping.c
deleted file mode 100644
index 5ca5dd9e0..000000000
--- a/ping.c
+++ /dev/null
@@ -1,555 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * $Id: ping.c,v 1.46 2001/07/17 01:12:36 andersen Exp $
4 * Mini ping implementation for busybox
5 *
6 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * This version of ping is adapted from the ping in netkit-base 0.10,
23 * which is:
24 *
25 * Copyright (c) 1989 The Regents of the University of California.
26 * All rights reserved.
27 *
28 * This code is derived from software contributed to Berkeley by
29 * Mike Muuss.
30 *
31 * Original copyright notice is retained at the end of this file.
32 */
33
34#include <sys/param.h>
35#include <sys/socket.h>
36#include <sys/file.h>
37#include <sys/time.h>
38#include <sys/times.h>
39#include <sys/signal.h>
40
41#include <netinet/in.h>
42#include <netinet/ip.h>
43#include <netinet/ip_icmp.h>
44#include <arpa/inet.h>
45#include <netdb.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <errno.h>
49#include <unistd.h>
50#include <string.h>
51#include <stdlib.h>
52#include "busybox.h"
53
54
55/* It turns out that libc5 doesn't have proper icmp support
56 * built into it header files, so we have to supplement it */
57#if __GNU_LIBRARY__ < 5
58static const int ICMP_MINLEN = 8; /* abs minimum */
59
60struct icmp_ra_addr
61{
62 u_int32_t ira_addr;
63 u_int32_t ira_preference;
64};
65
66
67struct icmp
68{
69 u_int8_t icmp_type; /* type of message, see below */
70 u_int8_t icmp_code; /* type sub code */
71 u_int16_t icmp_cksum; /* ones complement checksum of struct */
72 union
73 {
74 u_char ih_pptr; /* ICMP_PARAMPROB */
75 struct in_addr ih_gwaddr; /* gateway address */
76 struct ih_idseq /* echo datagram */
77 {
78 u_int16_t icd_id;
79 u_int16_t icd_seq;
80 } ih_idseq;
81 u_int32_t ih_void;
82
83 /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
84 struct ih_pmtu
85 {
86 u_int16_t ipm_void;
87 u_int16_t ipm_nextmtu;
88 } ih_pmtu;
89
90 struct ih_rtradv
91 {
92 u_int8_t irt_num_addrs;
93 u_int8_t irt_wpa;
94 u_int16_t irt_lifetime;
95 } ih_rtradv;
96 } icmp_hun;
97#define icmp_pptr icmp_hun.ih_pptr
98#define icmp_gwaddr icmp_hun.ih_gwaddr
99#define icmp_id icmp_hun.ih_idseq.icd_id
100#define icmp_seq icmp_hun.ih_idseq.icd_seq
101#define icmp_void icmp_hun.ih_void
102#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
103#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
104#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
105#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
106#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
107 union
108 {
109 struct
110 {
111 u_int32_t its_otime;
112 u_int32_t its_rtime;
113 u_int32_t its_ttime;
114 } id_ts;
115 struct
116 {
117 struct ip idi_ip;
118 /* options and then 64 bits of data */
119 } id_ip;
120 struct icmp_ra_addr id_radv;
121 u_int32_t id_mask;
122 u_int8_t id_data[1];
123 } icmp_dun;
124#define icmp_otime icmp_dun.id_ts.its_otime
125#define icmp_rtime icmp_dun.id_ts.its_rtime
126#define icmp_ttime icmp_dun.id_ts.its_ttime
127#define icmp_ip icmp_dun.id_ip.idi_ip
128#define icmp_radv icmp_dun.id_radv
129#define icmp_mask icmp_dun.id_mask
130#define icmp_data icmp_dun.id_data
131};
132#endif
133
134static const int DEFDATALEN = 56;
135static const int MAXIPLEN = 60;
136static const int MAXICMPLEN = 76;
137static const int MAXPACKET = 65468;
138#define MAX_DUP_CHK (8 * 128)
139static const int MAXWAIT = 10;
140static const int PINGINTERVAL = 1; /* second */
141
142#define O_QUIET (1 << 0)
143
144#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
145#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
146#define SET(bit) (A(bit) |= B(bit))
147#define CLR(bit) (A(bit) &= (~B(bit)))
148#define TST(bit) (A(bit) & B(bit))
149
150static void ping(const char *host);
151
152/* common routines */
153static int in_cksum(unsigned short *buf, int sz)
154{
155 int nleft = sz;
156 int sum = 0;
157 unsigned short *w = buf;
158 unsigned short ans = 0;
159
160 while (nleft > 1) {
161 sum += *w++;
162 nleft -= 2;
163 }
164
165 if (nleft == 1) {
166 *(unsigned char *) (&ans) = *(unsigned char *) w;
167 sum += ans;
168 }
169
170 sum = (sum >> 16) + (sum & 0xFFFF);
171 sum += (sum >> 16);
172 ans = ~sum;
173 return (ans);
174}
175
176/* simple version */
177#ifndef BB_FEATURE_FANCY_PING
178static char *hostname = NULL;
179
180static void noresp(int ign)
181{
182 printf("No response from %s\n", hostname);
183 exit(0);
184}
185
186static void ping(const char *host)
187{
188 struct hostent *h;
189 struct sockaddr_in pingaddr;
190 struct icmp *pkt;
191 int pingsock, c;
192 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
193
194 pingsock = create_icmp_socket();
195
196 memset(&pingaddr, 0, sizeof(struct sockaddr_in));
197
198 pingaddr.sin_family = AF_INET;
199 h = xgethostbyname(host);
200 memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
201 hostname = h->h_name;
202
203 pkt = (struct icmp *) packet;
204 memset(pkt, 0, sizeof(packet));
205 pkt->icmp_type = ICMP_ECHO;
206 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
207
208 c = sendto(pingsock, packet, sizeof(packet), 0,
209 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
210
211 if (c < 0 || c != sizeof(packet))
212 perror_msg_and_die("sendto");
213
214 signal(SIGALRM, noresp);
215 alarm(5); /* give the host 5000ms to respond */
216 /* listen for replies */
217 while (1) {
218 struct sockaddr_in from;
219 size_t fromlen = sizeof(from);
220
221 if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
222 (struct sockaddr *) &from, &fromlen)) < 0) {
223 if (errno == EINTR)
224 continue;
225 perror_msg("recvfrom");
226 continue;
227 }
228 if (c >= 76) { /* ip + icmp */
229 struct iphdr *iphdr = (struct iphdr *) packet;
230
231 pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */
232 if (pkt->icmp_type == ICMP_ECHOREPLY)
233 break;
234 }
235 }
236 printf("%s is alive!\n", hostname);
237 return;
238}
239
240extern int ping_main(int argc, char **argv)
241{
242 argc--;
243 argv++;
244 if (argc < 1)
245 show_usage();
246 ping(*argv);
247 return EXIT_SUCCESS;
248}
249
250#else /* ! BB_FEATURE_FANCY_PING */
251/* full(er) version */
252static char *hostname = NULL;
253static struct sockaddr_in pingaddr;
254static int pingsock = -1;
255static int datalen; /* intentionally uninitialized to work around gcc bug */
256
257static long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 0;
258static int myid = 0, options = 0;
259static unsigned long tmin = ULONG_MAX, tmax = 0, tsum = 0;
260static char rcvd_tbl[MAX_DUP_CHK / 8];
261
262static void sendping(int);
263static void pingstats(int);
264static void unpack(char *, int, struct sockaddr_in *);
265
266/**************************************************************************/
267
268static void pingstats(int junk)
269{
270 int status;
271
272 signal(SIGINT, SIG_IGN);
273
274 printf("\n--- %s ping statistics ---\n", hostname);
275 printf("%ld packets transmitted, ", ntransmitted);
276 printf("%ld packets received, ", nreceived);
277 if (nrepeats)
278 printf("%ld duplicates, ", nrepeats);
279 if (ntransmitted)
280 printf("%ld%% packet loss\n",
281 (ntransmitted - nreceived) * 100 / ntransmitted);
282 if (nreceived)
283 printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
284 tmin / 10, tmin % 10,
285 (tsum / (nreceived + nrepeats)) / 10,
286 (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
287 if (nreceived != 0)
288 status = EXIT_SUCCESS;
289 else
290 status = EXIT_FAILURE;
291 exit(status);
292}
293
294static void sendping(int junk)
295{
296 struct icmp *pkt;
297 int i;
298 char packet[datalen + 8];
299
300 pkt = (struct icmp *) packet;
301
302 pkt->icmp_type = ICMP_ECHO;
303 pkt->icmp_code = 0;
304 pkt->icmp_cksum = 0;
305 pkt->icmp_seq = ntransmitted++;
306 pkt->icmp_id = myid;
307 CLR(pkt->icmp_seq % MAX_DUP_CHK);
308
309 gettimeofday((struct timeval *) &packet[8], NULL);
310 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
311
312 i = sendto(pingsock, packet, sizeof(packet), 0,
313 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
314
315 if (i < 0)
316 perror_msg_and_die("sendto");
317 else if ((size_t)i != sizeof(packet))
318 error_msg_and_die("ping wrote %d chars; %d expected", i,
319 (int)sizeof(packet));
320
321 signal(SIGALRM, sendping);
322 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
323 alarm(PINGINTERVAL);
324 } else { /* done, wait for the last ping to come back */
325 /* todo, don't necessarily need to wait so long... */
326 signal(SIGALRM, pingstats);
327 alarm(MAXWAIT);
328 }
329}
330
331static char *icmp_type_name (int id)
332{
333 switch (id) {
334 case ICMP_ECHOREPLY: return "Echo Reply";
335 case ICMP_DEST_UNREACH: return "Destination Unreachable";
336 case ICMP_SOURCE_QUENCH: return "Source Quench";
337 case ICMP_REDIRECT: return "Redirect (change route)";
338 case ICMP_ECHO: return "Echo Request";
339 case ICMP_TIME_EXCEEDED: return "Time Exceeded";
340 case ICMP_PARAMETERPROB: return "Parameter Problem";
341 case ICMP_TIMESTAMP: return "Timestamp Request";
342 case ICMP_TIMESTAMPREPLY: return "Timestamp Reply";
343 case ICMP_INFO_REQUEST: return "Information Request";
344 case ICMP_INFO_REPLY: return "Information Reply";
345 case ICMP_ADDRESS: return "Address Mask Request";
346 case ICMP_ADDRESSREPLY: return "Address Mask Reply";
347 default: return "unknown ICMP type";
348 }
349}
350
351static void unpack(char *buf, int sz, struct sockaddr_in *from)
352{
353 struct icmp *icmppkt;
354 struct iphdr *iphdr;
355 struct timeval tv, *tp;
356 int hlen, dupflag;
357 unsigned long triptime;
358
359 gettimeofday(&tv, NULL);
360
361 /* check IP header */
362 iphdr = (struct iphdr *) buf;
363 hlen = iphdr->ihl << 2;
364 /* discard if too short */
365 if (sz < (datalen + ICMP_MINLEN))
366 return;
367
368 sz -= hlen;
369 icmppkt = (struct icmp *) (buf + hlen);
370
371 if (icmppkt->icmp_id != myid)
372 return; /* not our ping */
373
374 if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
375 ++nreceived;
376 tp = (struct timeval *) icmppkt->icmp_data;
377
378 if ((tv.tv_usec -= tp->tv_usec) < 0) {
379 --tv.tv_sec;
380 tv.tv_usec += 1000000;
381 }
382 tv.tv_sec -= tp->tv_sec;
383
384 triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
385 tsum += triptime;
386 if (triptime < tmin)
387 tmin = triptime;
388 if (triptime > tmax)
389 tmax = triptime;
390
391 if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) {
392 ++nrepeats;
393 --nreceived;
394 dupflag = 1;
395 } else {
396 SET(icmppkt->icmp_seq % MAX_DUP_CHK);
397 dupflag = 0;
398 }
399
400 if (options & O_QUIET)
401 return;
402
403 printf("%d bytes from %s: icmp_seq=%u", sz,
404 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
405 icmppkt->icmp_seq);
406 printf(" ttl=%d", iphdr->ttl);
407 printf(" time=%lu.%lu ms", triptime / 10, triptime % 10);
408 if (dupflag)
409 printf(" (DUP!)");
410 printf("\n");
411 } else
412 if (icmppkt->icmp_type != ICMP_ECHO)
413 error_msg("Warning: Got ICMP %d (%s)",
414 icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type));
415}
416
417static void ping(const char *host)
418{
419 struct hostent *h;
420 char buf[MAXHOSTNAMELEN];
421 char packet[datalen + MAXIPLEN + MAXICMPLEN];
422 int sockopt;
423
424 pingsock = create_icmp_socket();
425
426 memset(&pingaddr, 0, sizeof(struct sockaddr_in));
427
428 pingaddr.sin_family = AF_INET;
429 h = xgethostbyname(host);
430 if (h->h_addrtype != AF_INET)
431 error_msg_and_die("unknown address type; only AF_INET is currently supported.");
432
433 memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
434 strncpy(buf, h->h_name, sizeof(buf) - 1);
435 hostname = buf;
436
437 /* enable broadcast pings */
438 sockopt = 1;
439 setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt,
440 sizeof(sockopt));
441
442 /* set recv buf for broadcast pings */
443 sockopt = 48 * 1024;
444 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt,
445 sizeof(sockopt));
446
447 printf("PING %s (%s): %d data bytes\n",
448 hostname,
449 inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr),
450 datalen);
451
452 signal(SIGINT, pingstats);
453
454 /* start the ping's going ... */
455 sendping(0);
456
457 /* listen for replies */
458 while (1) {
459 struct sockaddr_in from;
460 socklen_t fromlen = (socklen_t) sizeof(from);
461 int c;
462
463 if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
464 (struct sockaddr *) &from, &fromlen)) < 0) {
465 if (errno == EINTR)
466 continue;
467 perror_msg("recvfrom");
468 continue;
469 }
470 unpack(packet, c, &from);
471 if (pingcount > 0 && nreceived >= pingcount)
472 break;
473 }
474 pingstats(0);
475}
476
477extern int ping_main(int argc, char **argv)
478{
479 char *thisarg;
480
481 datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
482
483 argc--;
484 argv++;
485 options = 0;
486 /* Parse any options */
487 while (argc >= 1 && **argv == '-') {
488 thisarg = *argv;
489 thisarg++;
490 switch (*thisarg) {
491 case 'q':
492 options |= O_QUIET;
493 break;
494 case 'c':
495 if (--argc <= 0)
496 show_usage();
497 argv++;
498 pingcount = atoi(*argv);
499 break;
500 case 's':
501 if (--argc <= 0)
502 show_usage();
503 argv++;
504 datalen = atoi(*argv);
505 break;
506 default:
507 show_usage();
508 }
509 argc--;
510 argv++;
511 }
512 if (argc < 1)
513 show_usage();
514
515 myid = getpid() & 0xFFFF;
516 ping(*argv);
517 return EXIT_SUCCESS;
518}
519#endif /* ! BB_FEATURE_FANCY_PING */
520
521/*
522 * Copyright (c) 1989 The Regents of the University of California.
523 * All rights reserved.
524 *
525 * This code is derived from software contributed to Berkeley by
526 * Mike Muuss.
527 *
528 * Redistribution and use in source and binary forms, with or without
529 * modification, are permitted provided that the following conditions
530 * are met:
531 * 1. Redistributions of source code must retain the above copyright
532 * notice, this list of conditions and the following disclaimer.
533 * 2. Redistributions in binary form must reproduce the above copyright
534 * notice, this list of conditions and the following disclaimer in the
535 * documentation and/or other materials provided with the distribution.
536 *
537 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
538 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
539 *
540 * 4. Neither the name of the University nor the names of its contributors
541 * may be used to endorse or promote products derived from this software
542 * without specific prior written permission.
543 *
544 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
545 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
546 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
547 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
548 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
549 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
550 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
551 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
552 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
553 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
554 * SUCH DAMAGE.
555 */
diff --git a/pivot_root.c b/pivot_root.c
deleted file mode 100644
index ba26b9c58..000000000
--- a/pivot_root.c
+++ /dev/null
@@ -1,35 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * pivot_root.c - Change root file system. Based on util-linux 2.10s
4 *
5 * busyboxed by Evin Robertson
6 * pivot_root syscall stubbed by Erik Andersen, so it will compile
7 * regardless of the kernel being used.
8 */
9#include <stdlib.h>
10#include <stdio.h>
11#include <errno.h>
12#include "busybox.h"
13
14extern int pivot_root(const char * new_root,const char * put_old);
15
16int pivot_root_main(int argc, char **argv)
17{
18 if (argc != 3)
19 show_usage();
20
21 if (pivot_root(argv[1],argv[2]) < 0)
22 perror_msg_and_die("pivot_root");
23
24 return EXIT_SUCCESS;
25
26}
27
28
29/*
30Local Variables:
31c-file-style: "linux"
32c-basic-offset: 4
33tab-width: 4
34End:
35*/
diff --git a/poweroff.c b/poweroff.c
deleted file mode 100644
index db20a4572..000000000
--- a/poweroff.c
+++ /dev/null
@@ -1,41 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini poweroff implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include "busybox.h"
25#include <signal.h>
26
27extern int poweroff_main(int argc, char **argv)
28{
29#ifdef BB_FEATURE_LINUXRC
30 /* don't assume init's pid == 1 */
31 pid_t *pid = find_pid_by_name("init");
32 if (!pid || *pid<=0) {
33 pid = find_pid_by_name("linuxrc");
34 if (!pid || *pid<=0)
35 error_msg_and_die("no process killed");
36 }
37 return(kill(*pid, SIGUSR2));
38#else
39 return(kill(1, SIGUSR2));
40#endif
41}
diff --git a/printf.c b/printf.c
deleted file mode 100644
index d579a9b4e..000000000
--- a/printf.c
+++ /dev/null
@@ -1,455 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/* printf - format and print data
3 Copyright (C) 90, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18
19/* Usage: printf format [argument...]
20
21 A front end to the printf function that lets it be used from the shell.
22
23 Backslash escapes:
24
25 \" = double quote
26 \\ = backslash
27 \a = alert (bell)
28 \b = backspace
29 \c = produce no further output
30 \f = form feed
31 \n = new line
32 \r = carriage return
33 \t = horizontal tab
34 \v = vertical tab
35 \0ooo = octal number (ooo is 0 to 3 digits)
36 \xhhh = hexadecimal number (hhh is 1 to 3 digits)
37
38 Additional directive:
39
40 %b = print an argument string, interpreting backslash escapes
41
42 The `format' argument is re-used as many times as necessary
43 to convert all of the given arguments.
44
45 David MacKenzie <djm@gnu.ai.mit.edu> */
46
47
48// 19990508 Busy Boxed! Dave Cinege
49
50#include <unistd.h>
51#include <stdio.h>
52#include <sys/types.h>
53#include <string.h>
54#include <errno.h>
55#include <stdlib.h>
56#include <fcntl.h>
57#include <ctype.h>
58#include "busybox.h"
59
60
61#ifndef S_IFMT
62static const int S_IFMT = 0170000;
63#endif
64#if !defined(S_ISBLK) && defined(S_IFBLK)
65# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
66#endif
67#if !defined(S_ISCHR) && defined(S_IFCHR)
68# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
69#endif
70#if !defined(S_ISDIR) && defined(S_IFDIR)
71# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
72#endif
73#if !defined(S_ISREG) && defined(S_IFREG)
74# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
75#endif
76#if !defined(S_ISFIFO) && defined(S_IFIFO)
77# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
78#endif
79#if !defined(S_ISLNK) && defined(S_IFLNK)
80# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
81#endif
82#if !defined(S_ISSOCK) && defined(S_IFSOCK)
83# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
84#endif
85#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
86# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
87# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
88#endif
89#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
90# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
91#endif
92
93#define IN_CTYPE_DOMAIN(c) 1
94
95#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
96#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
97#define ISDIGIT(c) (((unsigned char) (c)) - '0' <= 9)
98
99#define isodigit(c) ((c) >= '0' && (c) <= '7')
100#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
101#define octtobin(c) ((c) - '0')
102
103static double xstrtod __P((char *s));
104static int print_esc __P((char *escstart));
105static int print_formatted __P((char *format, int argc, char **argv));
106static long xstrtol __P((char *s));
107static unsigned long xstrtoul __P((char *s));
108static void print_direc
109__P(
110
111 (char *start, size_t length, int field_width, int precision,
112 char *argument));
113static void print_esc_char __P((int c));
114static void print_esc_string __P((char *str));
115static void verify __P((char *s, char *end));
116
117/* The value to return to the calling program. */
118static int exit_status;
119
120int printf_main(int argc, char **argv)
121{
122 char *format;
123 int args_used;
124
125 exit_status = 0;
126 if (argc <= 1 || **(argv + 1) == '-') {
127 show_usage();
128 }
129
130 format = argv[1];
131 argc -= 2;
132 argv += 2;
133
134 do {
135 args_used = print_formatted(format, argc, argv);
136 argc -= args_used;
137 argv += args_used;
138 }
139 while (args_used > 0 && argc > 0);
140
141/*
142 if (argc > 0)
143 fprintf(stderr, "excess args ignored");
144*/
145
146 return(exit_status);
147}
148
149/* Print the text in FORMAT, using ARGV (with ARGC elements) for
150 arguments to any `%' directives.
151 Return the number of elements of ARGV used. */
152
153static int print_formatted(char *format, int argc, char **argv)
154{
155 int save_argc = argc; /* Preserve original value. */
156 char *f; /* Pointer into `format'. */
157 char *direc_start; /* Start of % directive. */
158 size_t direc_length; /* Length of % directive. */
159 int field_width; /* Arg to first '*', or -1 if none. */
160 int precision; /* Arg to second '*', or -1 if none. */
161
162 for (f = format; *f; ++f) {
163 switch (*f) {
164 case '%':
165 direc_start = f++;
166 direc_length = 1;
167 field_width = precision = -1;
168 if (*f == '%') {
169 putchar('%');
170 break;
171 }
172 if (*f == 'b') {
173 if (argc > 0) {
174 print_esc_string(*argv);
175 ++argv;
176 --argc;
177 }
178 break;
179 }
180 if (strchr("-+ #", *f)) {
181 ++f;
182 ++direc_length;
183 }
184 if (*f == '*') {
185 ++f;
186 ++direc_length;
187 if (argc > 0) {
188 field_width = xstrtoul(*argv);
189 ++argv;
190 --argc;
191 } else
192 field_width = 0;
193 } else
194 while (ISDIGIT(*f)) {
195 ++f;
196 ++direc_length;
197 }
198 if (*f == '.') {
199 ++f;
200 ++direc_length;
201 if (*f == '*') {
202 ++f;
203 ++direc_length;
204 if (argc > 0) {
205 precision = xstrtoul(*argv);
206 ++argv;
207 --argc;
208 } else
209 precision = 0;
210 } else
211 while (ISDIGIT(*f)) {
212 ++f;
213 ++direc_length;
214 }
215 }
216 if (*f == 'l' || *f == 'L' || *f == 'h') {
217 ++f;
218 ++direc_length;
219 }
220 /*
221 if (!strchr ("diouxXfeEgGcs", *f))
222 fprintf(stderr, "%%%c: invalid directive", *f);
223 */
224 ++direc_length;
225 if (argc > 0) {
226 print_direc(direc_start, direc_length, field_width,
227 precision, *argv);
228 ++argv;
229 --argc;
230 } else
231 print_direc(direc_start, direc_length, field_width,
232 precision, "");
233 break;
234
235 case '\\':
236 f += print_esc(f);
237 break;
238
239 default:
240 putchar(*f);
241 }
242 }
243
244 return save_argc - argc;
245}
246
247/* Print a \ escape sequence starting at ESCSTART.
248 Return the number of characters in the escape sequence
249 besides the backslash. */
250
251static int print_esc(char *escstart)
252{
253 register char *p = escstart + 1;
254 int esc_value = 0; /* Value of \nnn escape. */
255 int esc_length; /* Length of \nnn escape. */
256
257 /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
258 if (*p == 'x') {
259 for (esc_length = 0, ++p;
260 esc_length < 3 && ISXDIGIT(*p); ++esc_length, ++p)
261 esc_value = esc_value * 16 + hextobin(*p);
262/* if (esc_length == 0)
263 fprintf(stderr, "missing hex in esc");
264*/
265 putchar(esc_value);
266 } else if (*p == '0') {
267 for (esc_length = 0, ++p;
268 esc_length < 3 && isodigit(*p); ++esc_length, ++p)
269 esc_value = esc_value * 8 + octtobin(*p);
270 putchar(esc_value);
271 } else if (strchr("\"\\abcfnrtv", *p))
272 print_esc_char(*p++);
273/* else
274 fprintf(stderr, "\\%c: invalid esc", *p);
275*/
276 return p - escstart - 1;
277}
278
279/* Output a single-character \ escape. */
280
281static void print_esc_char(int c)
282{
283 switch (c) {
284 case 'a': /* Alert. */
285 putchar(7);
286 break;
287 case 'b': /* Backspace. */
288 putchar(8);
289 break;
290 case 'c': /* Cancel the rest of the output. */
291 exit(0);
292 break;
293 case 'f': /* Form feed. */
294 putchar(12);
295 break;
296 case 'n': /* New line. */
297 putchar(10);
298 break;
299 case 'r': /* Carriage return. */
300 putchar(13);
301 break;
302 case 't': /* Horizontal tab. */
303 putchar(9);
304 break;
305 case 'v': /* Vertical tab. */
306 putchar(11);
307 break;
308 default:
309 putchar(c);
310 break;
311 }
312}
313
314/* Print string STR, evaluating \ escapes. */
315
316static void print_esc_string(char *str)
317{
318 for (; *str; str++)
319 if (*str == '\\')
320 str += print_esc(str);
321 else
322 putchar(*str);
323}
324
325static void
326print_direc(char *start, size_t length, int field_width, int precision,
327 char *argument)
328{
329 char *p; /* Null-terminated copy of % directive. */
330
331 p = xmalloc((unsigned) (length + 1));
332 strncpy(p, start, length);
333 p[length] = 0;
334
335 switch (p[length - 1]) {
336 case 'd':
337 case 'i':
338 if (field_width < 0) {
339 if (precision < 0)
340 printf(p, xstrtol(argument));
341 else
342 printf(p, precision, xstrtol(argument));
343 } else {
344 if (precision < 0)
345 printf(p, field_width, xstrtol(argument));
346 else
347 printf(p, field_width, precision, xstrtol(argument));
348 }
349 break;
350
351 case 'o':
352 case 'u':
353 case 'x':
354 case 'X':
355 if (field_width < 0) {
356 if (precision < 0)
357 printf(p, xstrtoul(argument));
358 else
359 printf(p, precision, xstrtoul(argument));
360 } else {
361 if (precision < 0)
362 printf(p, field_width, xstrtoul(argument));
363 else
364 printf(p, field_width, precision, xstrtoul(argument));
365 }
366 break;
367
368 case 'f':
369 case 'e':
370 case 'E':
371 case 'g':
372 case 'G':
373 if (field_width < 0) {
374 if (precision < 0)
375 printf(p, xstrtod(argument));
376 else
377 printf(p, precision, xstrtod(argument));
378 } else {
379 if (precision < 0)
380 printf(p, field_width, xstrtod(argument));
381 else
382 printf(p, field_width, precision, xstrtod(argument));
383 }
384 break;
385
386 case 'c':
387 printf(p, *argument);
388 break;
389
390 case 's':
391 if (field_width < 0) {
392 if (precision < 0)
393 printf(p, argument);
394 else
395 printf(p, precision, argument);
396 } else {
397 if (precision < 0)
398 printf(p, field_width, argument);
399 else
400 printf(p, field_width, precision, argument);
401 }
402 break;
403 }
404
405 free(p);
406}
407
408static unsigned long xstrtoul(char *s)
409{
410 char *end;
411 unsigned long val;
412
413 errno = 0;
414 val = strtoul(s, &end, 0);
415 verify(s, end);
416 return val;
417}
418
419static long xstrtol(char *s)
420{
421 char *end;
422 long val;
423
424 errno = 0;
425 val = strtol(s, &end, 0);
426 verify(s, end);
427 return val;
428}
429
430static double xstrtod(char *s)
431{
432 char *end;
433 double val;
434
435 errno = 0;
436 val = strtod(s, &end);
437 verify(s, end);
438 return val;
439}
440
441static void verify(char *s, char *end)
442{
443 if (errno) {
444 fprintf(stderr, "%s", s);
445 exit_status = 1;
446 } else if (*end) {
447 /*
448 if (s == end)
449 fprintf(stderr, "%s: expected numeric", s);
450 else
451 fprintf(stderr, "%s: not completely converted", s);
452 */
453 exit_status = 1;
454 }
455}
diff --git a/pristine_setup.sh b/pristine_setup.sh
deleted file mode 100755
index 9e638f96e..000000000
--- a/pristine_setup.sh
+++ /dev/null
@@ -1,46 +0,0 @@
1#!/bin/sh
2#
3# To compile BusyBox without touching the original sources
4# (as might be interesting for multi-target builds), create
5# an empty directory, cd into it, and run this program by
6# giving its explicit path (kind of like how you would run
7# configure, if BusyBox had one). Then you should be ready
8# to "make". Files in the build tree, in particular Config.h,
9# will override those in the pristine source tree.
10#
11# If you use a ? in your path name, you lose, see sed command below.
12
13export LC_ALL=POSIX
14export LC_CTYPE=POSIX
15
16DIR=${0%%/pristine_setup.sh}
17if [ ! -d $DIR ]; then
18 echo "unexpected problem: $DIR is not a directory. Aborting pristine setup"
19 exit
20fi
21
22echo " "
23
24if [ -e ./Config.h ]; then
25 echo "./Config.h already exists: not overwriting"
26 exit
27fi
28
29if [ -e ./Makefile ]; then
30 echo "./Makefile already exists: not overwriting"
31fi
32
33sed -e "s?BB_SRC_DIR =.*?BB_SRC_DIR = $DIR?" <$DIR/Makefile >Makefile || exit
34cp $DIR/Config.h Config.h || exit
35#mkdir -p pwd_grp
36
37if [ ! -r $DIR/sh.c ]; then
38 echo "Warning: no shell selected. You must make the symlink (sh.c to either"
39 echo "lash.c or hush.c) in $DIR, not here."
40fi
41
42echo " "
43echo "You may now type 'make' to build busybox in this directory"
44echo "($PWD) using the pristine sources in $DIR"
45echo " "
46
diff --git a/procps/Makefile b/procps/Makefile
new file mode 100644
index 000000000..0e3bdc254
--- /dev/null
+++ b/procps/Makefile
@@ -0,0 +1,40 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := procps.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27obj-$(CONFIG_FREE) += free.o
28obj-$(CONFIG_KILL) += kill.o
29obj-$(CONFIG_PIDOF) += pidof.o
30obj-$(CONFIG_PS) += ps.o
31obj-$(CONFIG_RENICE) += renice.o
32obj-$(CONFIG_UPTIME) += uptime.o
33
34
35# Hand off to toplevel Rules.mak
36include $(TOPDIR)/Rules.mak
37
38clean:
39 rm -f $(L_TARGET) *.o core
40
diff --git a/procps/config.in b/procps/config.in
new file mode 100644
index 000000000..0c9c35c06
--- /dev/null
+++ b/procps/config.in
@@ -0,0 +1,17 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Process Utilities'
8
9bool 'free' CONFIG_FREE
10bool 'kill' CONFIG_KILL
11bool 'pidof' CONFIG_PIDOF
12bool 'ps' CONFIG_PS
13bool 'renice' CONFIG_RENICE
14bool 'uptime' CONFIG_UPTIME
15
16endmenu
17
diff --git a/procps/free.c b/procps/free.c
index 2e34a972c..cdc0d358c 100644
--- a/procps/free.c
+++ b/procps/free.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini free implementation for busybox 3 * Mini free implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/procps/kill.c b/procps/kill.c
index 3884ebdf4..8b8a9922c 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -40,7 +40,7 @@ extern int kill_main(int argc, char **argv)
40 int whichApp, sig = SIGTERM; 40 int whichApp, sig = SIGTERM;
41 const char *name; 41 const char *name;
42 42
43#ifdef BB_KILLALL 43#ifdef CONFIG_KILLALL
44 /* Figure out what we are trying to do here */ 44 /* Figure out what we are trying to do here */
45 whichApp = (strcmp(applet_name, "killall") == 0)? KILLALL : KILL; 45 whichApp = (strcmp(applet_name, "killall") == 0)? KILLALL : KILL;
46#else 46#else
@@ -108,7 +108,7 @@ extern int kill_main(int argc, char **argv)
108 argv++; 108 argv++;
109 } 109 }
110 } 110 }
111#ifdef BB_KILLALL 111#ifdef CONFIG_KILLALL
112 else { 112 else {
113 int all_found = TRUE; 113 int all_found = TRUE;
114 pid_t myPid=getpid(); 114 pid_t myPid=getpid();
diff --git a/procps/pidof.c b/procps/pidof.c
index 50dffd387..5a40288dc 100644
--- a/procps/pidof.c
+++ b/procps/pidof.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * pidof implementation for busybox 3 * pidof implementation for busybox
4 * 4 *
5 * Copyright (C) 2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/procps/ps.c b/procps/ps.c
index 9e96a5402..fcb605a6e 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -2,15 +2,8 @@
2/* 2/*
3 * Mini ps implementation(s) for busybox 3 * Mini ps implementation(s) for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 *
8 *
9 * This contains _two_ implementations of ps for Linux. One uses the
10 * traditional /proc virtual filesystem, and the other use the devps kernel
11 * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+).
12 *
13 *
14 * 7 *
15 * This program is free software; you can redistribute it and/or modify it 8 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the Free 9 * under the terms of the GNU General Public License as published by the Free
@@ -25,7 +18,12 @@
25 * You should have received a copy of the GNU General Public License along with 18 * You should have received a copy of the GNU General Public License along with
26 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 19 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
27 * Place, Suite 330, Boston, MA 02111-1307 USA 20 * Place, Suite 330, Boston, MA 02111-1307 USA
28 * 21 */
22
23/*
24 * This contains _two_ implementations of ps for Linux. One uses the
25 * traditional /proc virtual filesystem, and the other use the devps kernel
26 * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+).
29 */ 27 */
30 28
31#include <stdio.h> 29#include <stdio.h>
@@ -44,7 +42,7 @@ static const int TERMINAL_WIDTH = 79; /* not 80 in case terminal has linefo
44 42
45 43
46 44
47#if ! defined BB_FEATURE_USE_DEVPS_PATCH 45#if ! defined CONFIG_FEATURE_USE_DEVPS_PATCH
48 46
49/* The following is the first ps implementation -- 47/* The following is the first ps implementation --
50 * the one using the /proc virtual filesystem. 48 * the one using the /proc virtual filesystem.
@@ -114,7 +112,7 @@ extern int ps_main(int argc, char **argv)
114 char path[32], sbuf[512]; 112 char path[32], sbuf[512];
115 char uidName[9]; 113 char uidName[9];
116 int len, i, c; 114 int len, i, c;
117#ifdef BB_FEATURE_AUTOWIDTH 115#ifdef CONFIG_FEATURE_AUTOWIDTH
118 struct winsize win = { 0, 0, 0, 0 }; 116 struct winsize win = { 0, 0, 0, 0 };
119 int terminal_width = TERMINAL_WIDTH; 117 int terminal_width = TERMINAL_WIDTH;
120#else 118#else
@@ -127,7 +125,7 @@ extern int ps_main(int argc, char **argv)
127 if (!dir) 125 if (!dir)
128 error_msg_and_die("Can't open /proc"); 126 error_msg_and_die("Can't open /proc");
129 127
130#ifdef BB_FEATURE_AUTOWIDTH 128#ifdef CONFIG_FEATURE_AUTOWIDTH
131 ioctl(fileno(stdout), TIOCGWINSZ, &win); 129 ioctl(fileno(stdout), TIOCGWINSZ, &win);
132 if (win.ws_col > 0) 130 if (win.ws_col > 0)
133 terminal_width = win.ws_col - 1; 131 terminal_width = win.ws_col - 1;
@@ -169,7 +167,7 @@ extern int ps_main(int argc, char **argv)
169} 167}
170 168
171 169
172#else /* BB_FEATURE_USE_DEVPS_PATCH */ 170#else /* CONFIG_FEATURE_USE_DEVPS_PATCH */
173 171
174 172
175/* The following is the second ps implementation -- 173/* The following is the second ps implementation --
@@ -187,7 +185,7 @@ extern int ps_main(int argc, char **argv)
187 pid_t* pid_array = NULL; 185 pid_t* pid_array = NULL;
188 struct pid_info info; 186 struct pid_info info;
189 char uidName[9]; 187 char uidName[9];
190#ifdef BB_FEATURE_AUTOWIDTH 188#ifdef CONFIG_FEATURE_AUTOWIDTH
191 struct winsize win = { 0, 0, 0, 0 }; 189 struct winsize win = { 0, 0, 0, 0 };
192 int terminal_width = TERMINAL_WIDTH; 190 int terminal_width = TERMINAL_WIDTH;
193#else 191#else
@@ -217,7 +215,7 @@ extern int ps_main(int argc, char **argv)
217 if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 215 if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0)
218 perror_msg_and_die("\nDEVPS_GET_PID_LIST"); 216 perror_msg_and_die("\nDEVPS_GET_PID_LIST");
219 217
220#ifdef BB_FEATURE_AUTOWIDTH 218#ifdef CONFIG_FEATURE_AUTOWIDTH
221 ioctl(fileno(stdout), TIOCGWINSZ, &win); 219 ioctl(fileno(stdout), TIOCGWINSZ, &win);
222 if (win.ws_col > 0) 220 if (win.ws_col > 0)
223 terminal_width = win.ws_col - 1; 221 terminal_width = win.ws_col - 1;
@@ -262,5 +260,5 @@ extern int ps_main(int argc, char **argv)
262 exit (0); 260 exit (0);
263} 261}
264 262
265#endif /* BB_FEATURE_USE_DEVPS_PATCH */ 263#endif /* CONFIG_FEATURE_USE_DEVPS_PATCH */
266 264
diff --git a/procps/uptime.c b/procps/uptime.c
index 6758d959e..85ff2233c 100644
--- a/procps/uptime.c
+++ b/procps/uptime.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini uptime implementation for busybox 3 * Mini uptime implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@
24/* This version of uptime doesn't display the number of users on the system, 24/* This version of uptime doesn't display the number of users on the system,
25 * since busybox init doesn't mess with utmp. For folks using utmp that are 25 * since busybox init doesn't mess with utmp. For folks using utmp that are
26 * just dying to have # of users reported, feel free to write it as some type 26 * just dying to have # of users reported, feel free to write it as some type
27 * of BB_FEATURE_UTMP_SUPPORT #define 27 * of CONFIG_FEATURE_UTMP_SUPPORT #define
28 */ 28 */
29 29
30/* getopt not needed */ 30/* getopt not needed */
diff --git a/ps.c b/ps.c
deleted file mode 100644
index 9e96a5402..000000000
--- a/ps.c
+++ /dev/null
@@ -1,266 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini ps implementation(s) for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 *
9 * This contains _two_ implementations of ps for Linux. One uses the
10 * traditional /proc virtual filesystem, and the other use the devps kernel
11 * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+).
12 *
13 *
14 *
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the Free
17 * Software Foundation; either version 2 of the License, or (at your option)
18 * any later version.
19 *
20 * This program is distributed in the hope that it will be useful, but WITHOUT
21 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
23 * more details.
24 *
25 * You should have received a copy of the GNU General Public License along with
26 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
27 * Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <dirent.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <ctype.h>
38#include <string.h>
39#include <termios.h>
40#include <sys/ioctl.h>
41#include "busybox.h"
42
43static const int TERMINAL_WIDTH = 79; /* not 80 in case terminal has linefold bug */
44
45
46
47#if ! defined BB_FEATURE_USE_DEVPS_PATCH
48
49/* The following is the first ps implementation --
50 * the one using the /proc virtual filesystem.
51 */
52
53typedef struct proc_s {
54 char
55 cmd[16]; /* basename of executable file in call to exec(2) */
56 int
57 ruid, /* real only (sorry) */
58 pid, /* process id */
59 ppid; /* pid of parent process */
60 char
61 state; /* single-char code for process state (S=sleeping) */
62} proc_t;
63
64
65
66static int file2str(char *filename, char *ret, int cap)
67{
68 int fd, num_read;
69
70 if ((fd = open(filename, O_RDONLY, 0)) == -1)
71 return -1;
72 if ((num_read = read(fd, ret, cap - 1)) <= 0)
73 return -1;
74 ret[num_read] = 0;
75 close(fd);
76 return num_read;
77}
78
79
80static void parse_proc_status(char *S, proc_t * P)
81{
82 char *tmp;
83
84 memset(P->cmd, 0, sizeof P->cmd);
85 sscanf(S, "Name:\t%15c", P->cmd);
86 tmp = strchr(P->cmd, '\n');
87 if (tmp)
88 *tmp = '\0';
89 tmp = strstr(S, "State");
90 sscanf(tmp, "State:\t%c", &P->state);
91
92 tmp = strstr(S, "Pid:");
93 if (tmp)
94 sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid);
95 else
96 error_msg("Internal error!");
97
98 /* For busybox, ignoring effective, saved, etc. */
99 tmp = strstr(S, "Uid:");
100 if (tmp)
101 sscanf(tmp, "Uid:\t%d", &P->ruid);
102 else
103 error_msg("Internal error!");
104
105
106}
107
108extern int ps_main(int argc, char **argv)
109{
110 proc_t p;
111 DIR *dir;
112 FILE *file;
113 struct dirent *entry;
114 char path[32], sbuf[512];
115 char uidName[9];
116 int len, i, c;
117#ifdef BB_FEATURE_AUTOWIDTH
118 struct winsize win = { 0, 0, 0, 0 };
119 int terminal_width = TERMINAL_WIDTH;
120#else
121#define terminal_width TERMINAL_WIDTH
122#endif
123
124
125
126 dir = opendir("/proc");
127 if (!dir)
128 error_msg_and_die("Can't open /proc");
129
130#ifdef BB_FEATURE_AUTOWIDTH
131 ioctl(fileno(stdout), TIOCGWINSZ, &win);
132 if (win.ws_col > 0)
133 terminal_width = win.ws_col - 1;
134#endif
135
136 printf(" PID Uid Stat Command\n");
137 while ((entry = readdir(dir)) != NULL) {
138 if (!isdigit(*entry->d_name))
139 continue;
140 sprintf(path, "/proc/%s/status", entry->d_name);
141 if ((file2str(path, sbuf, sizeof sbuf)) != -1) {
142 parse_proc_status(sbuf, &p);
143 }
144
145 /* Make some adjustments as needed */
146 my_getpwuid(uidName, p.ruid);
147 if (*uidName == '\0')
148 sprintf(uidName, "%d", p.ruid);
149
150 sprintf(path, "/proc/%s/cmdline", entry->d_name);
151 file = fopen(path, "r");
152 if (file == NULL)
153 continue;
154 i = 0;
155 len = printf("%5d %-8s %c ", p.pid, uidName, p.state);
156 while (((c = getc(file)) != EOF) && (i < (terminal_width-len))) {
157 i++;
158 if (c == '\0')
159 c = ' ';
160 putc(c, stdout);
161 }
162 fclose(file);
163 if (i == 0)
164 printf("[%s]", p.cmd);
165 putchar('\n');
166 }
167 closedir(dir);
168 return EXIT_SUCCESS;
169}
170
171
172#else /* BB_FEATURE_USE_DEVPS_PATCH */
173
174
175/* The following is the second ps implementation --
176 * this one uses the nifty new devps kernel device.
177 */
178
179#include <linux/devps.h> /* For Erik's nifty devps device driver */
180
181
182extern int ps_main(int argc, char **argv)
183{
184 char device[] = "/dev/ps";
185 int i, j, len, fd;
186 pid_t num_pids;
187 pid_t* pid_array = NULL;
188 struct pid_info info;
189 char uidName[9];
190#ifdef BB_FEATURE_AUTOWIDTH
191 struct winsize win = { 0, 0, 0, 0 };
192 int terminal_width = TERMINAL_WIDTH;
193#else
194#define terminal_width TERMINAL_WIDTH
195#endif
196
197 if (argc > 1 && **(argv + 1) == '-')
198 show_usage();
199
200 /* open device */
201 fd = open(device, O_RDONLY);
202 if (fd < 0)
203 perror_msg_and_die( "open failed for `%s'", device);
204
205 /* Find out how many processes there are */
206 if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0)
207 perror_msg_and_die( "\nDEVPS_GET_PID_LIST");
208
209 /* Allocate some memory -- grab a few extras just in case
210 * some new processes start up while we wait. The kernel will
211 * just ignore any extras if we give it too many, and will trunc.
212 * the list if we give it too few. */
213 pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t));
214 pid_array[0] = num_pids+10;
215
216 /* Now grab the pid list */
217 if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0)
218 perror_msg_and_die("\nDEVPS_GET_PID_LIST");
219
220#ifdef BB_FEATURE_AUTOWIDTH
221 ioctl(fileno(stdout), TIOCGWINSZ, &win);
222 if (win.ws_col > 0)
223 terminal_width = win.ws_col - 1;
224#endif
225
226 /* Print up a ps listing */
227 printf(" PID Uid Stat Command\n");
228
229 for (i=1; i<pid_array[0] ; i++) {
230 info.pid = pid_array[i];
231
232 if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
233 perror_msg_and_die("\nDEVPS_GET_PID_INFO");
234
235 /* Make some adjustments as needed */
236 my_getpwuid(uidName, info.euid);
237 if (*uidName == '\0')
238 sprintf(uidName, "%ld", info.euid);
239
240 len = printf("%5d %-8s %c ", info.pid, uidName, info.state);
241
242 if (strlen(info.command_line) > 1) {
243 for( j=0; j<(sizeof(info.command_line)-1) && j < (terminal_width-len); j++) {
244 if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') {
245 *(info.command_line+j) = ' ';
246 }
247 }
248 *(info.command_line+j) = '\0';
249 puts(info.command_line);
250 } else {
251 printf("[%s]\n", info.name);
252 }
253 }
254
255 /* Free memory */
256 free( pid_array);
257
258 /* close device */
259 if (close (fd) != 0)
260 perror_msg_and_die("close failed for `%s'", device);
261
262 exit (0);
263}
264
265#endif /* BB_FEATURE_USE_DEVPS_PATCH */
266
diff --git a/pwd.c b/pwd.c
deleted file mode 100644
index f6a00bf1e..000000000
--- a/pwd.c
+++ /dev/null
@@ -1,44 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini pwd implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24/* getopt not needed */
25
26#include <stdio.h>
27#include <dirent.h>
28#include <errno.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include "busybox.h"
32
33extern int pwd_main(int argc, char **argv)
34{
35 static char *buf;
36
37 buf = xgetcwd(buf);
38
39 if (buf != NULL) {
40 puts(buf);
41 return EXIT_SUCCESS;
42 }
43 return EXIT_FAILURE;
44}
diff --git a/rdate.c b/rdate.c
deleted file mode 100644
index 04a76129a..000000000
--- a/rdate.c
+++ /dev/null
@@ -1,116 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * The Rdate command will ask a time server for the RFC 868 time
4 * and optionally set the system time.
5 *
6 * by Sterling Huxley <sterling@europa.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22*/
23
24#include <sys/time.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <netdb.h>
29#include <stdio.h>
30#include <getopt.h>
31#include <string.h>
32#include <time.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include "busybox.h"
36
37
38static const int RFC_868_BIAS = 2208988800UL;
39
40static time_t askremotedate(const char *host)
41{
42 struct hostent *h;
43 struct sockaddr_in s_in;
44 struct servent *tserv;
45 unsigned long int nett, localt;
46 int fd;
47
48 h = xgethostbyname(host); /* get the IP addr */
49 memcpy(&s_in.sin_addr, h->h_addr, sizeof(s_in.sin_addr));
50
51 s_in.sin_port = htons(37); /* find port # */
52 if ((tserv = getservbyname("time", "tcp")) != NULL)
53 s_in.sin_port = tserv->s_port;
54
55 s_in.sin_family = AF_INET;
56
57 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) /* get net connection */
58 perror_msg_and_die("socket");
59
60 if (connect(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) /* connect to time server */
61 perror_msg_and_die("%s", host);
62
63 if (read(fd, (void *)&nett, 4) != 4) /* read time from server */
64 error_msg_and_die("%s did not send the complete time", host);
65
66 close(fd);
67
68 /* convert from network byte order to local byte order.
69 * RFC 868 time is the number of seconds
70 * since 00:00 (midnight) 1 January 1900 GMT
71 * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT
72 * Subtract the RFC 868 time to get Linux epoch
73 */
74 localt= ntohl(nett) - RFC_868_BIAS;
75
76 return(localt);
77}
78
79int rdate_main(int argc, char **argv)
80{
81 time_t remote_time;
82 int opt;
83 int setdate = 1;
84 int printdate = 1;
85
86 /* Interpret command line args */
87 while ((opt = getopt(argc, argv, "sp")) > 0) {
88 switch (opt) {
89 case 's':
90 printdate = 0;
91 setdate = 1;
92 break;
93 case 'p':
94 printdate = 1;
95 setdate = 0;
96 break;
97 default:
98 show_usage();
99 }
100 }
101
102 if (optind == argc)
103 show_usage();
104
105 remote_time = askremotedate(argv[optind]);
106
107 if (setdate) {
108 if (stime(&remote_time) < 0)
109 perror_msg_and_die("Could not set time of day");
110 }
111
112 if (printdate)
113 printf("%s", ctime(&remote_time));
114
115 return EXIT_SUCCESS;
116}
diff --git a/readlink.c b/readlink.c
deleted file mode 100644
index c46ebd108..000000000
--- a/readlink.c
+++ /dev/null
@@ -1,48 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini readlink implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <errno.h>
26#include <unistd.h>
27#include <stdlib.h>
28#include "busybox.h"
29
30int readlink_main(int argc, char **argv)
31{
32 char *buf = NULL;
33
34 /* no options, no getopt */
35
36 if (argc != 2)
37 show_usage();
38
39 buf = xreadlink(argv[1]);
40 if (!buf)
41 return EXIT_FAILURE;
42 puts(buf);
43#ifdef BB_FEATURE_CLEAN_UP
44 free(buf);
45#endif
46
47 return EXIT_SUCCESS;
48}
diff --git a/reboot.c b/reboot.c
deleted file mode 100644
index 35afd74ff..000000000
--- a/reboot.c
+++ /dev/null
@@ -1,49 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini reboot implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include "busybox.h"
25#include <signal.h>
26
27extern int reboot_main(int argc, char **argv)
28{
29#ifdef BB_FEATURE_LINUXRC
30 /* don't assume init's pid == 1 */
31 pid_t *pid = find_pid_by_name("init");
32 if (!pid || *pid<=0) {
33 pid = find_pid_by_name("linuxrc");
34 if (!pid || *pid<=0)
35 error_msg_and_die("no process killed");
36 }
37 return(kill(*pid, SIGTERM));
38#else
39 return(kill(1, SIGTERM));
40#endif
41}
42
43/*
44Local Variables:
45c-file-style: "linux"
46c-basic-offset: 4
47tab-width: 4
48End:
49*/
diff --git a/renice.c b/renice.c
deleted file mode 100644
index ec35bdcde..000000000
--- a/renice.c
+++ /dev/null
@@ -1,54 +0,0 @@
1/*
2 * Mini renice implementation for busybox
3 *
4 *
5 * Copyright (C) 2000 Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <errno.h>
25#include <stdlib.h>
26#include <sys/time.h>
27#include <sys/resource.h>
28#include "busybox.h"
29
30
31extern int renice_main(int argc, char **argv)
32{
33 int prio, status = EXIT_SUCCESS;
34
35 if (argc < 3) show_usage();
36
37 prio = atoi(*++argv);
38 if (prio > 20) prio = 20;
39 if (prio < -20) prio = -20;
40
41 while (*++argv) {
42 int ps = atoi(*argv);
43 int oldp = getpriority(PRIO_PROCESS, ps);
44
45 if (setpriority(PRIO_PROCESS, ps, prio) == 0) {
46 printf("%d: old priority %d, new priority %d\n", ps, oldp, prio );
47 } else {
48 perror_msg("%d: setpriority", ps);
49 status = EXIT_FAILURE;
50 }
51 }
52
53 return status;
54}
diff --git a/reset.c b/reset.c
deleted file mode 100644
index 755c4c335..000000000
--- a/reset.c
+++ /dev/null
@@ -1,35 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini reset implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * and Kent Robotti <robotti@metconnect.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include "busybox.h"
29
30extern int reset_main(int argc, char **argv)
31{
32 printf("\033c");
33 return EXIT_SUCCESS;
34}
35
diff --git a/rm.c b/rm.c
deleted file mode 100644
index 51c9f4ceb..000000000
--- a/rm.c
+++ /dev/null
@@ -1,77 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini rm implementation for busybox
4 *
5 *
6 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <time.h>
27#include <utime.h>
28#include <dirent.h>
29#include <errno.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <getopt.h>
34#include "busybox.h"
35
36extern int rm_main(int argc, char **argv)
37{
38 int status = 0;
39 int opt;
40 int flags = 0;
41 int i;
42
43 while ((opt = getopt(argc, argv, "fiRr")) != -1) {
44 switch (opt) {
45 case 'f':
46 flags &= ~FILEUTILS_INTERACTIVE;
47 flags |= FILEUTILS_FORCE;
48 break;
49 case 'i':
50 flags &= ~FILEUTILS_FORCE;
51 flags |= FILEUTILS_INTERACTIVE;
52 break;
53 case 'R':
54 case 'r':
55 flags |= FILEUTILS_RECUR;
56 break;
57 }
58 }
59
60 if (!(flags & FILEUTILS_FORCE) && optind == argc)
61 show_usage();
62
63 for (i = optind; i < argc; i++) {
64 char *base = get_last_path_component(argv[i]);
65
66 if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) {
67 error_msg("cannot remove `.' or `..'");
68 status = 1;
69 continue;
70 }
71
72 if (remove_file(argv[i], flags) < 0)
73 status = 1;
74 }
75
76 return status;
77}
diff --git a/rmdir.c b/rmdir.c
deleted file mode 100644
index cac27cac9..000000000
--- a/rmdir.c
+++ /dev/null
@@ -1,97 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini rmdir implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <getopt.h>
26#include <unistd.h>
27#include <stdlib.h>
28
29#include "busybox.h"
30
31
32/* Return true if a path is composed of multiple components. */
33
34static int
35multiple_components_p (const char *path)
36{
37 const char *s = path;
38
39 while (s[0] != '\0' && s[0] != '/')
40 s++;
41
42 while (s[0] == '/')
43 s++;
44
45 return (s[0] != '\0');
46}
47
48
49/* Remove a directory. Returns 0 if successful, -1 on error. */
50
51static int
52remove_directory (char *path, int flags)
53{
54 if (!(flags & FILEUTILS_RECUR)) {
55 if (rmdir (path) < 0) {
56 perror_msg ("unable to remove `%s'", path);
57 return -1;
58 }
59 } else {
60 if (remove_directory (path, 0) < 0)
61 return -1;
62
63 if (multiple_components_p (path))
64 if (remove_directory (dirname (path), flags) < 0)
65 return -1;
66 }
67
68 return 0;
69}
70
71
72extern int
73rmdir_main (int argc, char **argv)
74{
75 int status = EXIT_SUCCESS;
76 int flags = 0;
77 int i, opt;
78
79 while ((opt = getopt (argc, argv, "p")) != -1)
80 switch (opt) {
81 case 'p':
82 flags |= FILEUTILS_RECUR;
83 break;
84
85 default:
86 show_usage ();
87 }
88
89 if (optind == argc)
90 show_usage();
91
92 for (i = optind; i < argc; i++)
93 if (remove_directory (argv[i], flags) < 0)
94 status = EXIT_FAILURE;
95
96 return status;
97}
diff --git a/rmmod.c b/rmmod.c
deleted file mode 100644
index 7596d0232..000000000
--- a/rmmod.c
+++ /dev/null
@@ -1,62 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini rmmod implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <stdio.h>
25#include <errno.h>
26#include <unistd.h>
27#include <stdlib.h>
28#include <getopt.h>
29#include "busybox.h"
30
31extern int delete_module(const char * name);
32
33
34extern int rmmod_main(int argc, char **argv)
35{
36 int n, ret = EXIT_SUCCESS;
37
38 /* Parse command line. */
39 while ((n = getopt(argc, argv, "a")) != EOF) {
40 switch (n) {
41 case 'a':
42 /* Unload _all_ unused modules via NULL delete_module() call */
43 if (delete_module(NULL))
44 perror_msg_and_die("rmmod");
45 return EXIT_SUCCESS;
46 default:
47 show_usage();
48 }
49 }
50
51 if (optind == argc)
52 show_usage();
53
54 for (n = optind; n < argc; n++) {
55 if (delete_module(argv[n]) < 0) {
56 perror_msg("%s", argv[n]);
57 ret = EXIT_FAILURE;
58 }
59 }
60
61 return(ret);
62}
diff --git a/route.c b/route.c
deleted file mode 100644
index ee3533100..000000000
--- a/route.c
+++ /dev/null
@@ -1,452 +0,0 @@
1/* route
2 *
3 * Similar to the standard Unix route, but with only the necessary
4 * parts for AF_INET
5 *
6 * Bjorn Wesen, Axis Communications AB
7 *
8 * Author of the original route:
9 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
10 * (derived from FvK's 'route.c 1.70 01/04/94')
11 *
12 * This program is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU General
14 * Public License as published by the Free Software
15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version.
17 *
18 * $Id: route.c,v 1.13 2001/09/05 19:32:00 andersen Exp $
19 *
20 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
21 * adjustments by Larry Doolittle <LRDoolittle@lbl.gov>
22 */
23
24#include <sys/types.h>
25#include <sys/ioctl.h>
26#include <sys/socket.h>
27#include <net/route.h>
28#include <linux/param.h> // HZ
29#include <netinet/in.h>
30#include <arpa/inet.h>
31#include <stdio.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <stdlib.h>
35#include <string.h>
36#include <getopt.h>
37#include <unistd.h>
38#include <ctype.h>
39#include "busybox.h"
40
41#define _(x) x
42
43#define RTACTION_ADD 1
44#define RTACTION_DEL 2
45#define RTACTION_HELP 3
46#define RTACTION_FLUSH 4
47#define RTACTION_SHOW 5
48
49#define E_NOTFOUND 8
50#define E_SOCK 7
51#define E_LOOKUP 6
52#define E_VERSION 5
53#define E_USAGE 4
54#define E_OPTERR 3
55#define E_INTERN 2
56#define E_NOSUPP 1
57
58/* resolve XXX.YYY.ZZZ.QQQ -> binary */
59
60static int
61INET_resolve(char *name, struct sockaddr *sa)
62{
63 struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
64
65 s_in->sin_family = AF_INET;
66 s_in->sin_port = 0;
67
68 /* Default is special, meaning 0.0.0.0. */
69 if (strcmp(name, "default")==0) {
70 s_in->sin_addr.s_addr = INADDR_ANY;
71 return 1;
72 }
73 /* Look to see if it's a dotted quad. */
74 if (inet_aton(name, &s_in->sin_addr)) {
75 return 0;
76 }
77 /* guess not.. */
78 return -1;
79}
80
81#if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */
82#define HAVE_NEW_ADDRT 1
83#endif
84#ifdef RTF_IRTT /* route */
85#define HAVE_RTF_IRTT 1
86#endif
87#ifdef RTF_REJECT /* route */
88#define HAVE_RTF_REJECT 1
89#endif
90
91#if HAVE_NEW_ADDRT
92#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
93#define full_mask(x) (x)
94#else
95#define mask_in_addr(x) ((x).rt_genmask)
96#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
97#endif
98
99/* add or delete a route depending on action */
100
101static int
102INET_setroute(int action, int options, char **args)
103{
104 struct rtentry rt;
105 char target[128], gateway[128] = "NONE", netmask[128] = "default";
106 int xflag, isnet;
107 int skfd;
108
109 xflag = 0;
110
111 if (*args == NULL)
112 show_usage();
113 if (strcmp(*args, "-net")==0) {
114 xflag = 1;
115 args++;
116 } else if (strcmp(*args, "-host")==0) {
117 xflag = 2;
118 args++;
119 }
120 safe_strncpy(target, *args++, (sizeof target));
121
122 /* Clean out the RTREQ structure. */
123 memset((char *) &rt, 0, sizeof(struct rtentry));
124
125
126 if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) {
127 error_msg(_("can't resolve %s"), target);
128 return EXIT_FAILURE; /* XXX change to E_something */
129 }
130
131 switch (xflag) {
132 case 1:
133 isnet = 1;
134 break;
135
136 case 2:
137 isnet = 0;
138 break;
139
140 default:
141 break;
142 }
143
144 /* Fill in the other fields. */
145 rt.rt_flags = (RTF_UP | RTF_HOST);
146 if (isnet)
147 rt.rt_flags &= ~RTF_HOST;
148
149 while (*args) {
150 if (strcmp(*args, "metric")==0) {
151 int metric;
152
153 args++;
154 if (!*args || !isdigit(**args))
155 show_usage();
156 metric = atoi(*args);
157#if HAVE_NEW_ADDRT
158 rt.rt_metric = metric + 1;
159#else
160 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */
161#endif
162 args++;
163 continue;
164 }
165
166 if (strcmp(*args, "netmask")==0) {
167 struct sockaddr mask;
168
169 args++;
170 if (!*args || mask_in_addr(rt))
171 show_usage();
172 safe_strncpy(netmask, *args, (sizeof netmask));
173 if ((isnet = INET_resolve(netmask, &mask)) < 0) {
174 error_msg(_("can't resolve netmask %s"), netmask);
175 return E_LOOKUP;
176 }
177 rt.rt_genmask = full_mask(mask);
178 args++;
179 continue;
180 }
181
182 if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) {
183 args++;
184 if (!*args)
185 show_usage();
186 if (rt.rt_flags & RTF_GATEWAY)
187 show_usage();
188 safe_strncpy(gateway, *args, (sizeof gateway));
189 if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) {
190 error_msg(_("can't resolve gw %s"), gateway);
191 return E_LOOKUP;
192 }
193 if (isnet) {
194 error_msg(
195 _("%s: cannot use a NETWORK as gateway!"),
196 gateway);
197 return E_OPTERR;
198 }
199 rt.rt_flags |= RTF_GATEWAY;
200 args++;
201 continue;
202 }
203
204 if (strcmp(*args, "mss")==0) {
205 args++;
206 rt.rt_flags |= RTF_MSS;
207 if (!*args)
208 show_usage();
209 rt.rt_mss = atoi(*args);
210 args++;
211 if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
212 error_msg(_("Invalid MSS."));
213 return E_OPTERR;
214 }
215 continue;
216 }
217
218 if (strcmp(*args, "window")==0) {
219 args++;
220 if (!*args)
221 show_usage();
222 rt.rt_flags |= RTF_WINDOW;
223 rt.rt_window = atoi(*args);
224 args++;
225 if (rt.rt_window < 128) {
226 error_msg(_("Invalid window."));
227 return E_OPTERR;
228 }
229 continue;
230 }
231
232 if (strcmp(*args, "irtt")==0) {
233 args++;
234 if (!*args)
235 show_usage();
236 args++;
237#if HAVE_RTF_IRTT
238 rt.rt_flags |= RTF_IRTT;
239 rt.rt_irtt = atoi(*(args - 1));
240 rt.rt_irtt *= (HZ / 100); /* FIXME */
241#if 0 /* FIXME: do we need to check anything of this? */
242 if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
243 error_msg(_("Invalid initial rtt."));
244 return E_OPTERR;
245 }
246#endif
247#else
248 ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */
249#endif
250 continue;
251 }
252
253 if (strcmp(*args, "reject")==0) {
254 args++;
255#if HAVE_RTF_REJECT
256 rt.rt_flags |= RTF_REJECT;
257#else
258 ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
259#endif
260 continue;
261 }
262 if (strcmp(*args, "mod")==0) {
263 args++;
264 rt.rt_flags |= RTF_MODIFIED;
265 continue;
266 }
267 if (strcmp(*args, "dyn")==0) {
268 args++;
269 rt.rt_flags |= RTF_DYNAMIC;
270 continue;
271 }
272 if (strcmp(*args, "reinstate")==0) {
273 args++;
274 rt.rt_flags |= RTF_REINSTATE;
275 continue;
276 }
277 if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) {
278 args++;
279 if (rt.rt_dev || *args == NULL)
280 show_usage();
281 rt.rt_dev = *args++;
282 continue;
283 }
284 /* nothing matches */
285 if (!rt.rt_dev) {
286 rt.rt_dev = *args++;
287 if (*args)
288 show_usage(); /* must be last to catch typos */
289 } else {
290 show_usage();
291 }
292 }
293
294#if HAVE_RTF_REJECT
295 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
296 rt.rt_dev = "lo";
297#endif
298
299 /* sanity checks.. */
300 if (mask_in_addr(rt)) {
301 unsigned long mask = mask_in_addr(rt);
302 mask = ~ntohl(mask);
303 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
304 error_msg(
305 _("netmask %.8x doesn't make sense with host route"),
306 (unsigned int)mask);
307 return E_OPTERR;
308 }
309 if (mask & (mask + 1)) {
310 error_msg(_("bogus netmask %s"), netmask);
311 return E_OPTERR;
312 }
313 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
314 if (mask & ~mask_in_addr(rt)) {
315 error_msg(_("netmask doesn't match route address"));
316 return E_OPTERR;
317 }
318 }
319 /* Fill out netmask if still unset */
320 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
321 mask_in_addr(rt) = 0xffffffff;
322
323 /* Create a socket to the INET kernel. */
324 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
325 perror("socket");
326 return E_SOCK;
327 }
328 /* Tell the kernel to accept this route. */
329 if (action == RTACTION_DEL) {
330 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
331 perror("SIOCDELRT");
332 close(skfd);
333 return E_SOCK;
334 }
335 } else {
336 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
337 perror("SIOCADDRT");
338 close(skfd);
339 return E_SOCK;
340 }
341 }
342
343 /* Close the socket. */
344 (void) close(skfd);
345 return EXIT_SUCCESS;
346}
347
348#ifndef RTF_UP
349/* Keep this in sync with /usr/src/linux/include/linux/route.h */
350#define RTF_UP 0x0001 /* route usable */
351#define RTF_GATEWAY 0x0002 /* destination is a gateway */
352#define RTF_HOST 0x0004 /* host entry (net otherwise) */
353#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
354#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
355#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
356#define RTF_MTU 0x0040 /* specific MTU for this route */
357#ifndef RTF_MSS
358#define RTF_MSS RTF_MTU /* Compatibility :-( */
359#endif
360#define RTF_WINDOW 0x0080 /* per route window clamping */
361#define RTF_IRTT 0x0100 /* Initial round trip time */
362#define RTF_REJECT 0x0200 /* Reject route */
363#endif
364
365static void displayroutes(void)
366{
367 char buff[256];
368 int nl = 0 ;
369 struct in_addr dest;
370 struct in_addr gw;
371 struct in_addr mask;
372 int flgs, ref, use, metric;
373 char flags[64];
374 unsigned long int d,g,m;
375
376 char sdest[16], sgw[16];
377
378
379 FILE *fp = xfopen("/proc/net/route", "r");
380
381 while( fgets(buff, sizeof(buff), fp) != NULL ) {
382 if(nl) {
383 int ifl = 0;
384 while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0')
385 ifl++;
386 buff[ifl]=0; /* interface */
387 if(sscanf(buff+ifl+1, "%lx%lx%X%d%d%d%lx",
388 &d, &g, &flgs, &ref, &use, &metric, &m)!=7) {
389 error_msg_and_die( "Unsuported kernel route format\n");
390 }
391 if(nl==1)
392 printf("Kernel IP routing table\n"
393 "Destination Gateway Genmask Flags Metric Ref Use Iface\n");
394
395 ifl = 0; /* parse flags */
396 if(flgs&RTF_UP) {
397 if(flgs&RTF_REJECT)
398 flags[ifl++]='!';
399 else
400 flags[ifl++]='U';
401 if(flgs&RTF_GATEWAY)
402 flags[ifl++]='G';
403 if(flgs&RTF_HOST)
404 flags[ifl++]='H';
405 if(flgs&RTF_REINSTATE)
406 flags[ifl++]='R';
407 if(flgs&RTF_DYNAMIC)
408 flags[ifl++]='D';
409 if(flgs&RTF_MODIFIED)
410 flags[ifl++]='M';
411 flags[ifl]=0;
412 dest.s_addr = d;
413 gw.s_addr = g;
414 mask.s_addr = m;
415 strcpy(sdest, (dest.s_addr==0 ? "default" :
416 inet_ntoa(dest)));
417 strcpy(sgw, (gw.s_addr==0 ? "*" :
418 inet_ntoa(gw)));
419 printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n",
420 sdest, sgw,
421 inet_ntoa(mask),
422 flags, metric, ref, use, buff);
423 }
424 }
425 nl++;
426 }
427}
428
429int route_main(int argc, char **argv)
430{
431 int what = 0;
432
433 argc--;
434 argv++;
435
436 if (*argv == NULL) {
437 displayroutes();
438 return EXIT_SUCCESS;
439 } else {
440 /* check verb */
441 if (strcmp(*argv, "add")==0)
442 what = RTACTION_ADD;
443 else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0)
444 what = RTACTION_DEL;
445 else if (strcmp(*argv, "flush")==0)
446 what = RTACTION_FLUSH;
447 else
448 show_usage();
449 }
450
451 return INET_setroute(what, 0, ++argv);
452}
diff --git a/rpm2cpio.c b/rpm2cpio.c
deleted file mode 100644
index 8d639d6ad..000000000
--- a/rpm2cpio.c
+++ /dev/null
@@ -1,91 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini rpm2cpio implementation for busybox
4 *
5 * Copyright (C) 2001 by Laurence Anderson
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include "busybox.h"
23#include <netinet/in.h> /* For ntohl & htonl function */
24#include <string.h>
25
26#define RPM_MAGIC "\355\253\356\333"
27#define RPM_HEADER_MAGIC "\216\255\350"
28
29struct rpm_lead {
30 unsigned char magic[4];
31 u_int8_t major, minor;
32 u_int16_t type;
33 u_int16_t archnum;
34 char name[66];
35 u_int16_t osnum;
36 u_int16_t signature_type;
37 char reserved[16];
38};
39
40struct rpm_header {
41 char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
42 u_int8_t version; /* 1 byte version number */
43 u_int32_t reserved; /* 4 bytes reserved */
44 u_int32_t entries; /* Number of entries in header (4 bytes) */
45 u_int32_t size; /* Size of store (4 bytes) */
46};
47
48void skip_header(FILE *rpmfile)
49{
50 struct rpm_header header;
51
52 fread(&header, sizeof(struct rpm_header), 1, rpmfile);
53 if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */
54 if (header.version != 1) error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */
55 header.entries = ntohl(header.entries);
56 header.size = ntohl(header.size);
57 fseek (rpmfile, 16 * header.entries, SEEK_CUR); /* Seek past index entries */
58 fseek (rpmfile, header.size, SEEK_CUR); /* Seek past store */
59}
60
61/* No getopt required */
62extern int rpm2cpio_main(int argc, char **argv)
63{
64 struct rpm_lead lead;
65 int gunzip_pid;
66 FILE *rpmfile, *cpiofile;
67
68 if (argc == 1) {
69 rpmfile = stdin;
70 } else {
71 rpmfile = fopen(argv[1], "r");
72 if (!rpmfile) perror_msg_and_die("Can't open rpm file");
73 /* set the buffer size */
74 setvbuf(rpmfile, NULL, _IOFBF, 0x8000);
75 }
76
77 fread (&lead, sizeof(struct rpm_lead), 1, rpmfile);
78 if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */
79 /* Skip the signature header */
80 skip_header(rpmfile);
81 fseek(rpmfile, (8 - (ftell(rpmfile) % 8)) % 8, SEEK_CUR); /* Pad to 8 byte boundary */
82 /* Skip the main header */
83 skip_header(rpmfile);
84
85 cpiofile = gz_open(rpmfile, &gunzip_pid);
86
87 copyfd(fileno(cpiofile), fileno(stdout));
88 gz_close(gunzip_pid);
89 fclose(rpmfile);
90 return 0;
91}
diff --git a/scripts/Configure b/scripts/Configure
new file mode 100644
index 000000000..01637bdbe
--- /dev/null
+++ b/scripts/Configure
@@ -0,0 +1,705 @@
1#! /bin/sh
2#
3# This script is used to configure BusyBox.
4#
5# It was inspired by the challenge in the original Configure script
6# to ``do something better'', combined with the actual need to ``do
7# something better'' because the old configure script wasn't flexible
8# enough.
9#
10# Raymond Chen was the original author of Configure.
11# Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
12#
13# 050793 - use IFS='@' to get around a bug in a pre-version of bash-1.13
14# with an empty IFS.
15#
16# 030995 (storner@osiris.ping.dk) - added support for tri-state answers,
17# for selecting modules to compile.
18#
19# 180995 Bernhard Kaindl (bkaindl@ping.at) - added dummy functions for
20# use with a config.in modified for make menuconfig.
21#
22# 301195 (boldt@math.ucsb.edu) - added help text support
23#
24# 281295 Paul Gortmaker - make tri_state functions collapse to boolean
25# if module support is not enabled.
26#
27# 010296 Aaron Ucko (ucko@vax1.rockhurst.edu) - fix int and hex to accept
28# arbitrary ranges
29#
30# 150296 Dick Streefland (dicks@tasking.nl) - report new configuration
31# items and ask for a value even when doing a "make oldconfig"
32#
33# 200396 Tom Dyas (tdyas@eden.rutgers.edu) - when the module option is
34# chosen for an item, define the macro <option_name>_MODULE
35#
36# 090397 Axel Boldt (boldt@math.ucsb.edu) - avoid ? and + in regular
37# expressions for GNU expr since version 1.15 and up use \? and \+.
38#
39# 300397 Phil Blundell (pjb27@cam.ac.uk) - added support for min/max
40# arguments to "int", allow dep_tristate to take a list of dependencies
41# rather than just one.
42#
43# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
44# texts.
45#
46# 102598 Michael Chastain (mec@shout.net) - put temporary files in
47# current directory, not in /tmp.
48#
49# 24 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
50# - Improve the exit message (Jeff Ronne).
51#
52# 7 October 2000, Ghozlane Toumi, <gtoumi@messel.emse.fr>
53# added switches for "random" , "all yes" and "all modules"
54#
55
56#
57# Make sure we're really running bash.
58#
59# I would really have preferred to write this script in a language with
60# better string handling, but alas, bash is the only scripting language
61# that I can be reasonable sure everybody has on their linux machine.
62#
63[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; }
64
65# Disable filename globbing once and for all.
66# Enable function cacheing.
67set -f -h
68
69#
70# Dummy functions for use with a config.in modified for menuconf
71#
72function mainmenu_option () {
73 :
74}
75function mainmenu_name () {
76 :
77}
78function endmenu () {
79 :
80}
81
82#
83# returns a random number between 1 and $1
84#
85function rnd () {
86 rnd=$[ $RANDOM % $1 + 1 ]
87}
88
89#
90# randomly chose a number in a config list (LIST_CONFIG_NAME)
91# or in a range ( MIN_CONFIG_NAME MAX_CONFIG_NAME )
92# ONLY if there is no forced default (and we are in an "auto" mode)
93# we are limited by the range of values taken by "$RANDOM"
94#
95# rndval CONFIG_NAME
96#
97
98function rndval () {
99 [ "$AUTO" != "yes" -o -n "$old" ] && return
100 def_list=$(eval echo "\${LIST_$1}")
101 def_min=$(eval echo "\${MIN_$1}")
102 def_max=$(eval echo "\${MAX_$1}")
103
104 if [ -n "$def_list" ]; then
105 set -- $(echo $def_list | sed 's/,/ /g')
106 rnd $#
107 while [ $rnd -le $# ] ; do
108 def=$1
109 shift
110 done
111 return
112 fi
113 if [ -n "$def_min" -a -n "$def_max" ]; then
114 rnd $[ $def_max - $def_min ]
115 def=$[ $def_min + $rnd ]
116 fi
117}
118
119#
120# help prints the corresponding help text from Configure.help to stdout
121#
122# help variable
123#
124function help () {
125 if [ -f Documentation/Configure.help ]
126 then
127 #first escape regexp special characters in the argument:
128 var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
129 #now pick out the right help text:
130 text=$(sed -n "/^$var[ ]*\$/,\${
131 /^$var[ ]*\$/c\\
132${var}:\\
133
134 /^#/b
135 /^[^ ]/q
136 /<file:\\([^>]*\\)>/s//\\1/g
137 p
138 }" Documentation/Configure.help)
139 if [ -z "$text" ]
140 then
141 echo; echo " Sorry, no help available for this option yet.";echo
142 else
143 (echo; echo "$text") | ${PAGER:-more}
144 fi
145 else
146 echo;
147 echo " Can't access the file Documentation/Configure.help which"
148 echo " should contain the help texts."
149 echo
150 fi
151}
152
153
154#
155# readln reads a line into $ans.
156#
157# readln prompt default oldval
158#
159function readln () {
160 if [ "$AUTO" = "yes" ]; then
161 echo -n "$1"
162 ans=$2
163 echo $ans
164 elif [ "$DEFAULT" = "-d" -a -n "$3" ]; then
165 echo "$1"
166 ans=$2
167 else
168 echo -n "$1"
169 [ -z "$3" ] && echo -n "(NEW) "
170 IFS='@' read ans || exit 1
171 [ -z "$ans" ] && ans=$2
172 fi
173}
174
175#
176# comment does some pretty-printing
177#
178# comment 'xxx'
179#
180function comment () {
181 echo "*"; echo "* $1" ; echo "*"
182 (echo "" ; echo "#"; echo "# $1" ; echo "#") >>$CONFIG
183 (echo "" ; echo "/*"; echo " * $1" ; echo " */") >>$CONFIG_H
184}
185
186#
187# define_bool sets the value of a boolean argument
188#
189# define_bool define value
190#
191function define_bool () {
192 define_tristate $1 $2
193}
194
195function define_tristate () {
196 case "$2" in
197 "y")
198 echo "$1=y" >>$CONFIG
199 echo "#define $1 1" >>$CONFIG_H
200 ;;
201
202 "m")
203 echo "$1=m" >>$CONFIG
204 echo "#undef $1" >>$CONFIG_H
205 echo "#define $1_MODULE 1" >>$CONFIG_H
206 ;;
207
208 "n")
209 echo "# $1 is not set" >>$CONFIG
210 echo "#undef $1" >>$CONFIG_H
211 ;;
212 esac
213 eval "$1=$2"
214}
215
216#
217# bool processes a boolean argument
218#
219# bool question define
220#
221function bool () {
222 old=$(eval echo "\${$2}")
223 def=${old:-'n'}
224 if [ "$AUTO" = "yes" -a -z "$old" ]; then
225 if [ "$RND" = "-r" ]; then
226 rnd 2
227 case $rnd in
228 "1") def="y" ;;
229 "2") def="n" ;;
230 esac
231 else
232 def=$DEF_ANS;
233 fi
234 fi
235 case "$def" in
236 "y" | "m") defprompt="Y/n/?"
237 def="y"
238 ;;
239 "n") defprompt="N/y/?"
240 ;;
241 esac
242 while :; do
243 readln "$1 ($2) [$defprompt] " "$def" "$old"
244 case "$ans" in
245 [yY] | [yY]es ) define_bool "$2" "y"
246 break;;
247 [nN] | [nN]o ) define_bool "$2" "n"
248 break;;
249 * ) help "$2"
250 ;;
251 esac
252 done
253}
254
255#
256# tristate processes a tristate argument
257#
258# tristate question define
259#
260function tristate () {
261 if [ "$CONFIG_MODULES" != "y" ]; then
262 bool "$1" "$2"
263 else
264 old=$(eval echo "\${$2}")
265 def=${old:-'n'}
266 if [ "$AUTO" = "yes" -a -z "$old" ]; then
267 if [ "$RND" = "-r" ]; then
268 rnd 3
269 case $rnd in
270 "1") def="y" ;;
271 "2") def="n" ;;
272 "3") def="m" ;;
273 esac
274 else
275 def=$DEF_ANS
276 fi
277 fi
278 case "$def" in
279 "y") defprompt="Y/m/n/?"
280 ;;
281 "m") defprompt="M/n/y/?"
282 ;;
283 "n") defprompt="N/y/m/?"
284 ;;
285 esac
286 while :; do
287 readln "$1 ($2) [$defprompt] " "$def" "$old"
288 case "$ans" in
289 [yY] | [yY]es ) define_tristate "$2" "y"
290 break ;;
291 [nN] | [nN]o ) define_tristate "$2" "n"
292 break ;;
293 [mM] ) define_tristate "$2" "m"
294 break ;;
295 * ) help "$2"
296 ;;
297 esac
298 done
299 fi
300}
301
302#
303# dep_tristate processes a tristate argument that depends upon
304# another option or options. If any of the options we depend upon is a
305# module, then the only allowable options are M or N. If all are Y, then
306# this is a normal tristate. This is used in cases where modules
307# are nested, and one module requires the presence of something
308# else in the kernel.
309#
310# dep_tristate question define default ...
311#
312function dep_tristate () {
313 old=$(eval echo "\${$2}")
314 def=${old:-'n'}
315 ques=$1
316 var=$2
317 need_module=0
318 shift 2
319 while [ $# -gt 0 ]; do
320 case "$1" in
321 n)
322 define_tristate "$var" "n"
323 return
324 ;;
325 m)
326 need_module=1
327 ;;
328 esac
329 shift
330 done
331
332 if [ $need_module = 1 ]; then
333 if [ "$CONFIG_MODULES" = "y" ]; then
334 if [ "$AUTO" = "yes" -a -z "$old" ]; then
335 if [ "$RND" = "-r" ]; then
336 rnd 2
337 case $rnd in
338 "1") def="m" ;;
339 "2") def="n" ;;
340 esac
341 else
342 def=$DEF_ANS
343 fi
344 fi
345 case "$def" in
346 "y" | "m") defprompt="M/n/?"
347 def="m"
348 ;;
349 "n") defprompt="N/m/?"
350 ;;
351 esac
352 while :; do
353 readln "$ques ($var) [$defprompt] " "$def" "$old"
354 case "$ans" in
355 [nN] | [nN]o ) define_tristate "$var" "n"
356 break ;;
357 [mM] ) define_tristate "$var" "m"
358 break ;;
359 [yY] | [yY]es ) echo
360 echo " This answer is not allowed, because it is not consistent with"
361 echo " your other choices."
362 echo " This driver depends on another one which you chose to compile"
363 echo " as a module. This means that you can either compile this one"
364 echo " as a module as well (with M) or leave it out altogether (N)."
365 echo
366 ;;
367 * ) help "$var"
368 ;;
369 esac
370 done
371 fi
372 else
373 tristate "$ques" "$var"
374 fi
375}
376
377function dep_bool () {
378 ques=$1
379 var=$2
380 shift 2
381 while [ $# -gt 0 ]; do
382 case "$1" in
383 m | n)
384 define_bool "$var" "n"
385 return
386 ;;
387 esac
388 shift
389 done
390
391 bool "$ques" "$var"
392}
393
394function dep_mbool () {
395 ques=$1
396 var=$2
397 shift 2
398 while [ $# -gt 0 ]; do
399 case "$1" in
400 n)
401 define_bool "$var" "n"
402 return
403 ;;
404 esac
405 shift
406 done
407
408 bool "$ques" "$var"
409}
410
411#
412# define_int sets the value of a integer argument
413#
414# define_int define value
415#
416function define_int () {
417 echo "$1=$2" >>$CONFIG
418 echo "#define $1 ($2)" >>$CONFIG_H
419 eval "$1=$2"
420}
421
422#
423# int processes an integer argument with optional limits
424#
425# int question define default [min max]
426#
427function int () {
428 old=$(eval echo "\${$2}")
429 def=${old:-$3}
430 if [ $# -gt 3 ]; then
431 min=$4
432 else
433 min=-10000000 # !!
434 fi
435 if [ $# -gt 4 ]; then
436 max=$5
437 else
438 max=10000000 # !!
439 fi
440 rndval $2
441 while :; do
442 readln "$1 ($2) [$def] " "$def" "$old"
443 if expr \( \( $ans + 0 \) \>= $min \) \& \( $ans \<= $max \) >/dev/null 2>&1 ; then
444 define_int "$2" "$ans"
445 break
446 else
447 help "$2"
448 fi
449 done
450}
451
452#
453# define_hex sets the value of a hexadecimal argument
454#
455# define_hex define value
456#
457function define_hex () {
458 echo "$1=$2" >>$CONFIG
459 echo "#define $1 0x${2#*[x,X]}" >>$CONFIG_H
460 eval "$1=$2"
461}
462
463#
464# hex processes an hexadecimal argument
465#
466# hex question define default
467#
468function hex () {
469 old=$(eval echo "\${$2}")
470 def=${old:-$3}
471 def=${def#*[x,X]}
472 rndval $2
473 while :; do
474 readln "$1 ($2) [$def] " "$def" "$old"
475 ans=${ans#*[x,X]}
476 if expr "$ans" : '[0-9a-fA-F][0-9a-fA-F]*$' > /dev/null; then
477 define_hex "$2" "$ans"
478 break
479 else
480 help "$2"
481 fi
482 done
483}
484
485#
486# define_string sets the value of a string argument
487#
488# define_string define value
489#
490function define_string () {
491 echo "$1=\"$2\"" >>$CONFIG
492 echo "#define $1 \"$2\"" >>$CONFIG_H
493 eval "$1=\"$2\""
494}
495
496#
497# string processes a string argument
498#
499# string question define default
500#
501function string () {
502 old=$(eval echo "\${$2}")
503 def=${old:-$3}
504 while :; do
505 if [ "$old" = "?" ]; then
506 readln "$1 ($2) [$def] " "$def" ""
507 else
508 readln "$1 ($2) [$def] " "$def" "$old"
509 fi
510 if [ "$ans" = "?" ]; then
511 help "$2"
512 else
513 break
514 fi
515 done
516 define_string "$2" "$ans"
517}
518#
519# choice processes a choice list (1-out-of-n)
520#
521# choice question choice-list default
522#
523# The choice list has a syntax of:
524# NAME WHITESPACE VALUE { WHITESPACE NAME WHITESPACE VALUE }
525# The user may enter any unique prefix of one of the NAMEs and
526# choice will define VALUE as if it were a boolean option.
527# VALUE must be in all uppercase. Normally, VALUE is of the
528# form CONFIG_<something>. Thus, if the user selects <something>,
529# the CPP symbol CONFIG_<something> will be defined and the
530# shell variable CONFIG_<something> will be set to "y".
531#
532function choice () {
533 question="$1"
534 choices="$2"
535 old=
536 def=$3
537
538 # determine default answer:
539 names=""
540 set -- $choices
541 firstvar=$2
542 while [ -n "$2" ]; do
543 if [ -n "$names" ]; then
544 names="$names, $1"
545 else
546 names="$1"
547 fi
548 if [ "$(eval echo \"\${$2}\")" = "y" ]; then
549 old=$1
550 def=$1
551 fi
552 shift; shift
553 done
554
555 if [ "$RND" = "-r" -a -z "$old" ] ; then
556 set -- $choices
557 rnd $#
558 while [ $rnd -le $# ] ; do
559 def=$1
560 shift ; shift
561 done
562 fi
563
564 val=""
565 while [ -z "$val" ]; do
566 ambg=n
567 readln "$question ($names) [$def] " "$def" "$old"
568 ans=$(echo $ans | tr a-z A-Z)
569 set -- $choices
570 while [ -n "$1" ]; do
571 name=$(echo $1 | tr a-z A-Z)
572 case "$name" in
573 "$ans"* | */"$ans"* )
574 case "$name" in
575 "$ans" | */"$ans"/* | \
576 "$ans"/* | */"$ans" )
577 val="$2"
578 break # exact match
579 ;;
580 esac
581 if [ -n "$val" ]; then
582 echo;echo \
583 " Sorry, \"$ans\" is ambiguous; please enter a longer string."
584 echo
585 val=""
586 ambg=y
587 break
588 else
589 val="$2"
590 fi;;
591 esac
592 shift; shift
593 done
594 if [ "$val" = "" -a "$ambg" = "n" ]; then
595 help "$firstvar"
596 fi
597 done
598 set -- $choices
599 while [ -n "$2" ]; do
600 if [ "$2" = "$val" ]; then
601 echo " defined $val"
602 define_bool "$2" "y"
603 else
604 define_bool "$2" "n"
605 fi
606 shift; shift
607 done
608}
609
610CONFIG=.tmpconfig
611CONFIG_H=.tmpconfig.h
612FORCE_DEFAULT=.force_default
613trap "rm -f $CONFIG $CONFIG_H ; exit 1" 1 2
614
615#
616# Make sure we start out with a clean slate.
617#
618echo "#" > $CONFIG
619echo "# Automatically generated make config: don't edit" >> $CONFIG
620echo "#" >> $CONFIG
621
622echo "/*" > $CONFIG_H
623echo " * Automatically generated C config: don't edit" >> $CONFIG_H
624echo " */" >> $CONFIG_H
625echo "#define AUTOCONF_INCLUDED" >> $CONFIG_H
626
627DEFAULT=""
628if [ "$1" = "-d" ] ; then
629 DEFAULT="-d"
630 shift
631fi
632
633RND=""
634DEF_ANS=""
635AUTO=""
636case "$1" in
637 -r) RND="-r" ; AUTO="yes" ; shift ;;
638 -y) DEF_ANS="y" ; AUTO="yes" ; shift ;;
639 -m) DEF_ANS="m" ; AUTO="yes" ; shift ;;
640 -n) DEF_ANS="n" ; AUTO="yes" ; shift ;;
641esac
642
643CONFIG_IN=./config.in
644if [ "$1" != "" ] ; then
645 CONFIG_IN=$1
646fi
647
648DEFAULTS=sysdeps/$TARGET_OS/defconfig
649if [ -f .config ]; then
650 DEFAULTS=.config
651fi
652
653if [ "$AUTO" != "yes" ]; then
654 if [ -f $DEFAULTS ]; then
655 echo "#"
656 echo "# Using defaults found in" $DEFAULTS
657 echo "#"
658 . $DEFAULTS
659 sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
660 . .config-is-not.$$
661 rm .config-is-not.$$
662 else
663 echo "#"
664 echo "# No defaults found"
665 echo "#"
666 fi
667else
668 if [ -f $FORCE_DEFAULT ]; then
669 echo "#"
670 echo "# Forcing defaults found in $FORCE_DEFAULT"
671 echo "#"
672 sed -e '
673s/# \(CONFIG_[^ ]*\) is not.*/\1=n/;
674s/# range \(CONFIG_[^ ]*\) \([^ ][^ ]*\) \([^ ][^ ]*\)/MIN_\1=\2; MAX_\1=\3/;
675s/# list \(CONFIG_[^ ]*\) \([^ ][^ ]*\)/LIST_\1=\2/
676' <$FORCE_DEFAULT >.default_val.$$
677 . .default_val.$$
678 rm .default_val.$$
679 else
680 echo "#"
681 echo "# No defaults found"
682 echo "#"
683 fi
684fi
685
686. $CONFIG_IN
687
688rm -f .config.old
689if [ -f .config ]; then
690 mv .config .config.old
691fi
692mv .tmpconfig .config
693mv .tmpconfig.h include/config.h
694
695echo
696echo "*** End of BusyBox configuration."
697echo "*** Check the top-level Makefile for additional configuration."
698if [ ! -f .hdepend -o "$CONFIG_MODVERSIONS" = "y" ] ; then
699 echo "*** Next, you must run 'make dep'."
700else
701 echo "*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'."
702fi
703echo
704
705exit 0
diff --git a/scripts/Menuconfig b/scripts/Menuconfig
new file mode 100644
index 000000000..5d4cdce6b
--- /dev/null
+++ b/scripts/Menuconfig
@@ -0,0 +1,1285 @@
1#! /bin/sh
2#
3# This script is used to configure BusyBox.
4#
5# It was inspired by a desire to not have to hit <enter> 9 million times
6# or startup the X server just to change a single kernel parameter.
7#
8# This script attempts to parse the configuration files, which are
9# scattered throughout the kernel source tree, and creates a temporary
10# set of mini scripts which are in turn used to create nested menus and
11# radiolists.
12#
13# It uses a very modified/mutilated version of the "dialog" utility
14# written by Savio Lam (lam836@cs.cuhk.hk). Savio is not responsible
15# for this script or the version of dialog used by this script.
16# Please do not contact him with questions. The official version of
17# dialog is available at sunsite.unc.edu or a sunsite mirror.
18#
19# Portions of this script were borrowed from the original Configure
20# script.
21#
22# William Roadcap was the original author of Menuconfig.
23# Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
24#
25# 070497 Bernhard Kaindl (bkaindl@netway.at) - get default values for
26# new bool, tristate and dep_tristate parameters from the defconfig file.
27# new configuration parameters are marked with '(NEW)' as in make config.
28#
29# 180697 Bernhard Kaindl (bkaindl@netway.at) - added the needed support
30# for string options. They are handled like the int and hex options.
31#
32# 081297 Pavel Machek (pavel@atrey.karlin.mff.cuni.cz) - better error
33# handling
34#
35# 131197 Michael Chastain (mec@shout.net) - output all lines for a
36# choice list, not just the selected one. This makes the output
37# the same as Configure output, which is important for smart config
38# dependencies.
39#
40# 101297 Michael Chastain (mec@shout.net) - remove sound driver cruft.
41#
42# 221297 Michael Chastain (mec@shout.net) - make define_bool actually
43# define its arguments so that later tests on them work right.
44#
45# 160198 Michael Chastain (mec@shout.net) - fix bug with 'c' command
46# (complement existing value) when used on virgin uninitialized variables.
47#
48# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
49# texts.
50#
51# 12 Dec 1998, Michael Elizabeth Chastain (mec@shout.net)
52# Remove a /tmp security hole in get_def (also makes it faster).
53# Give uninitialized variables canonical values rather than null value.
54# Change a lot of places to call set_x_info uniformly.
55# Take out message about preparing version (old sound driver cruft).
56#
57# 13 Dec 1998, Riley H Williams <rhw@memalpha.cx>
58# When an error occurs, actually display the error message as well as
59# our comments thereon.
60#
61# 31 Dec 1998, Michael Elizabeth Chastain (mec@shout.net)
62# Fix mod_bool to honor $CONFIG_MODULES.
63# Fix dep_tristate to call define_bool when dependency is "n".
64#
65# 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
66# Blow away lxdialog.scrltmp on entry to activate_menu. This protects
67# against people who use commands like ' ' to select menus.
68#
69# 24 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
70# - Improve the exit message (Jeff Ronne).
71#
72# 06 July 1999, Andrzej M. Krzysztofowicz, <ankry@mif.pg.gda.pl>
73# - Support for multiple conditions in dep_tristate().
74# - Implemented new functions: define_tristate(), define_int(), define_hex(),
75# define_string(), dep_bool().
76#
77# 22 October 2001, Erik Andersen <andersee@debian.org>
78# - Adjusted for busybox (modified hard coded kernel specific paths,
79# and everything to do with modules (tristates, modbools, etc).
80
81
82#
83# Change this to TRUE if you prefer all options listed
84# in a single menu rather than the standard menu hierarchy.
85#
86single_menu_mode=
87
88#
89# Make sure we're really running bash.
90#
91[ -z "$BASH" ] && { echo "Menuconfig requires bash" 1>&2; exit 1; }
92
93#
94# Cache function definitions, turn off posix compliance
95#
96set -h +o posix
97
98
99
100# Given a configuration variable, set the global variable $x to its value,
101# and the global variable $info to the string " (NEW)" if this is a new
102# variable.
103#
104# This function looks for: (1) the current value, or (2) the default value
105# from the arch-dependent defconfig file, or (3) a default passed by the caller.
106
107function set_x_info () {
108 eval x=\$$1
109 if [ -z "$x" ]; then
110 eval `sed -n -e 's/# \(.*\) is not set.*/\1=n/' -e "/^$1=/p" sysdeps/$TARGET_OS/defconfig`
111 eval x=\${$1:-"$2"}
112 eval $1=$x
113 eval INFO_$1="' (NEW)'"
114 fi
115 eval info="\$INFO_$1"
116}
117
118#
119# Load the functions used by the config.in files.
120#
121# I do this because these functions must be redefined depending
122# on whether they are being called for interactive use or for
123# saving a configuration to a file.
124#
125# Thank the heavens bash supports nesting function definitions.
126#
127load_functions () {
128
129#
130# Additional comments
131#
132function comment () {
133 comment_ctr=$[ comment_ctr + 1 ]
134 echo -ne "': $comment_ctr' '--- $1' " >>MCmenu
135}
136
137#
138# Define a boolean to a specific value.
139#
140function define_bool () {
141 eval $1=$2
142}
143
144function define_hex () {
145 eval $1=$2
146}
147
148function define_int () {
149 eval $1=$2
150}
151
152function define_string () {
153 eval $1="$2"
154}
155
156#
157# Create a boolean (Yes/No) function for our current menu
158# which calls our local bool function.
159#
160function bool () {
161 set_x_info "$2" "n"
162
163 case $x in
164 y|m) flag="*" ;;
165 n) flag=" " ;;
166 esac
167
168 echo -ne "'$2' '[$flag] $1$info' " >>MCmenu
169
170 echo -e "function $2 () { l_bool '$2' \"\$1\" ;}\n" >>MCradiolists
171}
172
173#
174# Same as above, but now only Y and N are allowed as dependency
175# (i.e. third and next arguments).
176#
177function dep_bool () {
178 ques="$1"
179 var="$2"
180 dep=y
181 shift 2
182 while [ $# -gt 0 ]; do
183 if [ "$1" = y ]; then
184 shift
185 else
186 dep=n
187 shift $#
188 fi
189 done
190 if [ "$dep" = y ]; then
191 bool "$ques" "$var"
192 else
193 define_bool "$var" n
194 fi
195}
196
197function dep_mbool () {
198 ques="$1"
199 var="$2"
200 dep=y
201 shift 2
202 while [ $# -gt 0 ]; do
203 if [ "$1" = y -o "$1" = m ]; then
204 shift
205 else
206 dep=n
207 shift $#
208 fi
209 done
210 if [ "$dep" = y ]; then
211 bool "$ques" "$var"
212 else
213 define_bool "$var" n
214 fi
215}
216
217#
218# Add a menu item which will call our local int function.
219#
220function int () {
221 set_x_info "$2" "$3"
222
223 echo -ne "'$2' '($x) $1$info' " >>MCmenu
224
225 echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' ;}" >>MCradiolists
226}
227
228#
229# Add a menu item which will call our local hex function.
230#
231function hex () {
232 set_x_info "$2" "$3"
233 x=${x##*[x,X]}
234
235 echo -ne "'$2' '($x) $1$info' " >>MCmenu
236
237 echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' ;}" >>MCradiolists
238}
239
240#
241# Add a menu item which will call our local string function.
242#
243function string () {
244 set_x_info "$2" "$3"
245
246 echo -ne "'$2' ' $1: \"$x\"$info' " >>MCmenu
247
248 echo -e "function $2 () { l_string '$1' '$2' '$3' '$x' ;}" >>MCradiolists
249}
250
251#
252# Add a menu item which will call our local One-of-Many choice list.
253#
254function choice () {
255 #
256 # Need to remember params cause they're gonna get reset.
257 #
258 title=$1
259 choices=$2
260 default=$3
261 current=
262
263 #
264 # Find out if one of the choices is already set.
265 # If it's not then make it the default.
266 #
267 set -- $choices
268 firstchoice=$2
269
270 while [ -n "$2" ]
271 do
272 if eval [ "_\$$2" = "_y" ]
273 then
274 current=$1
275 break
276 fi
277 shift ; shift
278 done
279
280 : ${current:=$default}
281
282 echo -ne "'$firstchoice' '($current) $title' " >>MCmenu
283
284 echo -e "
285 function $firstchoice () \
286 { l_choice '$title' \"$choices\" \"$current\" ;}" >>MCradiolists
287}
288
289} # END load_functions()
290
291
292
293
294
295#
296# Extract available help for an option from Configure.help
297# and send it to standard output.
298#
299# Most of this function was borrowed from the original kernel
300# Configure script.
301#
302function extract_help () {
303 if [ -f docs/Configure.help ]
304 then
305 #first escape regexp special characters in the argument:
306 var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
307 #now pick out the right help text:
308 text=$(sed -n "/^$var[ ]*\$/,\${
309 /^$var[ ]*\$/c\\
310${var}:\\
311
312 /^#/b
313 /^[^ ]/q
314 s/^ //
315 /<file:\\([^>]*\\)>/s//\\1/g
316 p
317 }" docs/Configure.help)
318
319 if [ -z "$text" ]
320 then
321 echo "There is no help available for this option."
322 return 1
323 else
324 echo "$text"
325 fi
326 else
327 echo "There is no help available for this option."
328 return 1
329 fi
330}
331
332#
333# Activate a help dialog.
334#
335function help () {
336 if extract_help $1 >help.out
337 then
338 $DIALOG --backtitle "$backtitle" --title "$2"\
339 --textbox help.out $ROWS $COLS
340 else
341 $DIALOG --backtitle "$backtitle" \
342 --textbox help.out $ROWS $COLS
343 fi
344 rm -f help.out
345}
346
347#
348# Show the README file.
349#
350function show_readme () {
351 $DIALOG --backtitle "$backtitle" \
352 --textbox scripts/README.Menuconfig $ROWS $COLS
353}
354
355#
356# Begin building the dialog menu command and Initialize the
357# Radiolist function file.
358#
359function menu_name () {
360 echo -ne "$DIALOG --title '$1'\
361 --backtitle '$backtitle' \
362 --menu '$menu_instructions' \
363 $ROWS $COLS $((ROWS-10)) \
364 '$default' " >MCmenu
365 >MCradiolists
366}
367
368#
369# Add a submenu option to the menu currently under construction.
370#
371function submenu () {
372 echo -ne "'activate_menu $2' '$1 --->' " >>MCmenu
373}
374
375#
376# Handle a boolean (Yes/No) option.
377#
378function l_bool () {
379 if [ -n "$2" ]
380 then
381 case "$2" in
382 y|m) eval $1=y ;;
383 c) eval x=\$$1
384 case $x in
385 y) eval $1=n ;;
386 n) eval $1=y ;;
387 *) eval $1=y ;;
388 esac ;;
389 *) eval $1=n ;;
390 esac
391 else
392 echo -ne "\007"
393 fi
394}
395
396#
397# Create a dialog for entering an integer into a option.
398#
399function l_int () {
400 while true
401 do
402 if $DIALOG --title "$1" \
403 --backtitle "$backtitle" \
404 --inputbox "$inputbox_instructions_int" \
405 10 75 "$4" 2>MCdialog.out
406 then
407 answer="`cat MCdialog.out`"
408 answer="${answer:-$3}"
409
410 # Semantics of + and ? in GNU expr changed, so
411 # we avoid them:
412 if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null
413 then
414 eval $2="$answer"
415 else
416 eval $2="$3"
417 echo -en "\007"
418 ${DIALOG} --backtitle "$backtitle" \
419 --infobox "You have made an invalid entry." 3 43
420 sleep 2
421 fi
422
423 break
424 fi
425
426 help "$2" "$1"
427 done
428}
429
430#
431# Create a dialog for entering a hexadecimal into an option.
432#
433function l_hex () {
434 while true
435 do
436 if $DIALOG --title "$1" \
437 --backtitle "$backtitle" \
438 --inputbox "$inputbox_instructions_hex" \
439 10 75 "$4" 2>MCdialog.out
440 then
441 answer="`cat MCdialog.out`"
442 answer="${answer:-$3}"
443 answer="${answer##*[x,X]}"
444
445 if expr "$answer" : '[0-9a-fA-F][0-9a-fA-F]*$' >/dev/null
446 then
447 eval $2="$answer"
448 else
449 eval $2="$3"
450 echo -en "\007"
451 ${DIALOG} --backtitle "$backtitle" \
452 --infobox "You have made an invalid entry." 3 43
453 sleep 2
454 fi
455
456 break
457 fi
458
459 help "$2" "$1"
460 done
461}
462
463#
464# Create a dialog for entering a string into an option.
465#
466function l_string () {
467 while true
468 do
469 if $DIALOG --title "$1" \
470 --backtitle "$backtitle" \
471 --inputbox "$inputbox_instructions_string" \
472 10 75 "$4" 2>MCdialog.out
473 then
474 answer="`cat MCdialog.out`"
475 answer="${answer:-$3}"
476
477 #
478 # Someone may add a nice check for the entered
479 # string here...
480 #
481 eval $2=\"$answer\"
482
483 break
484 fi
485
486 help "$2" "$1"
487 done
488}
489
490
491#
492# Handle a one-of-many choice list.
493#
494function l_choice () {
495 #
496 # Need to remember params cause they're gonna get reset.
497 #
498 title="$1"
499 choices="$2"
500 current="$3"
501 chosen=
502
503 #
504 # Scan current value of choices and set radiolist switches.
505 #
506 list=
507 set -- $choices
508 firstchoice=$2
509 while [ -n "$2" ]
510 do
511 case "$1" in
512 "$current"*) if [ -z "$chosen" ]; then
513 list="$list $2 $1 ON "
514 chosen=1
515 else
516 list="$list $2 $1 OFF "
517 fi ;;
518 *) list="$list $2 $1 OFF " ;;
519 esac
520
521 shift ; shift
522 done
523
524 while true
525 do
526 if $DIALOG --title "$title" \
527 --backtitle "$backtitle" \
528 --radiolist "$radiolist_instructions" \
529 15 70 6 $list 2>MCdialog.out
530 then
531 choice=`cat MCdialog.out`
532 break
533 fi
534
535 help "$firstchoice" "$title"
536 done
537
538 #
539 # Now set the boolean value of each option based on
540 # the selection made from the radiolist.
541 #
542 set -- $choices
543 while [ -n "$2" ]
544 do
545 if [ "$2" = "$choice" ]
546 then
547 eval $2="y"
548 else
549 eval $2="n"
550 fi
551
552 shift ; shift
553 done
554}
555
556#
557# Call awk, and watch for error codes, etc.
558#
559function callawk () {
560awk "$1" || echo "Awk died with error code $?. Giving up." || exit 1
561}
562
563#
564# A faster awk based recursive parser. (I hope)
565#
566function parser1 () {
567callawk '
568BEGIN {
569 menu_no = 0
570 comment_is_option = 0
571 parser("'$CONFIG_IN'","MCmenu0")
572}
573
574function parser(ifile,menu) {
575
576 while (getline <ifile) {
577 if ($1 == "mainmenu_option") {
578 comment_is_option = "1"
579 }
580 else if ($1 == "comment" && comment_is_option == "1") {
581 comment_is_option= "0"
582 sub($1,"",$0)
583 ++menu_no
584
585 printf("submenu %s MCmenu%s\n", $0, menu_no) >>menu
586
587 newmenu = sprintf("MCmenu%d", menu_no);
588 printf( "function MCmenu%s () {\n"\
589 "default=$1\n"\
590 "menu_name %s\n",\
591 menu_no, $0) >newmenu
592
593 parser(ifile, newmenu)
594 }
595 else if ($0 ~ /^#|\$MAKE|mainmenu_name/) {
596 printf("") >>menu
597 }
598 else if ($1 ~ "endmenu") {
599 printf("}\n") >>menu
600 return
601 }
602 else if ($1 == "source") {
603 parser($2,menu)
604 }
605 else {
606 print >>menu
607 }
608 }
609}'
610}
611
612#
613# Secondary parser for single menu mode.
614#
615function parser2 () {
616callawk '
617BEGIN {
618 parser("'$CONFIG_IN'","MCmenu0")
619}
620
621function parser(ifile,menu) {
622
623 while (getline <ifile) {
624 if ($0 ~ /^#|$MAKE|mainmenu_name/) {
625 printf("") >>menu
626 }
627 else if ($1 ~ /mainmenu_option|endmenu/) {
628 printf("") >>menu
629 }
630 else if ($1 == "source") {
631 parser($2,menu)
632 }
633 else {
634 print >>menu
635 }
636 }
637}'
638}
639
640#
641# Parse all the config.in files into mini scripts.
642#
643function parse_config_files () {
644 rm -f MCmenu*
645
646 echo "function MCmenu0 () {" >MCmenu0
647 echo 'default=$1' >>MCmenu0
648 echo "menu_name 'Main Menu'" >>MCmenu0
649
650 if [ "_$single_menu_mode" = "_TRUE" ]
651 then
652 parser2
653 else
654 parser1
655 fi
656
657 echo "comment ''" >>MCmenu0
658 echo "g_alt_config" >>MCmenu0
659 echo "s_alt_config" >>MCmenu0
660
661 echo "}" >>MCmenu0
662
663 #
664 # These mini scripts must be sourced into the current
665 # environment in order for all of this to work. Leaving
666 # them on the disk as executables screws up the recursion
667 # in activate_menu(), among other things. Once they are
668 # sourced we can discard them.
669 #
670 for i in MCmenu*
671 do
672 echo -n "."
673 source ./$i
674 done
675 rm -f MCmenu*
676}
677
678#
679# This is the menu tree's bootstrap.
680#
681# Executes the parsed menus on demand and creates a set of functions,
682# one per configuration option. These functions will in turn execute
683# dialog commands or recursively call other menus.
684#
685function activate_menu () {
686 rm -f lxdialog.scrltmp
687 while true
688 do
689 comment_ctr=0 #So comment lines get unique tags
690
691 $1 "$default" 2> MCerror #Create the lxdialog menu & functions
692
693 if [ "$?" != "0" ]
694 then
695 clear
696 cat <<EOM
697
698Menuconfig has encountered a possible error in one of BusyBox's
699configuration files and is unable to continue. Here is the error
700report:
701
702EOM
703 sed 's/^/ Q> /' MCerror
704 cat <<EOM
705
706Please report this to the maintainer <mec@shout.net>. You may also
707send a problem report to <busybox@oss.lineo.com>.
708
709Please indicate the BusyBox version you are trying to configure and
710which menu you were trying to enter when this error occurred.
711
712EOM
713 cleanup
714 exit 1
715 fi
716 rm -f MCerror
717
718 . ./MCradiolists #Source the menu's functions
719
720 . ./MCmenu 2>MCdialog.out #Activate the lxdialog menu
721 ret=$?
722
723 read selection <MCdialog.out
724
725 case "$ret" in
726 0|3|4|5|6)
727 defaults="$selection$defaults" #pseudo stack
728 case "$ret" in
729 0) eval $selection ;;
730 3) eval $selection y ;;
731 4) eval $selection n ;;
732 5) eval $selection m ;;
733 6) eval $selection c ;;
734 esac
735 default="${defaults%%*}" defaults="${defaults#*}"
736 ;;
737 2)
738 default="${selection%%\ *}"
739
740 case "$selection" in
741 *"-->"*|*"alt_config"*)
742 show_readme ;;
743 *)
744 eval help $selection ;;
745 esac
746 ;;
747 255|1)
748 break
749 ;;
750 139)
751 stty sane
752 clear
753 cat <<EOM
754
755There seems to be a problem with the lxdialog companion utility which is
756built prior to running Menuconfig. Usually this is an indicator that you
757have upgraded/downgraded your ncurses libraries and did not remove the
758old ncurses header file(s) in /usr/include or /usr/include/ncurses.
759
760It is VERY important that you have only one set of ncurses header files
761and that those files are properly version matched to the ncurses libraries
762installed on your machine.
763
764You may also need to rebuild lxdialog. This can be done by moving to
765the /usr/src/linux/scripts/lxdialog directory and issuing the
766"make clean all" command.
767
768If you have verified that your ncurses install is correct, you may email
769the maintainer <andersen@codepoet.org> or post a message to
770<busybox@oss.lineo.com> for additional assistance.
771
772EOM
773 cleanup
774 exit 139
775 ;;
776 esac
777 done
778}
779
780#
781# Create a menu item to load an alternate configuration file.
782#
783g_alt_config () {
784 echo -n "get_alt_config 'Load an Alternate Configuration File' "\
785 >>MCmenu
786}
787
788#
789# Get alternate config file name and load the
790# configuration from it.
791#
792get_alt_config () {
793 set -f ## Switch file expansion OFF
794
795 while true
796 do
797 ALT_CONFIG="${ALT_CONFIG:-$DEFAULTS}"
798
799 $DIALOG --backtitle "$backtitle" \
800 --inputbox "\
801Enter the name of the configuration file you wish to load. \
802Accept the name shown to restore the configuration you \
803last retrieved. Leave blank to abort."\
804 11 55 "$ALT_CONFIG" 2>MCdialog.out
805
806 if [ "$?" = "0" ]
807 then
808 ALT_CONFIG=`cat MCdialog.out`
809
810 [ "_" = "_$ALT_CONFIG" ] && break
811
812 if eval [ -r "$ALT_CONFIG" ]
813 then
814 eval load_config_file "$ALT_CONFIG"
815 break
816 else
817 echo -ne "\007"
818 $DIALOG --backtitle "$backtitle" \
819 --infobox "File does not exist!" 3 38
820 sleep 2
821 fi
822 else
823 cat <<EOM >help.out
824
825For various reasons, one may wish to keep several different BusyBox
826configurations available on a single machine.
827
828If you have saved a previous configuration in a file other than the
829busybox default, entering the name of the file here will allow you
830to modify that configuration.
831
832If you are uncertain, then you have probably never used alternate
833configuration files. You should therefor leave this blank to abort.
834
835EOM
836 $DIALOG --backtitle "$backtitle"\
837 --title "Load Alternate Configuration"\
838 --textbox help.out $ROWS $COLS
839 fi
840 done
841
842 set +f ## Switch file expansion ON
843 rm -f help.out MCdialog.out
844}
845
846#
847# Create a menu item to store an alternate config file.
848#
849s_alt_config () {
850 echo -n "save_alt_config 'Save Configuration to an Alternate File' "\
851 >>MCmenu
852}
853
854#
855# Get an alternate config file name and save the current
856# configuration to it.
857#
858save_alt_config () {
859 set -f ## Switch file expansion OFF
860
861 while true
862 do
863 $DIALOG --backtitle "$backtitle" \
864 --inputbox "\
865Enter a filename to which this configuration should be saved \
866as an alternate. Leave blank to abort."\
867 10 55 "$ALT_CONFIG" 2>MCdialog.out
868
869 if [ "$?" = "0" ]
870 then
871 ALT_CONFIG=`cat MCdialog.out`
872
873 [ "_" = "_$ALT_CONFIG" ] && break
874
875 if eval touch $ALT_CONFIG 2>/dev/null
876 then
877 eval save_configuration $ALT_CONFIG
878 load_functions ## RELOAD
879 break
880 else
881 echo -ne "\007"
882 $DIALOG --backtitle "$backtitle" \
883 --infobox "Can't create file! Probably a nonexistent directory." 3 60
884 sleep 2
885 fi
886 else
887 cat <<EOM >help.out
888
889For various reasons, one may wish to keep different BusyBox
890configurations available on a single machine.
891
892Entering a file name here will allow you to later retrieve, modify
893and use the current configuration as an alternate to whatever
894configuration options you have selected at that time.
895
896If you are uncertain what all this means then you should probably
897leave this blank.
898EOM
899 $DIALOG --backtitle "$backtitle"\
900 --title "Save Alternate Configuration"\
901 --textbox help.out $ROWS $COLS
902 fi
903 done
904
905 set +f ## Switch file expansion ON
906 rm -f help.out MCdialog.out
907}
908
909#
910# Load config options from a file.
911# Converts all "# OPTION is not set" lines to "OPTION=n" lines
912#
913function load_config_file () {
914 awk '
915 /# .* is not set.*/ { printf("%s=n\n", $2) }
916 ! /# .* is not set.*/ { print }
917 ' $1 >.tmpconfig
918
919 source ./.tmpconfig
920 rm -f .tmpconfig
921}
922
923#
924# Just what it says.
925#
926save_configuration () {
927 echo
928 echo -n "Saving your BusyBox configuration."
929
930 #
931 # Now, let's redefine the configuration functions for final
932 # output to the config files.
933 #
934 # Nested function definitions, YIPEE!
935 #
936 function bool () {
937 set_x_info "$2" "n"
938 eval define_bool "$2" "$x"
939 }
940
941 function dep_bool () {
942 set_x_info "$2" "n"
943 var="$2"
944 shift 2
945 while [ $# -gt 0 ]; do
946 if [ "$1" = y ]; then
947 shift
948 else
949 x=n; shift $#
950 fi
951 done
952 define_bool "$var" "$x"
953 }
954
955 function int () {
956 set_x_info "$2" "$3"
957 echo "$2=$x" >>$CONFIG
958 echo "#define $2 ($x)" >>$CONFIG_H
959 }
960
961 function hex () {
962 set_x_info "$2" "$3"
963 echo "$2=$x" >>$CONFIG
964 echo "#define $2 0x${x##*[x,X]}" >>$CONFIG_H
965 }
966
967 function string () {
968 set_x_info "$2" "$3"
969 echo "$2=\"$x\"" >>$CONFIG
970 echo "#define $2 \"$x\"" >>$CONFIG_H
971 }
972
973 function define_hex () {
974 eval $1="$2"
975 echo "$1=$2" >>$CONFIG
976 echo "#define $1 0x${2##*[x,X]}" >>$CONFIG_H
977 }
978
979 function define_int () {
980 eval $1="$2"
981 echo "$1=$2" >>$CONFIG
982 echo "#define $1 ($2)" >>$CONFIG_H
983 }
984
985 function define_string () {
986 eval $1="$2"
987 echo "$1=\"$2\"" >>$CONFIG
988 echo "#define $1 \"$2\"" >>$CONFIG_H
989 }
990
991 function define_bool () {
992 define_tristate "$1" "$2"
993 }
994
995 function define_tristate () {
996 eval $1="$2"
997
998 case "$2" in
999 y)
1000 echo "$1=y" >>$CONFIG
1001 echo "#define $1 1" >>$CONFIG_H
1002 ;;
1003
1004 n)
1005 echo "# $1 is not set" >>$CONFIG
1006 echo "#undef $1" >>$CONFIG_H
1007 ;;
1008 esac
1009 }
1010
1011 function choice () {
1012 #
1013 # Find the first choice that's already set to 'y'
1014 #
1015 choices="$2"
1016 default="$3"
1017 current=
1018 chosen=
1019
1020 set -- $choices
1021 while [ -n "$2" ]
1022 do
1023 if eval [ "_\$$2" = "_y" ]
1024 then
1025 current=$1
1026 break
1027 fi
1028 shift ; shift
1029 done
1030
1031 #
1032 # Use the default if none were set.
1033 #
1034 : ${current:=$default}
1035
1036 #
1037 # Output all choices (to be compatible with other configs).
1038 #
1039 set -- $choices
1040 while [ -n "$2" ]
1041 do
1042 case "$1" in
1043 "$current"*) if [ -z "$chosen" ]; then
1044 define_bool "$2" "y"
1045 chosen=1
1046 else
1047 define_bool "$2" "n"
1048 fi ;;
1049 *) define_bool "$2" "n" ;;
1050 esac
1051 shift ; shift
1052 done
1053 }
1054
1055 function mainmenu_name () {
1056 :
1057 }
1058
1059 function mainmenu_option () {
1060 comment_is_option=TRUE
1061 }
1062
1063 function endmenu () {
1064 :
1065 }
1066
1067 function comment () {
1068 if [ "$comment_is_option" ]
1069 then
1070 comment_is_option=
1071 echo >>$CONFIG
1072 echo "#" >>$CONFIG
1073 echo "# $1" >>$CONFIG
1074 echo "#" >>$CONFIG
1075
1076 echo >>$CONFIG_H
1077 echo "/*" >>$CONFIG_H
1078 echo " * $1" >>$CONFIG_H
1079 echo " */" >>$CONFIG_H
1080 fi
1081 }
1082
1083 echo -n "."
1084
1085 DEF_CONFIG="${1:-.config}"
1086 DEF_CONFIG_H="include/config.h"
1087
1088 CONFIG=.tmpconfig
1089 CONFIG_H=.tmpconfig.h
1090
1091 echo "#" >$CONFIG
1092 echo "# Automatically generated by make menuconfig: don't edit" >>$CONFIG
1093 echo "#" >>$CONFIG
1094
1095 echo "/*" >$CONFIG_H
1096 echo " * Automatically generated by make menuconfig: don't edit" >>$CONFIG_H
1097 echo " */" >>$CONFIG_H
1098 echo "#define AUTOCONF_INCLUDED" >> $CONFIG_H
1099
1100 echo -n "."
1101 if . $CONFIG_IN >>.menuconfig.log 2>&1
1102 then
1103 if [ "$DEF_CONFIG" = ".config" ]
1104 then
1105 mv $CONFIG_H $DEF_CONFIG_H
1106 fi
1107
1108 if [ -f "$DEF_CONFIG" ]
1109 then
1110 rm -f ${DEF_CONFIG}.old
1111 mv $DEF_CONFIG ${DEF_CONFIG}.old
1112 fi
1113
1114 mv $CONFIG $DEF_CONFIG
1115
1116 return 0
1117 else
1118 return 1
1119 fi
1120}
1121
1122#
1123# Remove temporary files
1124#
1125cleanup () {
1126 cleanup1
1127 cleanup2
1128}
1129
1130cleanup1 () {
1131 rm -f MCmenu* MCradiolists MCdialog.out help.out
1132}
1133
1134cleanup2 () {
1135 rm -f .tmpconfig .tmpconfig.h
1136}
1137
1138set_geometry () {
1139 # Some distributions export these with incorrect values
1140 # which can really screw up some ncurses programs.
1141 LINES= COLUMNS=
1142
1143 ROWS=${1:-24} COLS=${2:-80}
1144
1145 # Just in case the nasty rlogin bug returns.
1146 #
1147 [ $ROWS = 0 ] && ROWS=24
1148 [ $COLS = 0 ] && COLS=80
1149
1150 if [ $ROWS -lt 19 -o $COLS -lt 80 ]
1151 then
1152 echo -e "\n\007Your display is too small to run Menuconfig!"
1153 echo "It must be at least 19 lines by 80 columns."
1154 exit 1
1155 fi
1156
1157 ROWS=$((ROWS-4)) COLS=$((COLS-5))
1158}
1159
1160
1161set_geometry `stty size 2>/dev/null`
1162
1163menu_instructions="\
1164Arrow keys navigate the menu. \
1165Pressing <Enter> selects submenus --->. \
1166Highlighted letters are hotkeys. \
1167Pressing <Y> includes, and <N> excludes. \
1168Press <Esc><Esc> to exit, <?> for Help. \
1169Legend: [*] built-in [ ] excluded "
1170
1171radiolist_instructions="\
1172Use the arrow keys to navigate this window or \
1173press the hotkey of the item you wish to select \
1174followed by the <SPACE BAR>.
1175Press <?> for additional information about this option."
1176
1177inputbox_instructions_int="\
1178Please enter a decimal value. \
1179Fractions will not be accepted. \
1180Use the <TAB> key to move from the input field to the buttons below it."
1181
1182inputbox_instructions_hex="\
1183Please enter a hexadecimal value. \
1184Use the <TAB> key to move from the input field to the buttons below it."
1185
1186inputbox_instructions_string="\
1187Please enter a string value. \
1188Use the <TAB> key to move from the input field to the buttons below it."
1189
1190DIALOG="./scripts/lxdialog/lxdialog"
1191
1192bb_version="${VERSION}"
1193backtitle="BusyBox v$bb_version Configuration"
1194
1195trap "cleanup ; exit 1" 1 2 15
1196
1197
1198#
1199# Locate default files.
1200#
1201CONFIG_IN=./config.in
1202if [ "$1" != "" ] ; then
1203 CONFIG_IN=$1
1204fi
1205
1206DEFAULTS=sysdeps/$TARGET_OS/defconfig
1207if [ -f .config ]; then
1208 DEFAULTS=.config
1209fi
1210
1211if [ -f $DEFAULTS ]
1212then
1213 echo "Using defaults found in" $DEFAULTS
1214 load_config_file $DEFAULTS
1215else
1216 echo "No defaults found"
1217fi
1218
1219
1220# Fresh new log.
1221>.menuconfig.log
1222
1223# Load the functions used by the config.in files.
1224echo -n "Preparing scripts: functions"
1225load_functions
1226
1227if [ ! -e $CONFIG_IN ]
1228then
1229 echo "Your main config.in file ($CONFIG_IN) does not exist"
1230 exit 1
1231fi
1232
1233if [ ! -x $DIALOG ]
1234then
1235 echo "Your lxdialog utility does not exist"
1236 exit 1
1237fi
1238
1239#
1240# Read config.in files and parse them into one shell function per menu.
1241#
1242echo -n ", parsing"
1243parse_config_files $CONFIG_IN
1244
1245echo "done."
1246#
1247# Start the ball rolling from the top.
1248#
1249activate_menu MCmenu0
1250
1251#
1252# All done!
1253#
1254cleanup1
1255
1256#
1257# Confirm and Save
1258#
1259if $DIALOG --backtitle "$backtitle" \
1260 --yesno "Do you wish to save your new BusyBox configuration?" 5 60
1261then
1262 save_configuration
1263 echo
1264 echo
1265 echo "*** End of BusyBox configuration."
1266 echo "*** Check the top-level Makefile for additional configuration."
1267 if [ ! -f .hdepend ] ; then
1268 echo "*** Next, you must run 'make dep'."
1269 else
1270 echo "*** Next, you should run 'make' or 'make install'."
1271 fi
1272 echo
1273else
1274 echo
1275 echo
1276 echo Your BusyBox configuration changes were NOT saved.
1277 echo
1278fi
1279
1280# Remove log if empty.
1281if [ ! -s .menuconfig.log ] ; then
1282 rm -f .menuconfig.log
1283fi
1284
1285exit 0
diff --git a/scripts/depmod.pl b/scripts/depmod.pl
deleted file mode 100755
index e65f07b68..000000000
--- a/scripts/depmod.pl
+++ /dev/null
@@ -1,227 +0,0 @@
1#!/usr/bin/perl -w
2# vi: set ts=4:
3# Copyright (c) 2001 David Schleef <ds@schleef.org>
4# Copyright (c) 2001 Erik Andersen <andersen@lineo.com>
5# Copyright (c) 2001 Stuart Hughes <stuarth@lineo.com>
6# This program is free software; you can redistribute it and/or modify it
7# under the same terms as Perl itself.
8
9# TODO -- use strict mode...
10#use strict;
11
12use Getopt::Long;
13use File::Find;
14
15
16# Set up some default values
17
18my $basedir="";
19my $kernel;
20my $kernelsyms;
21my $stdout=1;
22my $verbose=0;
23
24
25# get command-line options
26
27my %opt;
28
29GetOptions(
30 \%opt,
31 "help|h",
32 "basedir|b=s" => \$basedir,
33 "kernel|k=s" => \$kernel,
34 "kernelsyms|F=s" => \$kernelsyms,
35 "stdout|n" => \$stdout,
36 "verbose|v" => \$verbose,
37);
38
39if (defined $opt{help}) {
40 print
41 "$0 [OPTION]... [basedir]\n",
42 "\t-h --help\t\tShow this help screen\n",
43 "\t-b --basedir\t\tModules base directory (defaults to /lib/modules)\n",
44 "\t-k --kernel\t\tKernel binary for the target\n",
45 "\t-F --kernelsyms\t\tKernel symbol file\n",
46 "\t-n --stdout\t\tWrite to stdout instead of modules.dep\n",
47 "\t-v --verbose\t\tPrint out lots of debugging stuff\n",
48 ;
49 exit 1;
50}
51
52if($basedir !~ m-/lib/modules-) {
53 warn "WARNING: base directory does not match ..../lib/modules\n";
54}
55
56# Find the list of .o files living under $basedir
57#if ($verbose) { printf "Locating all modules\n"; }
58my($file) = "";
59my(@liblist) = ();
60find sub {
61 if ( -f $_ && ! -d $_ ) {
62 $file = $File::Find::name;
63 if ( $file =~ /.o$/ ) {
64 push(@liblist, $file);
65 if ($verbose) { printf "$file\n"; }
66 }
67 }
68}, $basedir;
69if ($verbose) { printf "Finished locating modules\n"; }
70
71foreach $obj ( @liblist, $kernel ){
72 # turn the input file name into a target tag name
73 # vmlinux is a special that is only used to resolve symbols
74 if($obj =~ /vmlinux/) {
75 $tgtname = "vmlinux";
76 } else {
77 ($tgtname) = $obj =~ m-(/lib/modules/.*)$-;
78 }
79
80 warn "MODULE = $tgtname\n" if $verbose;
81
82 # get a list of symbols
83 @output=`nm $obj`;
84 $ksymtab=grep m/ __ksymtab/, @output;
85
86 # gather the exported symbols
87 if($ksymtab){
88 # explicitly exported
89 foreach ( @output ) {
90 / __ksymtab_(.*)$/ and do {
91 warn "sym = $1\n" if $verbose;
92 $exp->{$1} = $tgtname;
93 };
94 }
95 } else {
96 # exporting all symbols
97 foreach ( @output) {
98 / [ABCDGRST] (.*)$/ and do {
99 warn "syma = $1\n" if $verbose;
100 $exp->{$1} = $tgtname;
101 };
102 }
103 }
104 # gather the unresolved symbols
105 foreach ( @output ) {
106 !/ __this_module/ && / U (.*)$/ and do {
107 warn "und = $1\n" if $verbose;
108 push @{$dep->{$tgtname}}, $1;
109 };
110 }
111}
112
113
114# reduce dependancies: remove unresolvable and resolved from vmlinux
115# remove duplicates
116foreach $module (keys %$dep) {
117 $mod->{$module} = {};
118 foreach (@{$dep->{$module}}) {
119 if( $exp->{$_} ) {
120 warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose;
121 next if $exp->{$_} =~ /vmlinux/;
122 $mod->{$module}{$exp->{$_}} = 1;
123 } else {
124 warn "unresolved symbol $_ in file $module\n";
125 }
126 }
127}
128
129# resolve the dependancies for each module
130foreach $module ( keys %$mod ) {
131 print "$module:\t";
132 @sorted = sort bydep keys %{$mod->{$module}};
133 print join(" \\\n\t",@sorted);
134# foreach $m (@sorted ) {
135# print "\t$m\n";
136# }
137 print "\n\n";
138}
139
140sub bydep
141{
142 foreach my $f ( keys %{$mod->{$b}} ) {
143 if($f eq $a) {
144 return 1;
145 }
146 }
147 return -1;
148}
149
150
151
152__END__
153
154=head1 NAME
155
156depmod.pl - a cross platform script to generate kernel module dependency
157 lists which can then be used by modprobe.
158
159=head1 SYNOPSIS
160
161depmod.pl [OPTION]... [FILE]...
162
163Example:
164
165 depmod.pl -F linux/System.map target/lib/modules
166
167=head1 DESCRIPTION
168
169The purpose of this script is to automagically generate a list of of kernel
170module dependancies. This script produces dependancy lists that should be
171identical to the depmod program from the modutils package. Unlike the depmod
172binary, however, depmod.pl is designed to be run on your host system, not
173on your target system.
174
175This script was written by David Schleef <ds@schleef.org> to be used in
176conjunction with the BusyBox modprobe applet.
177
178=head1 OPTIONS
179
180=over 4
181
182=item B<-h --help>
183
184This displays the help message.
185
186=item B<-b --basedir>
187
188The base directory uner which the target's modules will be found. This
189defaults to the /lib/modules directory.
190
191=item B<-k --kernel>
192
193Kernel binary for the target. You must either supply a kernel binary
194or a kernel symbol file (using the -F option).
195
196=item B<-F --kernelsyms>
197
198Kernel symbol file for the target. You must supply either a kernel symbol file
199kernel binary for the target (using the -k option).
200
201=item B<-n --stdout>
202
203Write to stdout instead of modules.dep. This is currently hard coded...
204kernel binary for the target (using the -k option).
205
206=item B<--verbose>
207
208Be verbose (not implemented)
209
210=back
211
212=head1 COPYRIGHT
213
214Copyright (c) 2001 David Schleef <ds@schleef.org>
215Copyright (c) 2001 Erik Andersen <andersen@lineo.com>
216Copyright (c) 2001 Stuart Hughes <stuarth@lineo.com>
217This program is free software; you can redistribute it and/or modify it
218under the same terms as Perl itself.
219
220=head1 AUTHOR
221
222David Schleef <ds@schleef.org>
223
224=cut
225
226# $Id: depmod.pl,v 1.1 2001/07/30 19:32:03 andersen Exp $
227
diff --git a/scripts/inittab b/scripts/inittab
deleted file mode 100644
index 8e7e945b3..000000000
--- a/scripts/inittab
+++ /dev/null
@@ -1,86 +0,0 @@
1# /etc/inittab init(8) configuration for BusyBox
2#
3# Copyright (C) 1999 by Lineo, inc. Written by Erik Andersen
4# <andersen@lineo.com>, <andersee@debian.org>
5#
6#
7# Note, BusyBox init doesn't support runlevels. The runlevels field is
8# completely ignored by BusyBox init. If you want runlevels, use sysvinit.
9#
10#
11# Format for each entry: <id>:<runlevels>:<action>:<process>
12#
13# <id>: WARNING: This field has a non-traditional meaning for BusyBox init!
14#
15# The id field is used by BusyBox init to specify the controlling tty for
16# the specified process to run on. The contents of this field are
17# appended to "/dev/" and used as-is. There is no need for this field to
18# be unique, although if it isn't you may have strange results. If this
19# field is left blank, it is completely ignored. Also note that if
20# BusyBox detects that a serial console is in use, then all entries
21# containing non-empty id fields will _not_ be run. BusyBox init does
22# nothing with utmp. We don't need no stinkin' utmp.
23#
24# <runlevels>: The runlevels field is completely ignored.
25#
26# <action>: Valid actions include: sysinit, respawn, askfirst, wait, once,
27# ctrlaltdel, and shutdown.
28#
29# Note: askfirst acts just like respawn, but before running the specified
30# process it displays the line "Please press Enter to activate this
31# console." and then waits for the user to press enter before starting
32# the specified process.
33#
34# Note: unrecognised actions (like initdefault) will cause init to emit
35# an error message, and then go along with its business.
36#
37# <process>: Specifies the process to be executed and it's command line.
38#
39# Note: BusyBox init works just fine without an inittab. If no inittab is
40# found, it has the following default behavior:
41# ::sysinit:/etc/init.d/rcS
42# ::askfirst:/bin/sh
43# ::ctrlaltdel:/sbin/reboot
44# ::shutdown:/sbin/swapoff -a
45# ::shutdown:/bin/umount -a -r
46# if it detects that /dev/console is _not_ a serial console, it will
47# also run:
48# tty2::askfirst:/bin/sh
49# tty3::askfirst:/bin/sh
50# tty4::askfirst:/bin/sh
51#
52# Boot-time system configuration/initialization script.
53# This is run first except when booting in single-user mode.
54#
55::sysinit:/etc/init.d/rcS
56
57# /bin/sh invocations on selected ttys
58#
59# Note below that we prefix the shell commands with a "-" to indicate to the
60# shell that it is supposed to be a login shell. Normally this is handled by
61# login, but since we are bypassing login in this case, BusyBox lets you do
62# this yourself...
63#
64# Start an "askfirst" shell on the console (whatever that may be)
65::askfirst:-/bin/sh
66# Start an "askfirst" shell on /dev/tty2-4
67tty2::askfirst:-/bin/sh
68tty3::askfirst:-/bin/sh
69tty4::askfirst:-/bin/sh
70
71# /sbin/getty invocations for selected ttys
72tty4::respawn:/sbin/getty 38400 tty5
73tty5::respawn:/sbin/getty 38400 tty6
74
75# Example of how to put a getty on a serial line (for a terminal)
76#::respawn:/sbin/getty -L ttyS0 9600 vt100
77#::respawn:/sbin/getty -L ttyS1 9600 vt100
78#
79# Example how to put a getty on a modem line.
80#::respawn:/sbin/getty 57600 ttyS2
81
82# Stuff to do before rebooting
83::ctrlaltdel:/sbin/reboot
84::shutdown:/bin/umount -a -r
85::shutdown:/sbin/swapoff -a
86
diff --git a/scripts/lxdialog/BIG.FAT.WARNING b/scripts/lxdialog/BIG.FAT.WARNING
new file mode 100644
index 000000000..a8999d82b
--- /dev/null
+++ b/scripts/lxdialog/BIG.FAT.WARNING
@@ -0,0 +1,4 @@
1This is NOT the official version of dialog. This version has been
2significantly modified from the original. It is for use by the Linux
3kernel configuration script. Please do not bother Savio Lam with
4questions about this program.
diff --git a/scripts/lxdialog/Makefile b/scripts/lxdialog/Makefile
new file mode 100644
index 000000000..ed8d17c37
--- /dev/null
+++ b/scripts/lxdialog/Makefile
@@ -0,0 +1,46 @@
1HOSTCFLAGS += -DLOCALE
2LIBS = -lncurses
3
4ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
5 HOSTCFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
6else
7ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h))
8 HOSTCFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
9else
10ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h))
11 HOSTCFLAGS += -DCURSES_LOC="<ncurses.h>"
12else
13 HOSTCFLAGS += -DCURSES_LOC="<curses.h>"
14endif
15endif
16endif
17
18
19OBJS = checklist.o menubox.o textbox.o yesno.o inputbox.o \
20 util.o lxdialog.o msgbox.o
21
22%.o: %.c
23 $(HOSTCC) $(HOSTCFLAGS) -c -o $@ $<
24
25all: ncurses lxdialog
26
27lxdialog: $(OBJS)
28 $(HOSTCC) -o lxdialog $(OBJS) $(LIBS)
29
30ncurses:
31 @echo "main() {}" > lxtemp.c
32 @if $(HOSTCC) -lncurses lxtemp.c ; then \
33 rm -f lxtemp.c a.out; \
34 else \
35 rm -f lxtemp.c; \
36 echo -e "\007" ;\
37 echo ">> Unable to find the Ncurses libraries." ;\
38 echo ">>" ;\
39 echo ">> You must have Ncurses installed in order" ;\
40 echo ">> to use 'make menuconfig'" ;\
41 echo ;\
42 exit 1 ;\
43 fi
44
45clean:
46 rm -f core *.o *~ lxdialog
diff --git a/scripts/lxdialog/Makefile-2.5 b/scripts/lxdialog/Makefile-2.5
new file mode 100644
index 000000000..665205200
--- /dev/null
+++ b/scripts/lxdialog/Makefile-2.5
@@ -0,0 +1,71 @@
1lxdialog-hostcflags += -DLOCALE
2lxdialog-libs = -lncurses
3
4ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
5 lxdialog-hostcflags += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
6else
7ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h))
8 lxdialog-hostcflags += -I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
9else
10ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h))
11 lxdialog-hostcflags += -DCURSES_LOC="<ncurses.h>"
12else
13 lxdialog-hostcflags += -DCURSES_LOC="<curses.h>"
14endif
15endif
16endif
17
18$(tmp_config)lxdialog-ncurses:
19 @mkdir -p $(lxdialog-objtree)
20 @( \
21 cd $(lxdialog-objtree) && \
22 echo "main() {}" > lxtemp.c && \
23 if $(HOSTCC) -lncurses lxtemp.c ; then \
24 rm -f lxtemp.c a.out && \
25 mkdir -p $(@D) && \
26 touch $@; \
27 else \
28 rm -f lxtemp.c; \
29 echo -e "\007" ;\
30 echo ">> Unable to find the Ncurses libraries." ;\
31 echo ">>" ;\
32 echo ">> You must have Ncurses installed in order" ;\
33 echo ">> to use 'make menuconfig'" ;\
34 echo ;\
35 exit 1 ;\
36 fi ; \
37 )
38
39lxdialog-objs := $(lxdialog-objtree)checklist.o $(lxdialog-objtree)menubox.o \
40 $(lxdialog-objtree)textbox.o $(lxdialog-objtree)yesno.o \
41 $(lxdialog-objtree)inputbox.o $(lxdialog-objtree)util.o \
42 $(lxdialog-objtree)lxdialog.o $(lxdialog-objtree)msgbox.o
43
44$(lxdialog-objtree)checklist.o: $(lxdialog-srctree)checklist.c $(tmp_config)lxdialog-ncurses
45 $(HOSTCC) $(HOSTCFLAGS) $(lxdialog-hostcflags) -c -o $@ $<
46
47$(lxdialog-objtree)menubox.o: $(lxdialog-srctree)menubox.c $(tmp_config)lxdialog-ncurses
48 $(HOSTCC) $(HOSTCFLAGS) $(lxdialog-hostcflags) -c -o $@ $<
49
50$(lxdialog-objtree)textbox.o: $(lxdialog-srctree)textbox.c $(tmp_config)lxdialog-ncurses
51 $(HOSTCC) $(HOSTCFLAGS) $(lxdialog-hostcflags) -c -o $@ $<
52
53$(lxdialog-objtree)yesno.o: $(lxdialog-srctree)yesno.c $(tmp_config)lxdialog-ncurses
54 $(HOSTCC) $(HOSTCFLAGS) $(lxdialog-hostcflags) -c -o $@ $<
55
56$(lxdialog-objtree)inputbox.o: $(lxdialog-srctree)inputbox.c $(tmp_config)lxdialog-ncurses
57 $(HOSTCC) $(HOSTCFLAGS) $(lxdialog-hostcflags) -c -o $@ $<
58
59$(lxdialog-objtree)util.o: $(lxdialog-srctree)util.c $(tmp_config)lxdialog-ncurses
60 $(HOSTCC) $(HOSTCFLAGS) $(lxdialog-hostcflags) -c -o $@ $<
61
62$(lxdialog-objtree)lxdialog.o: $(lxdialog-srctree)lxdialog.c $(tmp_config)lxdialog-ncurses
63 $(HOSTCC) $(HOSTCFLAGS) $(lxdialog-hostcflags) -c -o $@ $<
64
65$(lxdialog-objtree)msgbox.o: $(lxdialog-srctree)msgbox.c $(tmp_config)lxdialog-ncurses
66 $(HOSTCC) $(HOSTCFLAGS) $(lxdialog-hostcflags) -c -o $@ $<
67
68$(lxdialog-objtree)lxdialog: $(lxdialog-objs)
69 $(HOSTCC) -o $@ $(lxdialog-objs) $(lxdialog-libs)
70
71MRPROPER += $(lxdialog-objtree)lxdialog
diff --git a/scripts/lxdialog/checklist.c b/scripts/lxdialog/checklist.c
new file mode 100644
index 000000000..4f78688ed
--- /dev/null
+++ b/scripts/lxdialog/checklist.c
@@ -0,0 +1,369 @@
1/*
2 * checklist.c -- implements the checklist box
3 *
4 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
6 * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
7 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include "dialog.h"
25
26static int list_width, check_x, item_x, checkflag;
27
28/*
29 * Print list item
30 */
31static void
32print_item (WINDOW * win, const char *item, int status,
33 int choice, int selected)
34{
35 int i;
36
37 /* Clear 'residue' of last item */
38 wattrset (win, menubox_attr);
39 wmove (win, choice, 0);
40 for (i = 0; i < list_width; i++)
41 waddch (win, ' ');
42
43 wmove (win, choice, check_x);
44 wattrset (win, selected ? check_selected_attr : check_attr);
45 if (checkflag == FLAG_CHECK)
46 wprintw (win, "[%c]", status ? 'X' : ' ');
47 else
48 wprintw (win, "(%c)", status ? 'X' : ' ');
49
50 wattrset (win, selected ? tag_selected_attr : tag_attr);
51 mvwaddch(win, choice, item_x, item[0]);
52 wattrset (win, selected ? item_selected_attr : item_attr);
53 waddstr (win, (char *)item+1);
54 if (selected) {
55 wmove (win, choice, check_x+1);
56 wrefresh (win);
57 }
58}
59
60/*
61 * Print the scroll indicators.
62 */
63static void
64print_arrows (WINDOW * win, int choice, int item_no, int scroll,
65 int y, int x, int height)
66{
67 wmove(win, y, x);
68
69 if (scroll > 0) {
70 wattrset (win, uarrow_attr);
71 waddch (win, ACS_UARROW);
72 waddstr (win, "(-)");
73 }
74 else {
75 wattrset (win, menubox_attr);
76 waddch (win, ACS_HLINE);
77 waddch (win, ACS_HLINE);
78 waddch (win, ACS_HLINE);
79 waddch (win, ACS_HLINE);
80 }
81
82 y = y + height + 1;
83 wmove(win, y, x);
84
85 if ((height < item_no) && (scroll + choice < item_no - 1)) {
86 wattrset (win, darrow_attr);
87 waddch (win, ACS_DARROW);
88 waddstr (win, "(+)");
89 }
90 else {
91 wattrset (win, menubox_border_attr);
92 waddch (win, ACS_HLINE);
93 waddch (win, ACS_HLINE);
94 waddch (win, ACS_HLINE);
95 waddch (win, ACS_HLINE);
96 }
97}
98
99/*
100 * Display the termination buttons
101 */
102static void
103print_buttons( WINDOW *dialog, int height, int width, int selected)
104{
105 int x = width / 2 - 11;
106 int y = height - 2;
107
108 print_button (dialog, "Select", y, x, selected == 0);
109 print_button (dialog, " Help ", y, x + 14, selected == 1);
110
111 wmove(dialog, y, x+1 + 14*selected);
112 wrefresh (dialog);
113}
114
115/*
116 * Display a dialog box with a list of options that can be turned on or off
117 * The `flag' parameter is used to select between radiolist and checklist.
118 */
119int
120dialog_checklist (const char *title, const char *prompt, int height, int width,
121 int list_height, int item_no, const char * const * items, int flag)
122
123{
124 int i, x, y, box_x, box_y;
125 int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
126 WINDOW *dialog, *list;
127
128 checkflag = flag;
129
130 /* Allocate space for storing item on/off status */
131 if ((status = malloc (sizeof (int) * item_no)) == NULL) {
132 endwin ();
133 fprintf (stderr,
134 "\nCan't allocate memory in dialog_checklist().\n");
135 exit (-1);
136 }
137
138 /* Initializes status */
139 for (i = 0; i < item_no; i++) {
140 status[i] = !strcasecmp (items[i * 3 + 2], "on");
141 if (!choice && status[i])
142 choice = i;
143 }
144
145 max_choice = MIN (list_height, item_no);
146
147 /* center dialog box on screen */
148 x = (COLS - width) / 2;
149 y = (LINES - height) / 2;
150
151 draw_shadow (stdscr, y, x, height, width);
152
153 dialog = newwin (height, width, y, x);
154 keypad (dialog, TRUE);
155
156 draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
157 wattrset (dialog, border_attr);
158 mvwaddch (dialog, height-3, 0, ACS_LTEE);
159 for (i = 0; i < width - 2; i++)
160 waddch (dialog, ACS_HLINE);
161 wattrset (dialog, dialog_attr);
162 waddch (dialog, ACS_RTEE);
163
164 if (title != NULL && strlen(title) >= width-2 ) {
165 /* truncate long title -- mec */
166 char * title2 = malloc(width-2+1);
167 memcpy( title2, title, width-2 );
168 title2[width-2] = '\0';
169 title = title2;
170 }
171
172 if (title != NULL) {
173 wattrset (dialog, title_attr);
174 mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
175 waddstr (dialog, (char *)title);
176 waddch (dialog, ' ');
177 }
178
179 wattrset (dialog, dialog_attr);
180 print_autowrap (dialog, prompt, width - 2, 1, 3);
181
182 list_width = width - 6;
183 box_y = height - list_height - 5;
184 box_x = (width - list_width) / 2 - 1;
185
186 /* create new window for the list */
187 list = subwin (dialog, list_height, list_width, y+box_y+1, x+box_x+1);
188
189 keypad (list, TRUE);
190
191 /* draw a box around the list items */
192 draw_box (dialog, box_y, box_x, list_height + 2, list_width + 2,
193 menubox_border_attr, menubox_attr);
194
195 /* Find length of longest item in order to center checklist */
196 check_x = 0;
197 for (i = 0; i < item_no; i++)
198 check_x = MAX (check_x, + strlen (items[i * 3 + 1]) + 4);
199
200 check_x = (list_width - check_x) / 2;
201 item_x = check_x + 4;
202
203 if (choice >= list_height) {
204 scroll = choice - list_height + 1;
205 choice -= scroll;
206 }
207
208 /* Print the list */
209 for (i = 0; i < max_choice; i++) {
210 print_item (list, items[(scroll+i) * 3 + 1],
211 status[i+scroll], i, i == choice);
212 }
213
214 print_arrows(dialog, choice, item_no, scroll,
215 box_y, box_x + check_x + 5, list_height);
216
217 print_buttons(dialog, height, width, 0);
218
219 wnoutrefresh (list);
220 wnoutrefresh (dialog);
221 doupdate ();
222
223 while (key != ESC) {
224 key = wgetch (dialog);
225
226 for (i = 0; i < max_choice; i++)
227 if (toupper(key) == toupper(items[(scroll+i)*3+1][0]))
228 break;
229
230
231 if ( i < max_choice || key == KEY_UP || key == KEY_DOWN ||
232 key == '+' || key == '-' ) {
233 if (key == KEY_UP || key == '-') {
234 if (!choice) {
235 if (!scroll)
236 continue;
237 /* Scroll list down */
238 if (list_height > 1) {
239 /* De-highlight current first item */
240 print_item (list, items[scroll * 3 + 1],
241 status[scroll], 0, FALSE);
242 scrollok (list, TRUE);
243 wscrl (list, -1);
244 scrollok (list, FALSE);
245 }
246 scroll--;
247 print_item (list, items[scroll * 3 + 1],
248 status[scroll], 0, TRUE);
249 wnoutrefresh (list);
250
251 print_arrows(dialog, choice, item_no, scroll,
252 box_y, box_x + check_x + 5, list_height);
253
254 wrefresh (dialog);
255
256 continue; /* wait for another key press */
257 } else
258 i = choice - 1;
259 } else if (key == KEY_DOWN || key == '+') {
260 if (choice == max_choice - 1) {
261 if (scroll + choice >= item_no - 1)
262 continue;
263 /* Scroll list up */
264 if (list_height > 1) {
265 /* De-highlight current last item before scrolling up */
266 print_item (list, items[(scroll + max_choice - 1) * 3 + 1],
267 status[scroll + max_choice - 1],
268 max_choice - 1, FALSE);
269 scrollok (list, TRUE);
270 scroll (list);
271 scrollok (list, FALSE);
272 }
273 scroll++;
274 print_item (list, items[(scroll + max_choice - 1) * 3 + 1],
275 status[scroll + max_choice - 1],
276 max_choice - 1, TRUE);
277 wnoutrefresh (list);
278
279 print_arrows(dialog, choice, item_no, scroll,
280 box_y, box_x + check_x + 5, list_height);
281
282 wrefresh (dialog);
283
284 continue; /* wait for another key press */
285 } else
286 i = choice + 1;
287 }
288 if (i != choice) {
289 /* De-highlight current item */
290 print_item (list, items[(scroll + choice) * 3 + 1],
291 status[scroll + choice], choice, FALSE);
292 /* Highlight new item */
293 choice = i;
294 print_item (list, items[(scroll + choice) * 3 + 1],
295 status[scroll + choice], choice, TRUE);
296 wnoutrefresh (list);
297 wrefresh (dialog);
298 }
299 continue; /* wait for another key press */
300 }
301 switch (key) {
302 case 'H':
303 case 'h':
304 case '?':
305 delwin (dialog);
306 free (status);
307 return 1;
308 case TAB:
309 case KEY_LEFT:
310 case KEY_RIGHT:
311 button = ((key == KEY_LEFT ? --button : ++button) < 0)
312 ? 1 : (button > 1 ? 0 : button);
313
314 print_buttons(dialog, height, width, button);
315 wrefresh (dialog);
316 break;
317 case 'S':
318 case 's':
319 case ' ':
320 case '\n':
321 if (!button) {
322 if (flag == FLAG_CHECK) {
323 status[scroll + choice] = !status[scroll + choice];
324 wmove (list, choice, check_x);
325 wattrset (list, check_selected_attr);
326 wprintw (list, "[%c]", status[scroll + choice] ? 'X' : ' ');
327 } else {
328 if (!status[scroll + choice]) {
329 for (i = 0; i < item_no; i++)
330 status[i] = 0;
331 status[scroll + choice] = 1;
332 for (i = 0; i < max_choice; i++)
333 print_item (list, items[(scroll + i) * 3 + 1],
334 status[scroll + i], i, i == choice);
335 }
336 }
337 wnoutrefresh (list);
338 wrefresh (dialog);
339
340 for (i = 0; i < item_no; i++) {
341 if (status[i]) {
342 if (flag == FLAG_CHECK) {
343 fprintf (stderr, "\"%s\" ", items[i * 3]);
344 } else {
345 fprintf (stderr, "%s", items[i * 3]);
346 }
347
348 }
349 }
350 }
351 delwin (dialog);
352 free (status);
353 return button;
354 case 'X':
355 case 'x':
356 key = ESC;
357 case ESC:
358 break;
359 }
360
361 /* Now, update everything... */
362 doupdate ();
363 }
364
365
366 delwin (dialog);
367 free (status);
368 return -1; /* ESC pressed */
369}
diff --git a/scripts/lxdialog/colors.h b/scripts/lxdialog/colors.h
new file mode 100644
index 000000000..d34dd37c6
--- /dev/null
+++ b/scripts/lxdialog/colors.h
@@ -0,0 +1,161 @@
1/*
2 * colors.h -- color attribute definitions
3 *
4 * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22/*
23 * Default color definitions
24 *
25 * *_FG = foreground
26 * *_BG = background
27 * *_HL = highlight?
28 */
29#define SCREEN_FG COLOR_CYAN
30#define SCREEN_BG COLOR_BLUE
31#define SCREEN_HL TRUE
32
33#define SHADOW_FG COLOR_BLACK
34#define SHADOW_BG COLOR_BLACK
35#define SHADOW_HL TRUE
36
37#define DIALOG_FG COLOR_BLACK
38#define DIALOG_BG COLOR_WHITE
39#define DIALOG_HL FALSE
40
41#define TITLE_FG COLOR_YELLOW
42#define TITLE_BG COLOR_WHITE
43#define TITLE_HL TRUE
44
45#define BORDER_FG COLOR_WHITE
46#define BORDER_BG COLOR_WHITE
47#define BORDER_HL TRUE
48
49#define BUTTON_ACTIVE_FG COLOR_WHITE
50#define BUTTON_ACTIVE_BG COLOR_BLUE
51#define BUTTON_ACTIVE_HL TRUE
52
53#define BUTTON_INACTIVE_FG COLOR_BLACK
54#define BUTTON_INACTIVE_BG COLOR_WHITE
55#define BUTTON_INACTIVE_HL FALSE
56
57#define BUTTON_KEY_ACTIVE_FG COLOR_WHITE
58#define BUTTON_KEY_ACTIVE_BG COLOR_BLUE
59#define BUTTON_KEY_ACTIVE_HL TRUE
60
61#define BUTTON_KEY_INACTIVE_FG COLOR_RED
62#define BUTTON_KEY_INACTIVE_BG COLOR_WHITE
63#define BUTTON_KEY_INACTIVE_HL FALSE
64
65#define BUTTON_LABEL_ACTIVE_FG COLOR_YELLOW
66#define BUTTON_LABEL_ACTIVE_BG COLOR_BLUE
67#define BUTTON_LABEL_ACTIVE_HL TRUE
68
69#define BUTTON_LABEL_INACTIVE_FG COLOR_BLACK
70#define BUTTON_LABEL_INACTIVE_BG COLOR_WHITE
71#define BUTTON_LABEL_INACTIVE_HL TRUE
72
73#define INPUTBOX_FG COLOR_BLACK
74#define INPUTBOX_BG COLOR_WHITE
75#define INPUTBOX_HL FALSE
76
77#define INPUTBOX_BORDER_FG COLOR_BLACK
78#define INPUTBOX_BORDER_BG COLOR_WHITE
79#define INPUTBOX_BORDER_HL FALSE
80
81#define SEARCHBOX_FG COLOR_BLACK
82#define SEARCHBOX_BG COLOR_WHITE
83#define SEARCHBOX_HL FALSE
84
85#define SEARCHBOX_TITLE_FG COLOR_YELLOW
86#define SEARCHBOX_TITLE_BG COLOR_WHITE
87#define SEARCHBOX_TITLE_HL TRUE
88
89#define SEARCHBOX_BORDER_FG COLOR_WHITE
90#define SEARCHBOX_BORDER_BG COLOR_WHITE
91#define SEARCHBOX_BORDER_HL TRUE
92
93#define POSITION_INDICATOR_FG COLOR_YELLOW
94#define POSITION_INDICATOR_BG COLOR_WHITE
95#define POSITION_INDICATOR_HL TRUE
96
97#define MENUBOX_FG COLOR_BLACK
98#define MENUBOX_BG COLOR_WHITE
99#define MENUBOX_HL FALSE
100
101#define MENUBOX_BORDER_FG COLOR_WHITE
102#define MENUBOX_BORDER_BG COLOR_WHITE
103#define MENUBOX_BORDER_HL TRUE
104
105#define ITEM_FG COLOR_BLACK
106#define ITEM_BG COLOR_WHITE
107#define ITEM_HL FALSE
108
109#define ITEM_SELECTED_FG COLOR_WHITE
110#define ITEM_SELECTED_BG COLOR_BLUE
111#define ITEM_SELECTED_HL TRUE
112
113#define TAG_FG COLOR_YELLOW
114#define TAG_BG COLOR_WHITE
115#define TAG_HL TRUE
116
117#define TAG_SELECTED_FG COLOR_YELLOW
118#define TAG_SELECTED_BG COLOR_BLUE
119#define TAG_SELECTED_HL TRUE
120
121#define TAG_KEY_FG COLOR_YELLOW
122#define TAG_KEY_BG COLOR_WHITE
123#define TAG_KEY_HL TRUE
124
125#define TAG_KEY_SELECTED_FG COLOR_YELLOW
126#define TAG_KEY_SELECTED_BG COLOR_BLUE
127#define TAG_KEY_SELECTED_HL TRUE
128
129#define CHECK_FG COLOR_BLACK
130#define CHECK_BG COLOR_WHITE
131#define CHECK_HL FALSE
132
133#define CHECK_SELECTED_FG COLOR_WHITE
134#define CHECK_SELECTED_BG COLOR_BLUE
135#define CHECK_SELECTED_HL TRUE
136
137#define UARROW_FG COLOR_GREEN
138#define UARROW_BG COLOR_WHITE
139#define UARROW_HL TRUE
140
141#define DARROW_FG COLOR_GREEN
142#define DARROW_BG COLOR_WHITE
143#define DARROW_HL TRUE
144
145/* End of default color definitions */
146
147#define C_ATTR(x,y) ((x ? A_BOLD : 0) | COLOR_PAIR((y)))
148#define COLOR_NAME_LEN 10
149#define COLOR_COUNT 8
150
151/*
152 * Global variables
153 */
154
155typedef struct {
156 char name[COLOR_NAME_LEN];
157 int value;
158} color_names_st;
159
160extern color_names_st color_names[];
161extern int color_table[][3];
diff --git a/scripts/lxdialog/dialog.h b/scripts/lxdialog/dialog.h
new file mode 100644
index 000000000..0e30d00d0
--- /dev/null
+++ b/scripts/lxdialog/dialog.h
@@ -0,0 +1,184 @@
1
2/*
3 * dialog.h -- common declarations for all dialog modules
4 *
5 * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <sys/types.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <ctype.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include CURSES_LOC
30
31/*
32 * Colors in ncurses 1.9.9e do not work properly since foreground and
33 * background colors are OR'd rather than separately masked. This version
34 * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
35 * with standard curses. The simplest fix (to make this work with standard
36 * curses) uses the wbkgdset() function, not used in the original hack.
37 * Turn it off if we're building with 1.9.9e, since it just confuses things.
38 */
39#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
40#define OLD_NCURSES 1
41#undef wbkgdset
42#define wbkgdset(w,p) /*nothing*/
43#else
44#define OLD_NCURSES 0
45#endif
46
47#define TR(params) _tracef params
48
49#define ESC 27
50#define TAB 9
51#define MAX_LEN 2048
52#define BUF_SIZE (10*1024)
53#define MIN(x,y) (x < y ? x : y)
54#define MAX(x,y) (x > y ? x : y)
55
56
57#ifndef ACS_ULCORNER
58#define ACS_ULCORNER '+'
59#endif
60#ifndef ACS_LLCORNER
61#define ACS_LLCORNER '+'
62#endif
63#ifndef ACS_URCORNER
64#define ACS_URCORNER '+'
65#endif
66#ifndef ACS_LRCORNER
67#define ACS_LRCORNER '+'
68#endif
69#ifndef ACS_HLINE
70#define ACS_HLINE '-'
71#endif
72#ifndef ACS_VLINE
73#define ACS_VLINE '|'
74#endif
75#ifndef ACS_LTEE
76#define ACS_LTEE '+'
77#endif
78#ifndef ACS_RTEE
79#define ACS_RTEE '+'
80#endif
81#ifndef ACS_UARROW
82#define ACS_UARROW '^'
83#endif
84#ifndef ACS_DARROW
85#define ACS_DARROW 'v'
86#endif
87
88/*
89 * Attribute names
90 */
91#define screen_attr attributes[0]
92#define shadow_attr attributes[1]
93#define dialog_attr attributes[2]
94#define title_attr attributes[3]
95#define border_attr attributes[4]
96#define button_active_attr attributes[5]
97#define button_inactive_attr attributes[6]
98#define button_key_active_attr attributes[7]
99#define button_key_inactive_attr attributes[8]
100#define button_label_active_attr attributes[9]
101#define button_label_inactive_attr attributes[10]
102#define inputbox_attr attributes[11]
103#define inputbox_border_attr attributes[12]
104#define searchbox_attr attributes[13]
105#define searchbox_title_attr attributes[14]
106#define searchbox_border_attr attributes[15]
107#define position_indicator_attr attributes[16]
108#define menubox_attr attributes[17]
109#define menubox_border_attr attributes[18]
110#define item_attr attributes[19]
111#define item_selected_attr attributes[20]
112#define tag_attr attributes[21]
113#define tag_selected_attr attributes[22]
114#define tag_key_attr attributes[23]
115#define tag_key_selected_attr attributes[24]
116#define check_attr attributes[25]
117#define check_selected_attr attributes[26]
118#define uarrow_attr attributes[27]
119#define darrow_attr attributes[28]
120
121/* number of attributes */
122#define ATTRIBUTE_COUNT 29
123
124/*
125 * Global variables
126 */
127extern bool use_colors;
128extern bool use_shadow;
129
130extern chtype attributes[];
131
132extern const char *backtitle;
133
134/*
135 * Function prototypes
136 */
137extern void create_rc (const char *filename);
138extern int parse_rc (void);
139
140
141void init_dialog (void);
142void end_dialog (void);
143void attr_clear (WINDOW * win, int height, int width, chtype attr);
144void dialog_clear (void);
145void color_setup (void);
146void print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x);
147void print_button (WINDOW * win, const char *label, int y, int x, int selected);
148void draw_box (WINDOW * win, int y, int x, int height, int width, chtype box,
149 chtype border);
150void draw_shadow (WINDOW * win, int y, int x, int height, int width);
151
152int first_alpha (const char *string, const char *exempt);
153int dialog_yesno (const char *title, const char *prompt, int height, int width);
154int dialog_msgbox (const char *title, const char *prompt, int height,
155 int width, int pause);
156int dialog_textbox (const char *title, const char *file, int height, int width);
157int dialog_menu (const char *title, const char *prompt, int height, int width,
158 int menu_height, const char *choice, int item_no,
159 const char * const * items);
160int dialog_checklist (const char *title, const char *prompt, int height,
161 int width, int list_height, int item_no,
162 const char * const * items, int flag);
163extern unsigned char dialog_input_result[];
164int dialog_inputbox (const char *title, const char *prompt, int height,
165 int width, const char *init);
166
167/*
168 * This is the base for fictitious keys, which activate
169 * the buttons.
170 *
171 * Mouse-generated keys are the following:
172 * -- the first 32 are used as numbers, in addition to '0'-'9'
173 * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
174 * -- uppercase chars are used to invoke the button (M_EVENT + 'O')
175 */
176#define M_EVENT (KEY_MAX+1)
177
178
179/*
180 * The `flag' parameter in checklist is used to select between
181 * radiolist and checklist
182 */
183#define FLAG_CHECK 1
184#define FLAG_RADIO 0
diff --git a/scripts/lxdialog/inputbox.c b/scripts/lxdialog/inputbox.c
new file mode 100644
index 000000000..fa7bebc69
--- /dev/null
+++ b/scripts/lxdialog/inputbox.c
@@ -0,0 +1,240 @@
1/*
2 * inputbox.c -- implements the input box
3 *
4 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "dialog.h"
23
24unsigned char dialog_input_result[MAX_LEN + 1];
25
26/*
27 * Print the termination buttons
28 */
29static void
30print_buttons(WINDOW *dialog, int height, int width, int selected)
31{
32 int x = width / 2 - 11;
33 int y = height - 2;
34
35 print_button (dialog, " Ok ", y, x, selected==0);
36 print_button (dialog, " Help ", y, x + 14, selected==1);
37
38 wmove(dialog, y, x+1+14*selected);
39 wrefresh(dialog);
40}
41
42/*
43 * Display a dialog box for inputing a string
44 */
45int
46dialog_inputbox (const char *title, const char *prompt, int height, int width,
47 const char *init)
48{
49 int i, x, y, box_y, box_x, box_width;
50 int input_x = 0, scroll = 0, key = 0, button = -1;
51 unsigned char *instr = dialog_input_result;
52 WINDOW *dialog;
53
54 /* center dialog box on screen */
55 x = (COLS - width) / 2;
56 y = (LINES - height) / 2;
57
58
59 draw_shadow (stdscr, y, x, height, width);
60
61 dialog = newwin (height, width, y, x);
62 keypad (dialog, TRUE);
63
64 draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
65 wattrset (dialog, border_attr);
66 mvwaddch (dialog, height-3, 0, ACS_LTEE);
67 for (i = 0; i < width - 2; i++)
68 waddch (dialog, ACS_HLINE);
69 wattrset (dialog, dialog_attr);
70 waddch (dialog, ACS_RTEE);
71
72 if (title != NULL && strlen(title) >= width-2 ) {
73 /* truncate long title -- mec */
74 char * title2 = malloc(width-2+1);
75 memcpy( title2, title, width-2 );
76 title2[width-2] = '\0';
77 title = title2;
78 }
79
80 if (title != NULL) {
81 wattrset (dialog, title_attr);
82 mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
83 waddstr (dialog, (char *)title);
84 waddch (dialog, ' ');
85 }
86
87 wattrset (dialog, dialog_attr);
88 print_autowrap (dialog, prompt, width - 2, 1, 3);
89
90 /* Draw the input field box */
91 box_width = width - 6;
92 getyx (dialog, y, x);
93 box_y = y + 2;
94 box_x = (width - box_width) / 2;
95 draw_box (dialog, y + 1, box_x - 1, 3, box_width + 2,
96 border_attr, dialog_attr);
97
98 print_buttons(dialog, height, width, 0);
99
100 /* Set up the initial value */
101 wmove (dialog, box_y, box_x);
102 wattrset (dialog, inputbox_attr);
103
104 if (!init)
105 instr[0] = '\0';
106 else
107 strcpy (instr, init);
108
109 input_x = strlen (instr);
110
111 if (input_x >= box_width) {
112 scroll = input_x - box_width + 1;
113 input_x = box_width - 1;
114 for (i = 0; i < box_width - 1; i++)
115 waddch (dialog, instr[scroll + i]);
116 } else
117 waddstr (dialog, instr);
118
119 wmove (dialog, box_y, box_x + input_x);
120
121 wrefresh (dialog);
122
123 while (key != ESC) {
124 key = wgetch (dialog);
125
126 if (button == -1) { /* Input box selected */
127 switch (key) {
128 case TAB:
129 case KEY_UP:
130 case KEY_DOWN:
131 break;
132 case KEY_LEFT:
133 continue;
134 case KEY_RIGHT:
135 continue;
136 case KEY_BACKSPACE:
137 case 127:
138 if (input_x || scroll) {
139 wattrset (dialog, inputbox_attr);
140 if (!input_x) {
141 scroll = scroll < box_width - 1 ?
142 0 : scroll - (box_width - 1);
143 wmove (dialog, box_y, box_x);
144 for (i = 0; i < box_width; i++)
145 waddch (dialog, instr[scroll + input_x + i] ?
146 instr[scroll + input_x + i] : ' ');
147 input_x = strlen (instr) - scroll;
148 } else
149 input_x--;
150 instr[scroll + input_x] = '\0';
151 mvwaddch (dialog, box_y, input_x + box_x, ' ');
152 wmove (dialog, box_y, input_x + box_x);
153 wrefresh (dialog);
154 }
155 continue;
156 default:
157 if (key < 0x100 && isprint (key)) {
158 if (scroll + input_x < MAX_LEN) {
159 wattrset (dialog, inputbox_attr);
160 instr[scroll + input_x] = key;
161 instr[scroll + input_x + 1] = '\0';
162 if (input_x == box_width - 1) {
163 scroll++;
164 wmove (dialog, box_y, box_x);
165 for (i = 0; i < box_width - 1; i++)
166 waddch (dialog, instr[scroll + i]);
167 } else {
168 wmove (dialog, box_y, input_x++ + box_x);
169 waddch (dialog, key);
170 }
171 wrefresh (dialog);
172 } else
173 flash (); /* Alarm user about overflow */
174 continue;
175 }
176 }
177 }
178 switch (key) {
179 case 'O':
180 case 'o':
181 delwin (dialog);
182 return 0;
183 case 'H':
184 case 'h':
185 delwin (dialog);
186 return 1;
187 case KEY_UP:
188 case KEY_LEFT:
189 switch (button) {
190 case -1:
191 button = 1; /* Indicates "Cancel" button is selected */
192 print_buttons(dialog, height, width, 1);
193 break;
194 case 0:
195 button = -1; /* Indicates input box is selected */
196 print_buttons(dialog, height, width, 0);
197 wmove (dialog, box_y, box_x + input_x);
198 wrefresh (dialog);
199 break;
200 case 1:
201 button = 0; /* Indicates "OK" button is selected */
202 print_buttons(dialog, height, width, 0);
203 break;
204 }
205 break;
206 case TAB:
207 case KEY_DOWN:
208 case KEY_RIGHT:
209 switch (button) {
210 case -1:
211 button = 0; /* Indicates "OK" button is selected */
212 print_buttons(dialog, height, width, 0);
213 break;
214 case 0:
215 button = 1; /* Indicates "Cancel" button is selected */
216 print_buttons(dialog, height, width, 1);
217 break;
218 case 1:
219 button = -1; /* Indicates input box is selected */
220 print_buttons(dialog, height, width, 0);
221 wmove (dialog, box_y, box_x + input_x);
222 wrefresh (dialog);
223 break;
224 }
225 break;
226 case ' ':
227 case '\n':
228 delwin (dialog);
229 return (button == -1 ? 0 : button);
230 case 'X':
231 case 'x':
232 key = ESC;
233 case ESC:
234 break;
235 }
236 }
237
238 delwin (dialog);
239 return -1; /* ESC pressed */
240}
diff --git a/scripts/lxdialog/lxdialog.c b/scripts/lxdialog/lxdialog.c
new file mode 100644
index 000000000..6f4c1fd4e
--- /dev/null
+++ b/scripts/lxdialog/lxdialog.c
@@ -0,0 +1,226 @@
1/*
2 * dialog - Display simple dialog boxes from shell scripts
3 *
4 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "dialog.h"
23
24static void Usage (const char *name);
25
26typedef int (jumperFn) (const char *title, int argc, const char * const * argv);
27
28struct Mode {
29 char *name;
30 int argmin, argmax, argmod;
31 jumperFn *jumper;
32};
33
34jumperFn j_menu, j_checklist, j_radiolist, j_yesno, j_textbox, j_inputbox;
35jumperFn j_msgbox, j_infobox;
36
37static struct Mode modes[] =
38{
39 {"--menu", 9, 0, 3, j_menu},
40 {"--checklist", 9, 0, 3, j_checklist},
41 {"--radiolist", 9, 0, 3, j_radiolist},
42 {"--yesno", 5,5,1, j_yesno},
43 {"--textbox", 5,5,1, j_textbox},
44 {"--inputbox", 5, 6, 1, j_inputbox},
45 {"--msgbox", 5, 5, 1, j_msgbox},
46 {"--infobox", 5, 5, 1, j_infobox},
47 {NULL, 0, 0, 0, NULL}
48};
49
50static struct Mode *modePtr;
51
52#ifdef LOCALE
53#include <locale.h>
54#endif
55
56int
57main (int argc, const char * const * argv)
58{
59 int offset = 0, clear_screen = 0, end_common_opts = 0, retval;
60 const char *title = NULL;
61
62#ifdef LOCALE
63 (void) setlocale (LC_ALL, "");
64#endif
65
66#ifdef TRACE
67 trace(TRACE_CALLS|TRACE_UPDATE);
68#endif
69 if (argc < 2) {
70 Usage (argv[0]);
71 exit (-1);
72 }
73
74 while (offset < argc - 1 && !end_common_opts) { /* Common options */
75 if (!strcmp (argv[offset + 1], "--title")) {
76 if (argc - offset < 3 || title != NULL) {
77 Usage (argv[0]);
78 exit (-1);
79 } else {
80 title = argv[offset + 2];
81 offset += 2;
82 }
83 } else if (!strcmp (argv[offset + 1], "--backtitle")) {
84 if (backtitle != NULL) {
85 Usage (argv[0]);
86 exit (-1);
87 } else {
88 backtitle = argv[offset + 2];
89 offset += 2;
90 }
91 } else if (!strcmp (argv[offset + 1], "--clear")) {
92 if (clear_screen) { /* Hey, "--clear" can't appear twice! */
93 Usage (argv[0]);
94 exit (-1);
95 } else if (argc == 2) { /* we only want to clear the screen */
96 init_dialog ();
97 refresh (); /* init_dialog() will clear the screen for us */
98 end_dialog ();
99 return 0;
100 } else {
101 clear_screen = 1;
102 offset++;
103 }
104 } else /* no more common options */
105 end_common_opts = 1;
106 }
107
108 if (argc - 1 == offset) { /* no more options */
109 Usage (argv[0]);
110 exit (-1);
111 }
112 /* use a table to look for the requested mode, to avoid code duplication */
113
114 for (modePtr = modes; modePtr->name; modePtr++) /* look for the mode */
115 if (!strcmp (argv[offset + 1], modePtr->name))
116 break;
117
118 if (!modePtr->name)
119 Usage (argv[0]);
120 if (argc - offset < modePtr->argmin)
121 Usage (argv[0]);
122 if (modePtr->argmax && argc - offset > modePtr->argmax)
123 Usage (argv[0]);
124
125
126
127 init_dialog ();
128 retval = (*(modePtr->jumper)) (title, argc - offset, argv + offset);
129
130 if (clear_screen) { /* clear screen before exit */
131 attr_clear (stdscr, LINES, COLS, screen_attr);
132 refresh ();
133 }
134 end_dialog();
135
136 exit (retval);
137}
138
139/*
140 * Print program usage
141 */
142static void
143Usage (const char *name)
144{
145 fprintf (stderr, "\
146\ndialog, by Savio Lam (lam836@cs.cuhk.hk).\
147\n patched by Stuart Herbert (S.Herbert@shef.ac.uk)\
148\n modified/gutted for use as a Linux kernel config tool by \
149\n William Roadcap (roadcapw@cfw.com)\
150\n\
151\n* Display dialog boxes from shell scripts *\
152\n\
153\nUsage: %s --clear\
154\n %s [--title <title>] [--backtitle <backtitle>] --clear <Box options>\
155\n\
156\nBox options:\
157\n\
158\n --menu <text> <height> <width> <menu height> <tag1> <item1>...\
159\n --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...\
160\n --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...\
161\n --textbox <file> <height> <width>\
162\n --inputbox <text> <height> <width> [<init>]\
163\n --yesno <text> <height> <width>\
164\n", name, name);
165 exit (-1);
166}
167
168/*
169 * These are the program jumpers
170 */
171
172int
173j_menu (const char *t, int ac, const char * const * av)
174{
175 return dialog_menu (t, av[2], atoi (av[3]), atoi (av[4]),
176 atoi (av[5]), av[6], (ac - 6) / 2, av + 7);
177}
178
179int
180j_checklist (const char *t, int ac, const char * const * av)
181{
182 return dialog_checklist (t, av[2], atoi (av[3]), atoi (av[4]),
183 atoi (av[5]), (ac - 6) / 3, av + 6, FLAG_CHECK);
184}
185
186int
187j_radiolist (const char *t, int ac, const char * const * av)
188{
189 return dialog_checklist (t, av[2], atoi (av[3]), atoi (av[4]),
190 atoi (av[5]), (ac - 6) / 3, av + 6, FLAG_RADIO);
191}
192
193int
194j_textbox (const char *t, int ac, const char * const * av)
195{
196 return dialog_textbox (t, av[2], atoi (av[3]), atoi (av[4]));
197}
198
199int
200j_yesno (const char *t, int ac, const char * const * av)
201{
202 return dialog_yesno (t, av[2], atoi (av[3]), atoi (av[4]));
203}
204
205int
206j_inputbox (const char *t, int ac, const char * const * av)
207{
208 int ret = dialog_inputbox (t, av[2], atoi (av[3]), atoi (av[4]),
209 ac == 6 ? av[5] : (char *) NULL);
210 if (ret == 0)
211 fprintf(stderr, dialog_input_result);
212 return ret;
213}
214
215int
216j_msgbox (const char *t, int ac, const char * const * av)
217{
218 return dialog_msgbox (t, av[2], atoi (av[3]), atoi (av[4]), 1);
219}
220
221int
222j_infobox (const char *t, int ac, const char * const * av)
223{
224 return dialog_msgbox (t, av[2], atoi (av[3]), atoi (av[4]), 0);
225}
226
diff --git a/scripts/lxdialog/menubox.c b/scripts/lxdialog/menubox.c
new file mode 100644
index 000000000..a234e9f3b
--- /dev/null
+++ b/scripts/lxdialog/menubox.c
@@ -0,0 +1,443 @@
1/*
2 * menubox.c -- implements the menu box
3 *
4 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22/*
23 * Changes by Clifford Wolf (god@clifford.at)
24 *
25 * [ 1998-06-13 ]
26 *
27 * *) A bugfix for the Page-Down problem
28 *
29 * *) Formerly when I used Page Down and Page Up, the cursor would be set
30 * to the first position in the menu box. Now lxdialog is a bit
31 * smarter and works more like other menu systems (just have a look at
32 * it).
33 *
34 * *) Formerly if I selected something my scrolling would be broken because
35 * lxdialog is re-invoked by the Menuconfig shell script, can't
36 * remember the last scrolling position, and just sets it so that the
37 * cursor is at the bottom of the box. Now it writes the temporary file
38 * lxdialog.scrltmp which contains this information. The file is
39 * deleted by lxdialog if the user leaves a submenu or enters a new
40 * one, but it would be nice if Menuconfig could make another "rm -f"
41 * just to be sure. Just try it out - you will recognise a difference!
42 *
43 * [ 1998-06-14 ]
44 *
45 * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
46 * and menus change their size on the fly.
47 *
48 * *) If for some reason the last scrolling position is not saved by
49 * lxdialog, it sets the scrolling so that the selected item is in the
50 * middle of the menu box, not at the bottom.
51 *
52 * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
53 * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
54 * This fixes a bug in Menuconfig where using ' ' to descend into menus
55 * would leave mis-synchronized lxdialog.scrltmp files lying around,
56 * fscanf would read in 'scroll', and eventually that value would get used.
57 */
58
59#include "dialog.h"
60
61static int menu_width, item_x;
62
63/*
64 * Print menu item
65 */
66static void
67print_item (WINDOW * win, const char *item, int choice, int selected, int hotkey)
68{
69 int j;
70 char menu_item[menu_width+1];
71
72 strncpy(menu_item, item, menu_width);
73 menu_item[menu_width] = 0;
74 j = first_alpha(menu_item, "YyNnMm");
75
76 /* Clear 'residue' of last item */
77 wattrset (win, menubox_attr);
78 wmove (win, choice, 0);
79#if OLD_NCURSES
80 {
81 int i;
82 for (i = 0; i < menu_width; i++)
83 waddch (win, ' ');
84 }
85#else
86 wclrtoeol(win);
87#endif
88 wattrset (win, selected ? item_selected_attr : item_attr);
89 mvwaddstr (win, choice, item_x, menu_item);
90 if (hotkey) {
91 wattrset (win, selected ? tag_key_selected_attr : tag_key_attr);
92 mvwaddch(win, choice, item_x+j, menu_item[j]);
93 }
94 if (selected) {
95 wmove (win, choice, item_x+1);
96 wrefresh (win);
97 }
98}
99
100/*
101 * Print the scroll indicators.
102 */
103static void
104print_arrows (WINDOW * win, int item_no, int scroll,
105 int y, int x, int height)
106{
107 int cur_y, cur_x;
108
109 getyx(win, cur_y, cur_x);
110
111 wmove(win, y, x);
112
113 if (scroll > 0) {
114 wattrset (win, uarrow_attr);
115 waddch (win, ACS_UARROW);
116 waddstr (win, "(-)");
117 }
118 else {
119 wattrset (win, menubox_attr);
120 waddch (win, ACS_HLINE);
121 waddch (win, ACS_HLINE);
122 waddch (win, ACS_HLINE);
123 waddch (win, ACS_HLINE);
124 }
125
126 y = y + height + 1;
127 wmove(win, y, x);
128
129 if ((height < item_no) && (scroll + height < item_no)) {
130 wattrset (win, darrow_attr);
131 waddch (win, ACS_DARROW);
132 waddstr (win, "(+)");
133 }
134 else {
135 wattrset (win, menubox_border_attr);
136 waddch (win, ACS_HLINE);
137 waddch (win, ACS_HLINE);
138 waddch (win, ACS_HLINE);
139 waddch (win, ACS_HLINE);
140 }
141
142 wmove(win, cur_y, cur_x);
143}
144
145/*
146 * Display the termination buttons.
147 */
148static void
149print_buttons (WINDOW *win, int height, int width, int selected)
150{
151 int x = width / 2 - 16;
152 int y = height - 2;
153
154 print_button (win, "Select", y, x, selected == 0);
155 print_button (win, " Exit ", y, x + 12, selected == 1);
156 print_button (win, " Help ", y, x + 24, selected == 2);
157
158 wmove(win, y, x+1+12*selected);
159 wrefresh (win);
160}
161
162/*
163 * Display a menu for choosing among a number of options
164 */
165int
166dialog_menu (const char *title, const char *prompt, int height, int width,
167 int menu_height, const char *current, int item_no,
168 const char * const * items)
169
170{
171 int i, j, x, y, box_x, box_y;
172 int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice;
173 WINDOW *dialog, *menu;
174 FILE *f;
175
176 max_choice = MIN (menu_height, item_no);
177
178 /* center dialog box on screen */
179 x = (COLS - width) / 2;
180 y = (LINES - height) / 2;
181
182 draw_shadow (stdscr, y, x, height, width);
183
184 dialog = newwin (height, width, y, x);
185 keypad (dialog, TRUE);
186
187 draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
188 wattrset (dialog, border_attr);
189 mvwaddch (dialog, height - 3, 0, ACS_LTEE);
190 for (i = 0; i < width - 2; i++)
191 waddch (dialog, ACS_HLINE);
192 wattrset (dialog, dialog_attr);
193 wbkgdset (dialog, dialog_attr & A_COLOR);
194 waddch (dialog, ACS_RTEE);
195
196 if (title != NULL && strlen(title) >= width-2 ) {
197 /* truncate long title -- mec */
198 char * title2 = malloc(width-2+1);
199 memcpy( title2, title, width-2 );
200 title2[width-2] = '\0';
201 title = title2;
202 }
203
204 if (title != NULL) {
205 wattrset (dialog, title_attr);
206 mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
207 waddstr (dialog, (char *)title);
208 waddch (dialog, ' ');
209 }
210
211 wattrset (dialog, dialog_attr);
212 print_autowrap (dialog, prompt, width - 2, 1, 3);
213
214 menu_width = width - 6;
215 box_y = height - menu_height - 5;
216 box_x = (width - menu_width) / 2 - 1;
217
218 /* create new window for the menu */
219 menu = subwin (dialog, menu_height, menu_width,
220 y + box_y + 1, x + box_x + 1);
221 keypad (menu, TRUE);
222
223 /* draw a box around the menu items */
224 draw_box (dialog, box_y, box_x, menu_height + 2, menu_width + 2,
225 menubox_border_attr, menubox_attr);
226
227 /*
228 * Find length of longest item in order to center menu.
229 * Set 'choice' to default item.
230 */
231 item_x = 0;
232 for (i = 0; i < item_no; i++) {
233 item_x = MAX (item_x, MIN(menu_width, strlen (items[i * 2 + 1]) + 2));
234 if (strcmp(current, items[i*2]) == 0) choice = i;
235 }
236
237 item_x = (menu_width - item_x) / 2;
238
239 /* get the scroll info from the temp file */
240 if ( (f=fopen("lxdialog.scrltmp","r")) != NULL ) {
241 if ( (fscanf(f,"%d\n",&scroll) == 1) && (scroll <= choice) &&
242 (scroll+max_choice > choice) && (scroll >= 0) &&
243 (scroll+max_choice <= item_no) ) {
244 first_item = scroll;
245 choice = choice - scroll;
246 fclose(f);
247 } else {
248 scroll=0;
249 remove("lxdialog.scrltmp");
250 fclose(f);
251 f=NULL;
252 }
253 }
254 if ( (choice >= max_choice) || (f==NULL && choice >= max_choice/2) ) {
255 if (choice >= item_no-max_choice/2)
256 scroll = first_item = item_no-max_choice;
257 else
258 scroll = first_item = choice - max_choice/2;
259 choice = choice - scroll;
260 }
261
262 /* Print the menu */
263 for (i=0; i < max_choice; i++) {
264 print_item (menu, items[(first_item + i) * 2 + 1], i, i == choice,
265 (items[(first_item + i)*2][0] != ':'));
266 }
267
268 wnoutrefresh (menu);
269
270 print_arrows(dialog, item_no, scroll,
271 box_y, box_x+item_x+1, menu_height);
272
273 print_buttons (dialog, height, width, 0);
274 wmove (menu, choice, item_x+1);
275 wrefresh (menu);
276
277 while (key != ESC) {
278 key = wgetch(menu);
279
280 if (key < 256 && isalpha(key)) key = tolower(key);
281
282 if (strchr("ynm", key))
283 i = max_choice;
284 else {
285 for (i = choice+1; i < max_choice; i++) {
286 j = first_alpha(items[(scroll+i)*2+1], "YyNnMm");
287 if (key == tolower(items[(scroll+i)*2+1][j]))
288 break;
289 }
290 if (i == max_choice)
291 for (i = 0; i < max_choice; i++) {
292 j = first_alpha(items[(scroll+i)*2+1], "YyNnMm");
293 if (key == tolower(items[(scroll+i)*2+1][j]))
294 break;
295 }
296 }
297
298 if (i < max_choice ||
299 key == KEY_UP || key == KEY_DOWN ||
300 key == '-' || key == '+' ||
301 key == KEY_PPAGE || key == KEY_NPAGE) {
302
303 print_item (menu, items[(scroll+choice)*2+1], choice, FALSE,
304 (items[(scroll+choice)*2][0] != ':'));
305
306 if (key == KEY_UP || key == '-') {
307 if (choice < 2 && scroll) {
308 /* Scroll menu down */
309 scrollok (menu, TRUE);
310 wscrl (menu, -1);
311 scrollok (menu, FALSE);
312
313 scroll--;
314
315 print_item (menu, items[scroll * 2 + 1], 0, FALSE,
316 (items[scroll*2][0] != ':'));
317 } else
318 choice = MAX(choice - 1, 0);
319
320 } else if (key == KEY_DOWN || key == '+') {
321
322 print_item (menu, items[(scroll+choice)*2+1], choice, FALSE,
323 (items[(scroll+choice)*2][0] != ':'));
324
325 if ((choice > max_choice-3) &&
326 (scroll + max_choice < item_no)
327 ) {
328 /* Scroll menu up */
329 scrollok (menu, TRUE);
330 scroll (menu);
331 scrollok (menu, FALSE);
332
333 scroll++;
334
335 print_item (menu, items[(scroll+max_choice-1)*2+1],
336 max_choice-1, FALSE,
337 (items[(scroll+max_choice-1)*2][0] != ':'));
338 } else
339 choice = MIN(choice+1, max_choice-1);
340
341 } else if (key == KEY_PPAGE) {
342 scrollok (menu, TRUE);
343 for (i=0; (i < max_choice); i++) {
344 if (scroll > 0) {
345 wscrl (menu, -1);
346 scroll--;
347 print_item (menu, items[scroll * 2 + 1], 0, FALSE,
348 (items[scroll*2][0] != ':'));
349 } else {
350 if (choice > 0)
351 choice--;
352 }
353 }
354 scrollok (menu, FALSE);
355
356 } else if (key == KEY_NPAGE) {
357 for (i=0; (i < max_choice); i++) {
358 if (scroll+max_choice < item_no) {
359 scrollok (menu, TRUE);
360 scroll(menu);
361 scrollok (menu, FALSE);
362 scroll++;
363 print_item (menu, items[(scroll+max_choice-1)*2+1],
364 max_choice-1, FALSE,
365 (items[(scroll+max_choice-1)*2][0] != ':'));
366 } else {
367 if (choice+1 < max_choice)
368 choice++;
369 }
370 }
371
372 } else
373 choice = i;
374
375 print_item (menu, items[(scroll+choice)*2+1], choice, TRUE,
376 (items[(scroll+choice)*2][0] != ':'));
377
378 print_arrows(dialog, item_no, scroll,
379 box_y, box_x+item_x+1, menu_height);
380
381 wnoutrefresh (dialog);
382 wrefresh (menu);
383
384 continue; /* wait for another key press */
385 }
386
387 switch (key) {
388 case KEY_LEFT:
389 case TAB:
390 case KEY_RIGHT:
391 button = ((key == KEY_LEFT ? --button : ++button) < 0)
392 ? 2 : (button > 2 ? 0 : button);
393
394 print_buttons(dialog, height, width, button);
395 wrefresh (menu);
396 break;
397 case ' ':
398 case 's':
399 case 'y':
400 case 'n':
401 case 'm':
402 /* save scroll info */
403 if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) {
404 fprintf(f,"%d\n",scroll);
405 fclose(f);
406 }
407 delwin (dialog);
408 fprintf(stderr, "%s\n", items[(scroll + choice) * 2]);
409 switch (key) {
410 case 's': return 3;
411 case 'y': return 3;
412 case 'n': return 4;
413 case 'm': return 5;
414 case ' ': return 6;
415 }
416 return 0;
417 case 'h':
418 case '?':
419 button = 2;
420 case '\n':
421 delwin (dialog);
422 if (button == 2)
423 fprintf(stderr, "%s \"%s\"\n",
424 items[(scroll + choice) * 2],
425 items[(scroll + choice) * 2 + 1] +
426 first_alpha(items[(scroll + choice) * 2 + 1],""));
427 else
428 fprintf(stderr, "%s\n", items[(scroll + choice) * 2]);
429
430 remove("lxdialog.scrltmp");
431 return button;
432 case 'e':
433 case 'x':
434 key = ESC;
435 case ESC:
436 break;
437 }
438 }
439
440 delwin (dialog);
441 remove("lxdialog.scrltmp");
442 return -1; /* ESC pressed */
443}
diff --git a/scripts/lxdialog/msgbox.c b/scripts/lxdialog/msgbox.c
new file mode 100644
index 000000000..93692e1fb
--- /dev/null
+++ b/scripts/lxdialog/msgbox.c
@@ -0,0 +1,85 @@
1/*
2 * msgbox.c -- implements the message box and info box
3 *
4 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "dialog.h"
23
24/*
25 * Display a message box. Program will pause and display an "OK" button
26 * if the parameter 'pause' is non-zero.
27 */
28int
29dialog_msgbox (const char *title, const char *prompt, int height, int width,
30 int pause)
31{
32 int i, x, y, key = 0;
33 WINDOW *dialog;
34
35 /* center dialog box on screen */
36 x = (COLS - width) / 2;
37 y = (LINES - height) / 2;
38
39 draw_shadow (stdscr, y, x, height, width);
40
41 dialog = newwin (height, width, y, x);
42 keypad (dialog, TRUE);
43
44 draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
45
46 if (title != NULL && strlen(title) >= width-2 ) {
47 /* truncate long title -- mec */
48 char * title2 = malloc(width-2+1);
49 memcpy( title2, title, width-2 );
50 title2[width-2] = '\0';
51 title = title2;
52 }
53
54 if (title != NULL) {
55 wattrset (dialog, title_attr);
56 mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
57 waddstr (dialog, (char *)title);
58 waddch (dialog, ' ');
59 }
60 wattrset (dialog, dialog_attr);
61 print_autowrap (dialog, prompt, width - 2, 1, 2);
62
63 if (pause) {
64 wattrset (dialog, border_attr);
65 mvwaddch (dialog, height - 3, 0, ACS_LTEE);
66 for (i = 0; i < width - 2; i++)
67 waddch (dialog, ACS_HLINE);
68 wattrset (dialog, dialog_attr);
69 waddch (dialog, ACS_RTEE);
70
71 print_button (dialog, " Ok ",
72 height - 2, width / 2 - 4, TRUE);
73
74 wrefresh (dialog);
75 while (key != ESC && key != '\n' && key != ' ' &&
76 key != 'O' && key != 'o' && key != 'X' && key != 'x')
77 key = wgetch (dialog);
78 } else {
79 key = '\n';
80 wrefresh (dialog);
81 }
82
83 delwin (dialog);
84 return key == ESC ? -1 : 0;
85}
diff --git a/scripts/lxdialog/textbox.c b/scripts/lxdialog/textbox.c
new file mode 100644
index 000000000..ecf55410e
--- /dev/null
+++ b/scripts/lxdialog/textbox.c
@@ -0,0 +1,556 @@
1/*
2 * textbox.c -- implements the text box
3 *
4 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "dialog.h"
23
24static void back_lines (int n);
25static void print_page (WINDOW * win, int height, int width);
26static void print_line (WINDOW * win, int row, int width);
27static char *get_line (void);
28static void print_position (WINDOW * win, int height, int width);
29
30static int hscroll = 0, fd, file_size, bytes_read;
31static int begin_reached = 1, end_reached = 0, page_length;
32static char *buf, *page;
33
34/*
35 * Display text from a file in a dialog box.
36 */
37int
38dialog_textbox (const char *title, const char *file, int height, int width)
39{
40 int i, x, y, cur_x, cur_y, fpos, key = 0;
41 int passed_end;
42 char search_term[MAX_LEN + 1];
43 WINDOW *dialog, *text;
44
45 search_term[0] = '\0'; /* no search term entered yet */
46
47 /* Open input file for reading */
48 if ((fd = open (file, O_RDONLY)) == -1) {
49 endwin ();
50 fprintf (stderr,
51 "\nCan't open input file in dialog_textbox().\n");
52 exit (-1);
53 }
54 /* Get file size. Actually, 'file_size' is the real file size - 1,
55 since it's only the last byte offset from the beginning */
56 if ((file_size = lseek (fd, 0, SEEK_END)) == -1) {
57 endwin ();
58 fprintf (stderr, "\nError getting file size in dialog_textbox().\n");
59 exit (-1);
60 }
61 /* Restore file pointer to beginning of file after getting file size */
62 if (lseek (fd, 0, SEEK_SET) == -1) {
63 endwin ();
64 fprintf (stderr, "\nError moving file pointer in dialog_textbox().\n");
65 exit (-1);
66 }
67 /* Allocate space for read buffer */
68 if ((buf = malloc (BUF_SIZE + 1)) == NULL) {
69 endwin ();
70 fprintf (stderr, "\nCan't allocate memory in dialog_textbox().\n");
71 exit (-1);
72 }
73 if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
74 endwin ();
75 fprintf (stderr, "\nError reading file in dialog_textbox().\n");
76 exit (-1);
77 }
78 buf[bytes_read] = '\0'; /* mark end of valid data */
79 page = buf; /* page is pointer to start of page to be displayed */
80
81 /* center dialog box on screen */
82 x = (COLS - width) / 2;
83 y = (LINES - height) / 2;
84
85
86 draw_shadow (stdscr, y, x, height, width);
87
88 dialog = newwin (height, width, y, x);
89 keypad (dialog, TRUE);
90
91 /* Create window for text region, used for scrolling text */
92 text = subwin (dialog, height - 4, width - 2, y + 1, x + 1);
93 wattrset (text, dialog_attr);
94 wbkgdset (text, dialog_attr & A_COLOR);
95
96 keypad (text, TRUE);
97
98 /* register the new window, along with its borders */
99 draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
100
101 wattrset (dialog, border_attr);
102 mvwaddch (dialog, height-3, 0, ACS_LTEE);
103 for (i = 0; i < width - 2; i++)
104 waddch (dialog, ACS_HLINE);
105 wattrset (dialog, dialog_attr);
106 wbkgdset (dialog, dialog_attr & A_COLOR);
107 waddch (dialog, ACS_RTEE);
108
109 if (title != NULL && strlen(title) >= width-2 ) {
110 /* truncate long title -- mec */
111 char * title2 = malloc(width-2+1);
112 memcpy( title2, title, width-2 );
113 title2[width-2] = '\0';
114 title = title2;
115 }
116
117 if (title != NULL) {
118 wattrset (dialog, title_attr);
119 mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
120 waddstr (dialog, (char *)title);
121 waddch (dialog, ' ');
122 }
123 print_button (dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
124 wnoutrefresh (dialog);
125 getyx (dialog, cur_y, cur_x); /* Save cursor position */
126
127 /* Print first page of text */
128 attr_clear (text, height - 4, width - 2, dialog_attr);
129 print_page (text, height - 4, width - 2);
130 print_position (dialog, height, width);
131 wmove (dialog, cur_y, cur_x); /* Restore cursor position */
132 wrefresh (dialog);
133
134 while ((key != ESC) && (key != '\n')) {
135 key = wgetch (dialog);
136 switch (key) {
137 case 'E': /* Exit */
138 case 'e':
139 case 'X':
140 case 'x':
141 delwin (dialog);
142 free (buf);
143 close (fd);
144 return 0;
145 case 'g': /* First page */
146 case KEY_HOME:
147 if (!begin_reached) {
148 begin_reached = 1;
149 /* First page not in buffer? */
150 if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
151 endwin ();
152 fprintf (stderr,
153 "\nError moving file pointer in dialog_textbox().\n");
154 exit (-1);
155 }
156 if (fpos > bytes_read) { /* Yes, we have to read it in */
157 if (lseek (fd, 0, SEEK_SET) == -1) {
158 endwin ();
159 fprintf (stderr, "\nError moving file pointer in "
160 "dialog_textbox().\n");
161 exit (-1);
162 }
163 if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
164 endwin ();
165 fprintf (stderr,
166 "\nError reading file in dialog_textbox().\n");
167 exit (-1);
168 }
169 buf[bytes_read] = '\0';
170 }
171 page = buf;
172 print_page (text, height - 4, width - 2);
173 print_position (dialog, height, width);
174 wmove (dialog, cur_y, cur_x); /* Restore cursor position */
175 wrefresh (dialog);
176 }
177 break;
178 case 'G': /* Last page */
179 case KEY_END:
180
181 end_reached = 1;
182 /* Last page not in buffer? */
183 if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
184 endwin ();
185 fprintf (stderr,
186 "\nError moving file pointer in dialog_textbox().\n");
187 exit (-1);
188 }
189 if (fpos < file_size) { /* Yes, we have to read it in */
190 if (lseek (fd, -BUF_SIZE, SEEK_END) == -1) {
191 endwin ();
192 fprintf (stderr,
193 "\nError moving file pointer in dialog_textbox().\n");
194 exit (-1);
195 }
196 if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
197 endwin ();
198 fprintf (stderr,
199 "\nError reading file in dialog_textbox().\n");
200 exit (-1);
201 }
202 buf[bytes_read] = '\0';
203 }
204 page = buf + bytes_read;
205 back_lines (height - 4);
206 print_page (text, height - 4, width - 2);
207 print_position (dialog, height, width);
208 wmove (dialog, cur_y, cur_x); /* Restore cursor position */
209 wrefresh (dialog);
210 break;
211 case 'K': /* Previous line */
212 case 'k':
213 case KEY_UP:
214 if (!begin_reached) {
215 back_lines (page_length + 1);
216
217 /* We don't call print_page() here but use scrolling to ensure
218 faster screen update. However, 'end_reached' and
219 'page_length' should still be updated, and 'page' should
220 point to start of next page. This is done by calling
221 get_line() in the following 'for' loop. */
222 scrollok (text, TRUE);
223 wscrl (text, -1); /* Scroll text region down one line */
224 scrollok (text, FALSE);
225 page_length = 0;
226 passed_end = 0;
227 for (i = 0; i < height - 4; i++) {
228 if (!i) {
229 /* print first line of page */
230 print_line (text, 0, width - 2);
231 wnoutrefresh (text);
232 } else
233 /* Called to update 'end_reached' and 'page' */
234 get_line ();
235 if (!passed_end)
236 page_length++;
237 if (end_reached && !passed_end)
238 passed_end = 1;
239 }
240
241 print_position (dialog, height, width);
242 wmove (dialog, cur_y, cur_x); /* Restore cursor position */
243 wrefresh (dialog);
244 }
245 break;
246 case 'B': /* Previous page */
247 case 'b':
248 case KEY_PPAGE:
249 if (begin_reached)
250 break;
251 back_lines (page_length + height - 4);
252 print_page (text, height - 4, width - 2);
253 print_position (dialog, height, width);
254 wmove (dialog, cur_y, cur_x);
255 wrefresh (dialog);
256 break;
257 case 'J': /* Next line */
258 case 'j':
259 case KEY_DOWN:
260 if (!end_reached) {
261 begin_reached = 0;
262 scrollok (text, TRUE);
263 scroll (text); /* Scroll text region up one line */
264 scrollok (text, FALSE);
265 print_line (text, height - 5, width - 2);
266 wnoutrefresh (text);
267 print_position (dialog, height, width);
268 wmove (dialog, cur_y, cur_x); /* Restore cursor position */
269 wrefresh (dialog);
270 }
271 break;
272 case KEY_NPAGE: /* Next page */
273 case ' ':
274 if (end_reached)
275 break;
276
277 begin_reached = 0;
278 print_page (text, height - 4, width - 2);
279 print_position (dialog, height, width);
280 wmove (dialog, cur_y, cur_x);
281 wrefresh (dialog);
282 break;
283 case '0': /* Beginning of line */
284 case 'H': /* Scroll left */
285 case 'h':
286 case KEY_LEFT:
287 if (hscroll <= 0)
288 break;
289
290 if (key == '0')
291 hscroll = 0;
292 else
293 hscroll--;
294 /* Reprint current page to scroll horizontally */
295 back_lines (page_length);
296 print_page (text, height - 4, width - 2);
297 wmove (dialog, cur_y, cur_x);
298 wrefresh (dialog);
299 break;
300 case 'L': /* Scroll right */
301 case 'l':
302 case KEY_RIGHT:
303 if (hscroll >= MAX_LEN)
304 break;
305 hscroll++;
306 /* Reprint current page to scroll horizontally */
307 back_lines (page_length);
308 print_page (text, height - 4, width - 2);
309 wmove (dialog, cur_y, cur_x);
310 wrefresh (dialog);
311 break;
312 case ESC:
313 break;
314 }
315 }
316
317 delwin (dialog);
318 free (buf);
319 close (fd);
320 return -1; /* ESC pressed */
321}
322
323/*
324 * Go back 'n' lines in text file. Called by dialog_textbox().
325 * 'page' will be updated to point to the desired line in 'buf'.
326 */
327static void
328back_lines (int n)
329{
330 int i, fpos;
331
332 begin_reached = 0;
333 /* We have to distinguish between end_reached and !end_reached
334 since at end of file, the line is not ended by a '\n'.
335 The code inside 'if' basically does a '--page' to move one
336 character backward so as to skip '\n' of the previous line */
337 if (!end_reached) {
338 /* Either beginning of buffer or beginning of file reached? */
339 if (page == buf) {
340 if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
341 endwin ();
342 fprintf (stderr, "\nError moving file pointer in "
343 "back_lines().\n");
344 exit (-1);
345 }
346 if (fpos > bytes_read) { /* Not beginning of file yet */
347 /* We've reached beginning of buffer, but not beginning of
348 file yet, so read previous part of file into buffer.
349 Note that we only move backward for BUF_SIZE/2 bytes,
350 but not BUF_SIZE bytes to avoid re-reading again in
351 print_page() later */
352 /* Really possible to move backward BUF_SIZE/2 bytes? */
353 if (fpos < BUF_SIZE / 2 + bytes_read) {
354 /* No, move less then */
355 if (lseek (fd, 0, SEEK_SET) == -1) {
356 endwin ();
357 fprintf (stderr, "\nError moving file pointer in "
358 "back_lines().\n");
359 exit (-1);
360 }
361 page = buf + fpos - bytes_read;
362 } else { /* Move backward BUF_SIZE/2 bytes */
363 if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR)
364 == -1) {
365 endwin ();
366 fprintf (stderr, "\nError moving file pointer "
367 "in back_lines().\n");
368 exit (-1);
369 }
370 page = buf + BUF_SIZE / 2;
371 }
372 if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
373 endwin ();
374 fprintf (stderr, "\nError reading file in back_lines().\n");
375 exit (-1);
376 }
377 buf[bytes_read] = '\0';
378 } else { /* Beginning of file reached */
379 begin_reached = 1;
380 return;
381 }
382 }
383 if (*(--page) != '\n') { /* '--page' here */
384 /* Something's wrong... */
385 endwin ();
386 fprintf (stderr, "\nInternal error in back_lines().\n");
387 exit (-1);
388 }
389 }
390 /* Go back 'n' lines */
391 for (i = 0; i < n; i++)
392 do {
393 if (page == buf) {
394 if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
395 endwin ();
396 fprintf (stderr,
397 "\nError moving file pointer in back_lines().\n");
398 exit (-1);
399 }
400 if (fpos > bytes_read) {
401 /* Really possible to move backward BUF_SIZE/2 bytes? */
402 if (fpos < BUF_SIZE / 2 + bytes_read) {
403 /* No, move less then */
404 if (lseek (fd, 0, SEEK_SET) == -1) {
405 endwin ();
406 fprintf (stderr, "\nError moving file pointer "
407 "in back_lines().\n");
408 exit (-1);
409 }
410 page = buf + fpos - bytes_read;
411 } else { /* Move backward BUF_SIZE/2 bytes */
412 if (lseek (fd, -(BUF_SIZE / 2 + bytes_read),
413 SEEK_CUR) == -1) {
414 endwin ();
415 fprintf (stderr, "\nError moving file pointer"
416 " in back_lines().\n");
417 exit (-1);
418 }
419 page = buf + BUF_SIZE / 2;
420 }
421 if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
422 endwin ();
423 fprintf (stderr, "\nError reading file in "
424 "back_lines().\n");
425 exit (-1);
426 }
427 buf[bytes_read] = '\0';
428 } else { /* Beginning of file reached */
429 begin_reached = 1;
430 return;
431 }
432 }
433 } while (*(--page) != '\n');
434 page++;
435}
436
437/*
438 * Print a new page of text. Called by dialog_textbox().
439 */
440static void
441print_page (WINDOW * win, int height, int width)
442{
443 int i, passed_end = 0;
444
445 page_length = 0;
446 for (i = 0; i < height; i++) {
447 print_line (win, i, width);
448 if (!passed_end)
449 page_length++;
450 if (end_reached && !passed_end)
451 passed_end = 1;
452 }
453 wnoutrefresh (win);
454}
455
456/*
457 * Print a new line of text. Called by dialog_textbox() and print_page().
458 */
459static void
460print_line (WINDOW * win, int row, int width)
461{
462 int y, x;
463 char *line;
464
465 line = get_line ();
466 line += MIN (strlen (line), hscroll); /* Scroll horizontally */
467 wmove (win, row, 0); /* move cursor to correct line */
468 waddch (win, ' ');
469 waddnstr (win, line, MIN (strlen (line), width - 2));
470
471 getyx (win, y, x);
472 /* Clear 'residue' of previous line */
473#if OLD_NCURSES
474 {
475 int i;
476 for (i = 0; i < width - x; i++)
477 waddch (win, ' ');
478 }
479#else
480 wclrtoeol(win);
481#endif
482}
483
484/*
485 * Return current line of text. Called by dialog_textbox() and print_line().
486 * 'page' should point to start of current line before calling, and will be
487 * updated to point to start of next line.
488 */
489static char *
490get_line (void)
491{
492 int i = 0, fpos;
493 static char line[MAX_LEN + 1];
494
495 end_reached = 0;
496 while (*page != '\n') {
497 if (*page == '\0') {
498 /* Either end of file or end of buffer reached */
499 if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
500 endwin ();
501 fprintf (stderr, "\nError moving file pointer in "
502 "get_line().\n");
503 exit (-1);
504 }
505 if (fpos < file_size) { /* Not end of file yet */
506 /* We've reached end of buffer, but not end of file yet,
507 so read next part of file into buffer */
508 if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
509 endwin ();
510 fprintf (stderr, "\nError reading file in get_line().\n");
511 exit (-1);
512 }
513 buf[bytes_read] = '\0';
514 page = buf;
515 } else {
516 if (!end_reached)
517 end_reached = 1;
518 break;
519 }
520 } else if (i < MAX_LEN)
521 line[i++] = *(page++);
522 else {
523 /* Truncate lines longer than MAX_LEN characters */
524 if (i == MAX_LEN)
525 line[i++] = '\0';
526 page++;
527 }
528 }
529 if (i <= MAX_LEN)
530 line[i] = '\0';
531 if (!end_reached)
532 page++; /* move pass '\n' */
533
534 return line;
535}
536
537/*
538 * Print current position
539 */
540static void
541print_position (WINDOW * win, int height, int width)
542{
543 int fpos, percent;
544
545 if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
546 endwin ();
547 fprintf (stderr, "\nError moving file pointer in print_position().\n");
548 exit (-1);
549 }
550 wattrset (win, position_indicator_attr);
551 wbkgdset (win, position_indicator_attr & A_COLOR);
552 percent = !file_size ?
553 100 : ((fpos - bytes_read + page - buf) * 100) / file_size;
554 wmove (win, height - 3, width - 9);
555 wprintw (win, "(%3d%%)", percent);
556}
diff --git a/scripts/lxdialog/util.c b/scripts/lxdialog/util.c
new file mode 100644
index 000000000..b3a7af9d2
--- /dev/null
+++ b/scripts/lxdialog/util.c
@@ -0,0 +1,359 @@
1/*
2 * util.c
3 *
4 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "dialog.h"
23
24
25/* use colors by default? */
26bool use_colors = 1;
27
28const char *backtitle = NULL;
29
30const char *dialog_result;
31
32/*
33 * Attribute values, default is for mono display
34 */
35chtype attributes[] =
36{
37 A_NORMAL, /* screen_attr */
38 A_NORMAL, /* shadow_attr */
39 A_NORMAL, /* dialog_attr */
40 A_BOLD, /* title_attr */
41 A_NORMAL, /* border_attr */
42 A_REVERSE, /* button_active_attr */
43 A_DIM, /* button_inactive_attr */
44 A_REVERSE, /* button_key_active_attr */
45 A_BOLD, /* button_key_inactive_attr */
46 A_REVERSE, /* button_label_active_attr */
47 A_NORMAL, /* button_label_inactive_attr */
48 A_NORMAL, /* inputbox_attr */
49 A_NORMAL, /* inputbox_border_attr */
50 A_NORMAL, /* searchbox_attr */
51 A_BOLD, /* searchbox_title_attr */
52 A_NORMAL, /* searchbox_border_attr */
53 A_BOLD, /* position_indicator_attr */
54 A_NORMAL, /* menubox_attr */
55 A_NORMAL, /* menubox_border_attr */
56 A_NORMAL, /* item_attr */
57 A_REVERSE, /* item_selected_attr */
58 A_BOLD, /* tag_attr */
59 A_REVERSE, /* tag_selected_attr */
60 A_BOLD, /* tag_key_attr */
61 A_REVERSE, /* tag_key_selected_attr */
62 A_BOLD, /* check_attr */
63 A_REVERSE, /* check_selected_attr */
64 A_BOLD, /* uarrow_attr */
65 A_BOLD /* darrow_attr */
66};
67
68
69#include "colors.h"
70
71/*
72 * Table of color values
73 */
74int color_table[][3] =
75{
76 {SCREEN_FG, SCREEN_BG, SCREEN_HL},
77 {SHADOW_FG, SHADOW_BG, SHADOW_HL},
78 {DIALOG_FG, DIALOG_BG, DIALOG_HL},
79 {TITLE_FG, TITLE_BG, TITLE_HL},
80 {BORDER_FG, BORDER_BG, BORDER_HL},
81 {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL},
82 {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL},
83 {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL},
84 {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG, BUTTON_KEY_INACTIVE_HL},
85 {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG, BUTTON_LABEL_ACTIVE_HL},
86 {BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG,
87 BUTTON_LABEL_INACTIVE_HL},
88 {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL},
89 {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL},
90 {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL},
91 {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL},
92 {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL},
93 {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL},
94 {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL},
95 {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL},
96 {ITEM_FG, ITEM_BG, ITEM_HL},
97 {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL},
98 {TAG_FG, TAG_BG, TAG_HL},
99 {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL},
100 {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL},
101 {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL},
102 {CHECK_FG, CHECK_BG, CHECK_HL},
103 {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL},
104 {UARROW_FG, UARROW_BG, UARROW_HL},
105 {DARROW_FG, DARROW_BG, DARROW_HL},
106}; /* color_table */
107
108/*
109 * Set window to attribute 'attr'
110 */
111void
112attr_clear (WINDOW * win, int height, int width, chtype attr)
113{
114 int i, j;
115
116 wattrset (win, attr);
117 for (i = 0; i < height; i++) {
118 wmove (win, i, 0);
119 for (j = 0; j < width; j++)
120 waddch (win, ' ');
121 }
122 touchwin (win);
123}
124
125void dialog_clear (void)
126{
127 attr_clear (stdscr, LINES, COLS, screen_attr);
128 /* Display background title if it exists ... - SLH */
129 if (backtitle != NULL) {
130 int i;
131
132 wattrset (stdscr, screen_attr);
133 mvwaddstr (stdscr, 0, 1, (char *)backtitle);
134 wmove (stdscr, 1, 1);
135 for (i = 1; i < COLS - 1; i++)
136 waddch (stdscr, ACS_HLINE);
137 }
138 wnoutrefresh (stdscr);
139}
140
141/*
142 * Do some initialization for dialog
143 */
144void
145init_dialog (void)
146{
147 initscr (); /* Init curses */
148 keypad (stdscr, TRUE);
149 cbreak ();
150 noecho ();
151
152
153 if (use_colors) /* Set up colors */
154 color_setup ();
155
156
157 dialog_clear ();
158}
159
160/*
161 * Setup for color display
162 */
163void
164color_setup (void)
165{
166 int i;
167
168 if (has_colors ()) { /* Terminal supports color? */
169 start_color ();
170
171 /* Initialize color pairs */
172 for (i = 0; i < ATTRIBUTE_COUNT; i++)
173 init_pair (i + 1, color_table[i][0], color_table[i][1]);
174
175 /* Setup color attributes */
176 for (i = 0; i < ATTRIBUTE_COUNT; i++)
177 attributes[i] = C_ATTR (color_table[i][2], i + 1);
178 }
179}
180
181/*
182 * End using dialog functions.
183 */
184void
185end_dialog (void)
186{
187 endwin ();
188}
189
190
191/*
192 * Print a string of text in a window, automatically wrap around to the
193 * next line if the string is too long to fit on one line. Newline
194 * characters '\n' are replaced by spaces. We start on a new line
195 * if there is no room for at least 4 nonblanks following a double-space.
196 */
197void
198print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x)
199{
200 int newl, cur_x, cur_y;
201 int i, prompt_len, room, wlen;
202 char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
203
204 strcpy (tempstr, prompt);
205
206 prompt_len = strlen(tempstr);
207
208 /*
209 * Remove newlines
210 */
211 for(i=0; i<prompt_len; i++) {
212 if(tempstr[i] == '\n') tempstr[i] = ' ';
213 }
214
215 if (prompt_len <= width - x * 2) { /* If prompt is short */
216 wmove (win, y, (width - prompt_len) / 2);
217 waddstr (win, tempstr);
218 } else {
219 cur_x = x;
220 cur_y = y;
221 newl = 1;
222 word = tempstr;
223 while (word && *word) {
224 sp = index(word, ' ');
225 if (sp)
226 *sp++ = 0;
227
228 /* Wrap to next line if either the word does not fit,
229 or it is the first word of a new sentence, and it is
230 short, and the next word does not fit. */
231 room = width - cur_x;
232 wlen = strlen(word);
233 if (wlen > room ||
234 (newl && wlen < 4 && sp && wlen+1+strlen(sp) > room
235 && (!(sp2 = index(sp, ' ')) || wlen+1+(sp2-sp) > room))) {
236 cur_y++;
237 cur_x = x;
238 }
239 wmove (win, cur_y, cur_x);
240 waddstr (win, word);
241 getyx (win, cur_y, cur_x);
242 cur_x++;
243 if (sp && *sp == ' ') {
244 cur_x++; /* double space */
245 while (*++sp == ' ');
246 newl = 1;
247 } else
248 newl = 0;
249 word = sp;
250 }
251 }
252}
253
254/*
255 * Print a button
256 */
257void
258print_button (WINDOW * win, const char *label, int y, int x, int selected)
259{
260 int i, temp;
261
262 wmove (win, y, x);
263 wattrset (win, selected ? button_active_attr : button_inactive_attr);
264 waddstr (win, "<");
265 temp = strspn (label, " ");
266 label += temp;
267 wattrset (win, selected ? button_label_active_attr
268 : button_label_inactive_attr);
269 for (i = 0; i < temp; i++)
270 waddch (win, ' ');
271 wattrset (win, selected ? button_key_active_attr
272 : button_key_inactive_attr);
273 waddch (win, label[0]);
274 wattrset (win, selected ? button_label_active_attr
275 : button_label_inactive_attr);
276 waddstr (win, (char *)label + 1);
277 wattrset (win, selected ? button_active_attr : button_inactive_attr);
278 waddstr (win, ">");
279 wmove (win, y, x + temp + 1);
280}
281
282/*
283 * Draw a rectangular box with line drawing characters
284 */
285void
286draw_box (WINDOW * win, int y, int x, int height, int width,
287 chtype box, chtype border)
288{
289 int i, j;
290
291 wattrset (win, 0);
292 for (i = 0; i < height; i++) {
293 wmove (win, y + i, x);
294 for (j = 0; j < width; j++)
295 if (!i && !j)
296 waddch (win, border | ACS_ULCORNER);
297 else if (i == height - 1 && !j)
298 waddch (win, border | ACS_LLCORNER);
299 else if (!i && j == width - 1)
300 waddch (win, box | ACS_URCORNER);
301 else if (i == height - 1 && j == width - 1)
302 waddch (win, box | ACS_LRCORNER);
303 else if (!i)
304 waddch (win, border | ACS_HLINE);
305 else if (i == height - 1)
306 waddch (win, box | ACS_HLINE);
307 else if (!j)
308 waddch (win, border | ACS_VLINE);
309 else if (j == width - 1)
310 waddch (win, box | ACS_VLINE);
311 else
312 waddch (win, box | ' ');
313 }
314}
315
316/*
317 * Draw shadows along the right and bottom edge to give a more 3D look
318 * to the boxes
319 */
320void
321draw_shadow (WINDOW * win, int y, int x, int height, int width)
322{
323 int i;
324
325 if (has_colors ()) { /* Whether terminal supports color? */
326 wattrset (win, shadow_attr);
327 wmove (win, y + height, x + 2);
328 for (i = 0; i < width; i++)
329 waddch (win, winch (win) & A_CHARTEXT);
330 for (i = y + 1; i < y + height + 1; i++) {
331 wmove (win, i, x + width);
332 waddch (win, winch (win) & A_CHARTEXT);
333 waddch (win, winch (win) & A_CHARTEXT);
334 }
335 wnoutrefresh (win);
336 }
337}
338
339/*
340 * Return the position of the first alphabetic character in a string.
341 */
342int
343first_alpha(const char *string, const char *exempt)
344{
345 int i, in_paren=0, c;
346
347 for (i = 0; i < strlen(string); i++) {
348 c = tolower(string[i]);
349
350 if (strchr("<[(", c)) ++in_paren;
351 if (strchr(">])", c)) --in_paren;
352
353 if ((! in_paren) && isalpha(c) &&
354 strchr(exempt, c) == 0)
355 return i;
356 }
357
358 return 0;
359}
diff --git a/scripts/lxdialog/yesno.c b/scripts/lxdialog/yesno.c
new file mode 100644
index 000000000..11fcc25f5
--- /dev/null
+++ b/scripts/lxdialog/yesno.c
@@ -0,0 +1,118 @@
1/*
2 * yesno.c -- implements the yes/no box
3 *
4 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "dialog.h"
23
24/*
25 * Display termination buttons
26 */
27static void
28print_buttons(WINDOW *dialog, int height, int width, int selected)
29{
30 int x = width / 2 - 10;
31 int y = height - 2;
32
33 print_button (dialog, " Yes ", y, x, selected == 0);
34 print_button (dialog, " No ", y, x + 13, selected == 1);
35
36 wmove(dialog, y, x+1 + 13*selected );
37 wrefresh (dialog);
38}
39
40/*
41 * Display a dialog box with two buttons - Yes and No
42 */
43int
44dialog_yesno (const char *title, const char *prompt, int height, int width)
45{
46 int i, x, y, key = 0, button = 0;
47 WINDOW *dialog;
48
49 /* center dialog box on screen */
50 x = (COLS - width) / 2;
51 y = (LINES - height) / 2;
52
53 draw_shadow (stdscr, y, x, height, width);
54
55 dialog = newwin (height, width, y, x);
56 keypad (dialog, TRUE);
57
58 draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
59 wattrset (dialog, border_attr);
60 mvwaddch (dialog, height-3, 0, ACS_LTEE);
61 for (i = 0; i < width - 2; i++)
62 waddch (dialog, ACS_HLINE);
63 wattrset (dialog, dialog_attr);
64 waddch (dialog, ACS_RTEE);
65
66 if (title != NULL && strlen(title) >= width-2 ) {
67 /* truncate long title -- mec */
68 char * title2 = malloc(width-2+1);
69 memcpy( title2, title, width-2 );
70 title2[width-2] = '\0';
71 title = title2;
72 }
73
74 if (title != NULL) {
75 wattrset (dialog, title_attr);
76 mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
77 waddstr (dialog, (char *)title);
78 waddch (dialog, ' ');
79 }
80
81 wattrset (dialog, dialog_attr);
82 print_autowrap (dialog, prompt, width - 2, 1, 3);
83
84 print_buttons(dialog, height, width, 0);
85
86 while (key != ESC) {
87 key = wgetch (dialog);
88 switch (key) {
89 case 'Y':
90 case 'y':
91 delwin (dialog);
92 return 0;
93 case 'N':
94 case 'n':
95 delwin (dialog);
96 return 1;
97
98 case TAB:
99 case KEY_LEFT:
100 case KEY_RIGHT:
101 button = ((key == KEY_LEFT ? --button : ++button) < 0)
102 ? 1 : (button > 1 ? 0 : button);
103
104 print_buttons(dialog, height, width, button);
105 wrefresh (dialog);
106 break;
107 case ' ':
108 case '\n':
109 delwin (dialog);
110 return button;
111 case ESC:
112 break;
113 }
114 }
115
116 delwin (dialog);
117 return -1; /* ESC pressed */
118}
diff --git a/scripts/mk2knr.pl b/scripts/mk2knr.pl
deleted file mode 100755
index aaf4963b1..000000000
--- a/scripts/mk2knr.pl
+++ /dev/null
@@ -1,84 +0,0 @@
1#!/usr/bin/perl -w
2#
3# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style
4#
5# How to use this script:
6# - In the busybox directory type 'scripts/mk2knr.pl files-you-want-to-convert'
7# - Review the 'convertme.pl' script generated and remove / edit any of the
8# substitutions in there (please especially check for false positives)
9# - Type './convertme.pl same-files-as-before'
10# - Compile and see if it works
11#
12# BUGS: This script does not ignore strings inside comments or strings inside
13# quotes (it probably should).
14
15# set this to something else if you want
16$convertme = 'convertme.pl';
17
18# internal-use variables (don't touch)
19$convert = 0;
20%converted = ();
21
22# if no files were specified, print usage
23die "usage: $0 file.c | file.h\n" if scalar(@ARGV) == 0;
24
25# prepare the "convert me" file
26open(CM, ">$convertme") or die "convertme.pl $!";
27print CM "#!/usr/bin/perl -p -i\n\n";
28
29# process each file passed on the cmd line
30while (<>) {
31
32 # if the line says "getopt" in it anywhere, we don't want to muck with it
33 # because option lists tend to include strings like "cxtzvOf:" which get
34 # matched by the "check for mixed case" regexps below
35 next if /getopt/;
36
37 # tokenize the string into just the variables
38 while (/([a-zA-Z_][a-zA-Z0-9_]*)/g) {
39 $var = $1;
40
41 # ignore the word "BusyBox"
42 next if ($var =~ /BusyBox/);
43
44 # this checks for javaStyle or szHungarianNotation
45 $convert++ if ($var =~ /^[a-z]+[A-Z][a-z]+/);
46
47 # this checks for PascalStyle
48 $convert++ if ($var =~ /^[A-Z][a-z]+[A-Z][a-z]+/);
49
50 # if we want to add more checks, we can add 'em here, but the above
51 # checks catch "just enough" and not too much, so prolly not.
52
53 if ($convert) {
54 $convert = 0;
55
56 # skip ahead if we've already dealt with this one
57 next if ($converted{$var});
58
59 # record that we've dealt with this var
60 $converted{$var} = 1;
61
62 print CM "s/\\b$var\\b/"; # more to come in just a minute
63
64 # change the first letter to lower-case
65 $var = lcfirst($var);
66
67 # put underscores before all remaining upper-case letters
68 $var =~ s/([A-Z])/_$1/g;
69
70 # now change the remaining characters to lower-case
71 $var = lc($var);
72
73 print CM "$var/g;\n";
74 }
75 }
76}
77
78# tidy up and make the $convertme script executable
79close(CM);
80chmod 0755, $convertme;
81
82# print a helpful help message
83print "Done. Scheduled name changes are in $convertme.\n";
84print "Please review/modify it and then type ./$convertme to do the search & replace.\n";
diff --git a/scripts/mkdep.c b/scripts/mkdep.c
new file mode 100644
index 000000000..c3e94bfae
--- /dev/null
+++ b/scripts/mkdep.c
@@ -0,0 +1,628 @@
1/*
2 * Originally by Linus Torvalds.
3 * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
4 *
5 * Usage: mkdep cflags -- file ...
6 *
7 * Read source files and output makefile dependency lines for them.
8 * I make simple dependency lines for #include <*.h> and #include "*.h".
9 * I also find instances of CONFIG_FOO and generate dependencies
10 * like include/config/foo.h.
11 *
12 * 1 August 1999, Michael Elizabeth Chastain, <mec@shout.net>
13 * - Keith Owens reported a bug in smart config processing. There used
14 * to be an optimization for "#define CONFIG_FOO ... #ifdef CONFIG_FOO",
15 * so that the file would not depend on CONFIG_FOO because the file defines
16 * this symbol itself. But this optimization is bogus! Consider this code:
17 * "#if 0 \n #define CONFIG_FOO \n #endif ... #ifdef CONFIG_FOO". Here
18 * the definition is inactivated, but I still used it. It turns out this
19 * actually happens a few times in the kernel source. The simple way to
20 * fix this problem is to remove this particular optimization.
21 *
22 * 2.3.99-pre1, Andrew Morton <andrewm@uow.edu.au>
23 * - Changed so that 'filename.o' depends upon 'filename.[cS]'. This is so that
24 * missing source files are noticed, rather than silently ignored.
25 *
26 * 2.4.2-pre3, Keith Owens <kaos@ocs.com.au>
27 * - Accept cflags followed by '--' followed by filenames. mkdep extracts -I
28 * options from cflags and looks in the specified directories as well as the
29 * defaults. Only -I is supported, no attempt is made to handle -idirafter,
30 * -isystem, -I- etc.
31 */
32
33#include <ctype.h>
34#include <fcntl.h>
35#include <limits.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41#include <sys/fcntl.h>
42#include <sys/mman.h>
43#include <sys/stat.h>
44#include <sys/types.h>
45
46
47
48char __depname[512] = "\n\t@touch ";
49#define depname (__depname+9)
50int hasdep;
51
52struct path_struct {
53 int len;
54 char *buffer;
55};
56struct path_struct *path_array;
57int paths;
58
59
60/* Current input file */
61static const char *g_filename;
62
63/*
64 * This records all the configuration options seen.
65 * In perl this would be a hash, but here it's a long string
66 * of values separated by newlines. This is simple and
67 * extremely fast.
68 */
69char * str_config = NULL;
70int size_config = 0;
71int len_config = 0;
72
73static void
74do_depname(void)
75{
76 if (!hasdep) {
77 hasdep = 1;
78 printf("%s:", depname);
79 if (g_filename)
80 printf(" %s", g_filename);
81 }
82}
83
84/*
85 * Grow the configuration string to a desired length.
86 * Usually the first growth is plenty.
87 */
88void grow_config(int len)
89{
90 while (len_config + len > size_config) {
91 if (size_config == 0)
92 size_config = 2048;
93 str_config = realloc(str_config, size_config *= 2);
94 if (str_config == NULL)
95 { perror("malloc config"); exit(1); }
96 }
97}
98
99
100
101/*
102 * Lookup a value in the configuration string.
103 */
104int is_defined_config(const char * name, int len)
105{
106 const char * pconfig;
107 const char * plast = str_config + len_config - len;
108 for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
109 if (pconfig[ -1] == '\n'
110 && pconfig[len] == '\n'
111 && !memcmp(pconfig, name, len))
112 return 1;
113 }
114 return 0;
115}
116
117
118
119/*
120 * Add a new value to the configuration string.
121 */
122void define_config(const char * name, int len)
123{
124 grow_config(len + 1);
125
126 memcpy(str_config+len_config, name, len);
127 len_config += len;
128 str_config[len_config++] = '\n';
129}
130
131
132
133/*
134 * Clear the set of configuration strings.
135 */
136void clear_config(void)
137{
138 len_config = 0;
139 define_config("", 0);
140}
141
142
143
144/*
145 * This records all the precious .h filenames. No need for a hash,
146 * it's a long string of values enclosed in tab and newline.
147 */
148char * str_precious = NULL;
149int size_precious = 0;
150int len_precious = 0;
151
152
153
154/*
155 * Grow the precious string to a desired length.
156 * Usually the first growth is plenty.
157 */
158void grow_precious(int len)
159{
160 while (len_precious + len > size_precious) {
161 if (size_precious == 0)
162 size_precious = 2048;
163 str_precious = realloc(str_precious, size_precious *= 2);
164 if (str_precious == NULL)
165 { perror("malloc"); exit(1); }
166 }
167}
168
169
170
171/*
172 * Add a new value to the precious string.
173 */
174void define_precious(const char * filename)
175{
176 int len = strlen(filename);
177 grow_precious(len + 4);
178 *(str_precious+len_precious++) = '\t';
179 memcpy(str_precious+len_precious, filename, len);
180 len_precious += len;
181 memcpy(str_precious+len_precious, " \\\n", 3);
182 len_precious += 3;
183}
184
185
186
187/*
188 * Handle an #include line.
189 */
190void handle_include(int start, const char * name, int len)
191{
192 struct path_struct *path;
193 int i;
194
195 if (len == 14 && !memcmp(name, "include/config.h", len))
196 return;
197
198 if (len >= 7 && !memcmp(name, "config/", 7))
199 define_config(name+7, len-7-2);
200
201 for (i = start, path = path_array+start; i < paths; ++i, ++path) {
202 memcpy(path->buffer+path->len, name, len);
203 path->buffer[path->len+len] = '\0';
204 if (access(path->buffer, F_OK) == 0) {
205 do_depname();
206 printf(" \\\n %s", path->buffer);
207 return;
208 }
209 }
210
211}
212
213
214
215/*
216 * Add a path to the list of include paths.
217 */
218void add_path(const char * name)
219{
220 struct path_struct *path;
221 char resolved_path[PATH_MAX+1];
222 const char *name2;
223
224 if (strcmp(name, ".")) {
225 name2 = realpath(name, resolved_path);
226 if (!name2) {
227 fprintf(stderr, "realpath(%s) failed, %m\n", name);
228 exit(1);
229 }
230 }
231 else {
232 name2 = "";
233 }
234
235 path_array = realloc(path_array, (++paths)*sizeof(*path_array));
236 if (!path_array) {
237 fprintf(stderr, "cannot expand path_arry\n");
238 exit(1);
239 }
240
241 path = path_array+paths-1;
242 path->len = strlen(name2);
243 path->buffer = malloc(path->len+1+256+1);
244 if (!path->buffer) {
245 fprintf(stderr, "cannot allocate path buffer\n");
246 exit(1);
247 }
248 strcpy(path->buffer, name2);
249 if (path->len && *(path->buffer+path->len-1) != '/') {
250 *(path->buffer+path->len) = '/';
251 *(path->buffer+(++(path->len))) = '\0';
252 }
253}
254
255
256
257/*
258 * Record the use of a CONFIG_* word.
259 */
260void use_config(const char * name, int len)
261{
262 char *pc;
263 int i;
264
265 pc = path_array[paths-1].buffer + path_array[paths-1].len;
266 memcpy(pc, "config/", 7);
267 pc += 7;
268
269 for (i = 0; i < len; i++) {
270 char c = name[i];
271 if (isupper(c)) c = tolower(c);
272 if (c == '_') c = '/';
273 pc[i] = c;
274 }
275 pc[len] = '\0';
276
277 if (is_defined_config(pc, len))
278 return;
279
280 define_config(pc, len);
281
282 do_depname();
283 printf(" \\\n $(wildcard %s.h)", path_array[paths-1].buffer);
284}
285
286
287
288/*
289 * Macros for stunningly fast map-based character access.
290 * __buf is a register which holds the current word of the input.
291 * Thus, there is one memory access per sizeof(unsigned long) characters.
292 */
293
294#if defined(__alpha__) || defined(__i386__) || defined(__ia64__) || defined(__x86_64__) || defined(__MIPSEL__) \
295 || defined(__arm__)
296#define LE_MACHINE
297#endif
298
299#ifdef LE_MACHINE
300#define next_byte(x) (x >>= 8)
301#define current ((unsigned char) __buf)
302#else
303#define next_byte(x) (x <<= 8)
304#define current (__buf >> 8*(sizeof(unsigned long)-1))
305#endif
306
307#define GETNEXT { \
308 next_byte(__buf); \
309 if ((unsigned long) next % sizeof(unsigned long) == 0) { \
310 if (next >= end) \
311 break; \
312 __buf = * (unsigned long *) next; \
313 } \
314 next++; \
315}
316
317/*
318 * State machine macros.
319 */
320#define CASE(c,label) if (current == c) goto label
321#define NOTCASE(c,label) if (current != c) goto label
322
323/*
324 * Yet another state machine speedup.
325 */
326#define MAX2(a,b) ((a)>(b)?(a):(b))
327#define MIN2(a,b) ((a)<(b)?(a):(b))
328#define MAX5(a,b,c,d,e) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,e)))))
329#define MIN5(a,b,c,d,e) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,e)))))
330
331
332
333/*
334 * The state machine looks for (approximately) these Perl regular expressions:
335 *
336 * m|\/\*.*?\*\/|
337 * m|\/\/.*|
338 * m|'.*?'|
339 * m|".*?"|
340 * m|#\s*include\s*"(.*?)"|
341 * m|#\s*include\s*<(.*?>"|
342 * m|#\s*(?define|undef)\s*CONFIG_(\w*)|
343 * m|(?!\w)CONFIG_|
344 *
345 * About 98% of the CPU time is spent here, and most of that is in
346 * the 'start' paragraph. Because the current characters are
347 * in a register, the start loop usually eats 4 or 8 characters
348 * per memory read. The MAX5 and MIN5 tests dispose of most
349 * input characters with 1 or 2 comparisons.
350 */
351void state_machine(const char * map, const char * end)
352{
353 const char * next = map;
354 const char * map_dot;
355 unsigned long __buf = 0;
356
357 for (;;) {
358start:
359 GETNEXT
360__start:
361 if (current > MAX5('/','\'','"','#','C')) goto start;
362 if (current < MIN5('/','\'','"','#','C')) goto start;
363 CASE('/', slash);
364 CASE('\'', squote);
365 CASE('"', dquote);
366 CASE('#', pound);
367 CASE('C', cee);
368 goto start;
369
370/* // */
371slash_slash:
372 GETNEXT
373 CASE('\n', start);
374 NOTCASE('\\', slash_slash);
375 GETNEXT
376 goto slash_slash;
377
378/* / */
379slash:
380 GETNEXT
381 CASE('/', slash_slash);
382 NOTCASE('*', __start);
383slash_star_dot_star:
384 GETNEXT
385__slash_star_dot_star:
386 NOTCASE('*', slash_star_dot_star);
387 GETNEXT
388 NOTCASE('/', __slash_star_dot_star);
389 goto start;
390
391/* '.*?' */
392squote:
393 GETNEXT
394 CASE('\'', start);
395 NOTCASE('\\', squote);
396 GETNEXT
397 goto squote;
398
399/* ".*?" */
400dquote:
401 GETNEXT
402 CASE('"', start);
403 NOTCASE('\\', dquote);
404 GETNEXT
405 goto dquote;
406
407/* #\s* */
408pound:
409 GETNEXT
410 CASE(' ', pound);
411 CASE('\t', pound);
412 CASE('i', pound_i);
413 CASE('d', pound_d);
414 CASE('u', pound_u);
415 goto __start;
416
417/* #\s*i */
418pound_i:
419 GETNEXT NOTCASE('n', __start);
420 GETNEXT NOTCASE('c', __start);
421 GETNEXT NOTCASE('l', __start);
422 GETNEXT NOTCASE('u', __start);
423 GETNEXT NOTCASE('d', __start);
424 GETNEXT NOTCASE('e', __start);
425 goto pound_include;
426
427/* #\s*include\s* */
428pound_include:
429 GETNEXT
430 CASE(' ', pound_include);
431 CASE('\t', pound_include);
432 map_dot = next;
433 CASE('"', pound_include_dquote);
434 CASE('<', pound_include_langle);
435 goto __start;
436
437/* #\s*include\s*"(.*)" */
438pound_include_dquote:
439 GETNEXT
440 CASE('\n', start);
441 NOTCASE('"', pound_include_dquote);
442 handle_include(0, map_dot, next - map_dot - 1);
443 goto start;
444
445/* #\s*include\s*<(.*)> */
446pound_include_langle:
447 GETNEXT
448 CASE('\n', start);
449 NOTCASE('>', pound_include_langle);
450 handle_include(1, map_dot, next - map_dot - 1);
451 goto start;
452
453/* #\s*d */
454pound_d:
455 GETNEXT NOTCASE('e', __start);
456 GETNEXT NOTCASE('f', __start);
457 GETNEXT NOTCASE('i', __start);
458 GETNEXT NOTCASE('n', __start);
459 GETNEXT NOTCASE('e', __start);
460 goto pound_define_undef;
461
462/* #\s*u */
463pound_u:
464 GETNEXT NOTCASE('n', __start);
465 GETNEXT NOTCASE('d', __start);
466 GETNEXT NOTCASE('e', __start);
467 GETNEXT NOTCASE('f', __start);
468 goto pound_define_undef;
469
470/*
471 * #\s*(define|undef)\s*CONFIG_(\w*)
472 *
473 * this does not define the word, because it could be inside another
474 * conditional (#if 0). But I do parse the word so that this instance
475 * does not count as a use. -- mec
476 */
477pound_define_undef:
478 GETNEXT
479 CASE(' ', pound_define_undef);
480 CASE('\t', pound_define_undef);
481
482 NOTCASE('C', __start);
483 GETNEXT NOTCASE('O', __start);
484 GETNEXT NOTCASE('N', __start);
485 GETNEXT NOTCASE('F', __start);
486 GETNEXT NOTCASE('I', __start);
487 GETNEXT NOTCASE('G', __start);
488 GETNEXT NOTCASE('_', __start);
489
490 map_dot = next;
491pound_define_undef_CONFIG_word:
492 GETNEXT
493 if (isalnum(current) || current == '_')
494 goto pound_define_undef_CONFIG_word;
495 goto __start;
496
497/* \<CONFIG_(\w*) */
498cee:
499 if (next >= map+2 && (isalnum(next[-2]) || next[-2] == '_'))
500 goto start;
501 GETNEXT NOTCASE('O', __start);
502 GETNEXT NOTCASE('N', __start);
503 GETNEXT NOTCASE('F', __start);
504 GETNEXT NOTCASE('I', __start);
505 GETNEXT NOTCASE('G', __start);
506 GETNEXT NOTCASE('_', __start);
507
508 map_dot = next;
509cee_CONFIG_word:
510 GETNEXT
511 if (isalnum(current) || current == '_')
512 goto cee_CONFIG_word;
513 use_config(map_dot, next - map_dot - 1);
514 goto __start;
515 }
516}
517
518
519
520/*
521 * Generate dependencies for one file.
522 */
523void do_depend(const char * filename, const char * command)
524{
525 int mapsize;
526 int pagesizem1 = getpagesize()-1;
527 int fd;
528 struct stat st;
529 char * map;
530
531 fd = open(filename, O_RDONLY);
532 if (fd < 0) {
533 perror(filename);
534 return;
535 }
536
537 fstat(fd, &st);
538 if (st.st_size == 0) {
539 fprintf(stderr,"%s is empty\n",filename);
540 close(fd);
541 return;
542 }
543
544 mapsize = st.st_size;
545 mapsize = (mapsize+pagesizem1) & ~pagesizem1;
546 map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
547 if ((long) map == -1) {
548 perror("mkdep: mmap");
549 close(fd);
550 return;
551 }
552 if ((unsigned long) map % sizeof(unsigned long) != 0)
553 {
554 fprintf(stderr, "do_depend: map not aligned\n");
555 exit(1);
556 }
557
558 hasdep = 0;
559 clear_config();
560 state_machine(map, map+st.st_size);
561 if (hasdep) {
562 puts(command);
563 if (*command)
564 define_precious(filename);
565 }
566
567 munmap(map, mapsize);
568 close(fd);
569}
570
571
572
573/*
574 * Generate dependencies for all files.
575 */
576int main(int argc, char **argv)
577{
578 int len;
579 const char *hpath;
580
581 hpath = getenv("TOPDIR");
582 if (!hpath) {
583 fputs("mkdep: TOPDIR not set in environment. "
584 "Don't bypass the top level Makefile.\n", stderr);
585 return 1;
586 }
587
588 add_path("."); /* for #include "..." */
589
590 while (++argv, --argc > 0) {
591 if (strncmp(*argv, "-I", 2) == 0) {
592 if (*((*argv)+2)) {
593 add_path((*argv)+2);
594 }
595 else {
596 ++argv;
597 --argc;
598 add_path(*argv);
599 }
600 }
601 else if (strcmp(*argv, "--") == 0) {
602 break;
603 }
604 }
605
606 add_path(hpath); /* must be last entry, for config files */
607
608 while (--argc > 0) {
609 const char * filename = *++argv;
610 const char * command = __depname;
611 g_filename = 0;
612 len = strlen(filename);
613 memcpy(depname, filename, len+1);
614 if (len > 2 && filename[len-2] == '.') {
615 if (filename[len-1] == 'c' || filename[len-1] == 'S') {
616 depname[len-1] = 'o';
617 g_filename = filename;
618 command = "";
619 }
620 }
621 do_depend(filename, command);
622 }
623 if (len_precious) {
624 *(str_precious+len_precious) = '\0';
625 printf(".PRECIOUS:%s\n", str_precious);
626 }
627 return 0;
628}
diff --git a/scripts/split-include.c b/scripts/split-include.c
new file mode 100644
index 000000000..3ab9fed87
--- /dev/null
+++ b/scripts/split-include.c
@@ -0,0 +1,226 @@
1/*
2 * split-include.c
3 *
4 * Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
5 * This is a C version of syncdep.pl by Werner Almesberger.
6 *
7 * This program takes autoconf.h as input and outputs a directory full
8 * of one-line include files, merging onto the old values.
9 *
10 * Think of the configuration options as key-value pairs. Then there
11 * are five cases:
12 *
13 * key old value new value action
14 *
15 * KEY-1 VALUE-1 VALUE-1 leave file alone
16 * KEY-2 VALUE-2A VALUE-2B write VALUE-2B into file
17 * KEY-3 - VALUE-3 write VALUE-3 into file
18 * KEY-4 VALUE-4 - write an empty file
19 * KEY-5 (empty) - leave old empty file alone
20 */
21
22#include <sys/stat.h>
23#include <sys/types.h>
24
25#include <ctype.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#define ERROR_EXIT(strExit) \
34 { \
35 const int errnoSave = errno; \
36 fprintf(stderr, "%s: ", str_my_name); \
37 errno = errnoSave; \
38 perror((strExit)); \
39 exit(1); \
40 }
41
42
43
44int main(int argc, const char * argv [])
45{
46 const char * str_my_name;
47 const char * str_file_autoconf;
48 const char * str_dir_config;
49
50 FILE * fp_config;
51 FILE * fp_target;
52 FILE * fp_find;
53
54 int buffer_size;
55
56 char * line;
57 char * old_line;
58 char * list_target;
59 char * ptarget;
60
61 struct stat stat_buf;
62
63 /* Check arg count. */
64 if (argc != 3)
65 {
66 fprintf(stderr, "%s: wrong number of arguments.\n", argv[0]);
67 exit(1);
68 }
69
70 str_my_name = argv[0];
71 str_file_autoconf = argv[1];
72 str_dir_config = argv[2];
73
74 /* Find a buffer size. */
75 if (stat(str_file_autoconf, &stat_buf) != 0)
76 ERROR_EXIT(str_file_autoconf);
77 buffer_size = 2 * stat_buf.st_size + 4096;
78
79 /* Allocate buffers. */
80 if ( (line = malloc(buffer_size)) == NULL
81 || (old_line = malloc(buffer_size)) == NULL
82 || (list_target = malloc(buffer_size)) == NULL )
83 ERROR_EXIT(str_file_autoconf);
84
85 /* Open autoconfig file. */
86 if ((fp_config = fopen(str_file_autoconf, "r")) == NULL)
87 ERROR_EXIT(str_file_autoconf);
88
89 /* Make output directory if needed. */
90 if (stat(str_dir_config, &stat_buf) != 0)
91 {
92 if (mkdir(str_dir_config, 0755) != 0)
93 ERROR_EXIT(str_dir_config);
94 }
95
96 /* Change to output directory. */
97 if (chdir(str_dir_config) != 0)
98 ERROR_EXIT(str_dir_config);
99
100 /* Put initial separator into target list. */
101 ptarget = list_target;
102 *ptarget++ = '\n';
103
104 /* Read config lines. */
105 while (fgets(line, buffer_size, fp_config))
106 {
107 const char * str_config;
108 int is_same;
109 int itarget;
110
111 if (line[0] != '#')
112 continue;
113 if ((str_config = strstr(line, "CONFIG_")) == NULL)
114 continue;
115
116 /* Make the output file name. */
117 str_config += sizeof("CONFIG_") - 1;
118 for (itarget = 0; !isspace(str_config[itarget]); itarget++)
119 {
120 char c = str_config[itarget];
121 if (isupper(c)) c = tolower(c);
122 if (c == '_') c = '/';
123 ptarget[itarget] = c;
124 }
125 ptarget[itarget++] = '.';
126 ptarget[itarget++] = 'h';
127 ptarget[itarget++] = '\0';
128
129 /* Check for existing file. */
130 is_same = 0;
131 if ((fp_target = fopen(ptarget, "r")) != NULL)
132 {
133 fgets(old_line, buffer_size, fp_target);
134 if (fclose(fp_target) != 0)
135 ERROR_EXIT(ptarget);
136 if (!strcmp(line, old_line))
137 is_same = 1;
138 }
139
140 if (!is_same)
141 {
142 /* Auto-create directories. */
143 int islash;
144 for (islash = 0; islash < itarget; islash++)
145 {
146 if (ptarget[islash] == '/')
147 {
148 ptarget[islash] = '\0';
149 if (stat(ptarget, &stat_buf) != 0
150 && mkdir(ptarget, 0755) != 0)
151 ERROR_EXIT( ptarget );
152 ptarget[islash] = '/';
153 }
154 }
155
156 /* Write the file. */
157 if ((fp_target = fopen(ptarget, "w" )) == NULL)
158 ERROR_EXIT(ptarget);
159 fputs(line, fp_target);
160 if (ferror(fp_target) || fclose(fp_target) != 0)
161 ERROR_EXIT(ptarget);
162 }
163
164 /* Update target list */
165 ptarget += itarget;
166 *(ptarget-1) = '\n';
167 }
168
169 /*
170 * Close autoconfig file.
171 * Terminate the target list.
172 */
173 if (fclose(fp_config) != 0)
174 ERROR_EXIT(str_file_autoconf);
175 *ptarget = '\0';
176
177 /*
178 * Fix up existing files which have no new value.
179 * This is Case 4 and Case 5.
180 *
181 * I re-read the tree and filter it against list_target.
182 * This is crude. But it avoids data copies. Also, list_target
183 * is compact and contiguous, so it easily fits into cache.
184 *
185 * Notice that list_target contains strings separated by \n,
186 * with a \n before the first string and after the last.
187 * fgets gives the incoming names a terminating \n.
188 * So by having an initial \n, strstr will find exact matches.
189 */
190
191 fp_find = popen("find * -type f -name \"*.h\" -print", "r");
192 if (fp_find == 0)
193 ERROR_EXIT( "find" );
194
195 line[0] = '\n';
196 while (fgets(line+1, buffer_size, fp_find))
197 {
198 if (strstr(list_target, line) == NULL)
199 {
200 /*
201 * This is an old file with no CONFIG_* flag in autoconf.h.
202 */
203
204 /* First strip the \n. */
205 line[strlen(line)-1] = '\0';
206
207 /* Grab size. */
208 if (stat(line+1, &stat_buf) != 0)
209 ERROR_EXIT(line);
210
211 /* If file is not empty, make it empty and give it a fresh date. */
212 if (stat_buf.st_size != 0)
213 {
214 if ((fp_target = fopen(line+1, "w")) == NULL)
215 ERROR_EXIT(line);
216 if (fclose(fp_target) != 0)
217 ERROR_EXIT(line);
218 }
219 }
220 }
221
222 if (pclose(fp_find) != 0)
223 ERROR_EXIT("find");
224
225 return 0;
226}
diff --git a/scripts/undeb b/scripts/undeb
deleted file mode 100644
index a72e1e2ba..000000000
--- a/scripts/undeb
+++ /dev/null
@@ -1,53 +0,0 @@
1#!/bin/sh
2#
3# This should work with the GNU version of tar and gzip!
4# This should work with the bash or ash shell!
5# Requires the programs (ar, tar, gzip, and the pager more or less).
6#
7usage() {
8echo "Usage: undeb -c package.deb <Print control file info>"
9echo " undeb -l package.deb <List contents of deb package>"
10echo " undeb -x package.deb /foo/boo <Extract deb package to this directory,"
11echo " put . for current directory>"
12exit
13}
14
15deb=$2
16
17exist() {
18if [ "$deb" = "" ]; then
19usage
20elif [ ! -s "$deb" ]; then
21echo "Can't find $deb!"
22exit
23fi
24}
25
26if [ "$1" = "" ]; then
27usage
28elif [ "$1" = "-l" ]; then
29exist
30type more >/dev/null 2>&1 && pager=more
31type less >/dev/null 2>&1 && pager=less
32[ "$pager" = "" ] && echo "No pager found!" && exit
33(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
34exit
35elif [ "$1" = "-c" ]; then
36exist
37ar -p $deb control.tar.gz | tar -xzO *control
38exit
39elif [ "$1" = "-x" ]; then
40exist
41if [ "$3" = "" ]; then
42usage
43elif [ ! -d "$3" ]; then
44echo "No such directory $3!"
45exit
46fi
47ar -p $deb data.tar.gz | tar -xzvpf - -C $3 || exit
48echo
49echo "Extracted $deb to $3!"
50exit
51else
52usage
53fi
diff --git a/scripts/unrpm b/scripts/unrpm
deleted file mode 100644
index 376286a6f..000000000
--- a/scripts/unrpm
+++ /dev/null
@@ -1,48 +0,0 @@
1#!/bin/sh
2#
3# This should work with the GNU version of cpio and gzip!
4# This should work with the bash or ash shell!
5# Requires the programs (cpio, gzip, and the pager more or less).
6#
7usage() {
8echo "Usage: unrpm -l package.rpm <List contents of rpm package>"
9echo " unrpm -x package.rpm /foo/boo <Extract rpm package to this directory,"
10echo " put . for current directory>"
11exit
12}
13
14rpm=$2
15
16exist() {
17if [ "$rpm" = "" ]; then
18usage
19elif [ ! -s "$rpm" ]; then
20echo "Can't find $rpm!"
21exit
22fi
23}
24
25if [ "$1" = "" ]; then
26usage
27elif [ "$1" = "-l" ]; then
28exist
29type more >/dev/null 2>&1 && pager=more
30type less >/dev/null 2>&1 && pager=less
31[ "$pager" = "" ] && echo "No pager found!" && exit
32(echo -e "\nPress enter to scroll, q to Quit!\n" ; rpm2cpio $rpm | cpio -tv --quiet) | $pager
33exit
34elif [ "$1" = "-x" ]; then
35exist
36if [ "$3" = "" ]; then
37usage
38elif [ ! -d "$3" ]; then
39echo "No such directory $3!"
40exit
41fi
42rpm2cpio $rpm | (umask 0 ; cd $3 ; cpio -idmuv) || exit
43echo
44echo "Extracted $rpm to $3!"
45exit
46else
47usage
48fi
diff --git a/sed.c b/sed.c
deleted file mode 100644
index 709fb13a8..000000000
--- a/sed.c
+++ /dev/null
@@ -1,850 +0,0 @@
1/*
2 * sed.c - very minimalist version of sed
3 *
4 * Copyright (C) 1999,2000,2001 by Lineo, inc.
5 * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23/*
24 Supported features and commands in this version of sed:
25
26 - comments ('#')
27 - address matching: num|/matchstr/[,num|/matchstr/|$]command
28 - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
29 - edit commands: (a)ppend, (i)nsert, (c)hange
30 - file commands: (r)ead
31 - backreferences in substitution expressions (\1, \2...\9)
32
33 (Note: Specifying an address (range) to match is *optional*; commands
34 default to the whole pattern space if no specific address match was
35 requested.)
36
37 Unsupported features:
38
39 - transliteration (y/source-chars/dest-chars/) (use 'tr')
40 - no pattern space hold space storing / swapping (x, etc.)
41 - no labels / branching (: label, b, t, and friends)
42 - and lots, lots more.
43*/
44
45#include <stdio.h>
46#include <unistd.h> /* for getopt() */
47#include <regex.h>
48#include <string.h> /* for strdup() */
49#include <errno.h>
50#include <ctype.h> /* for isspace() */
51#include <stdlib.h>
52#include "busybox.h"
53
54/* externs */
55extern void xregcomp(regex_t *preg, const char *regex, int cflags);
56extern int optind; /* in unistd.h */
57extern char *optarg; /* ditto */
58
59/* options */
60static int be_quiet = 0;
61
62
63struct sed_cmd {
64
65
66 /* GENERAL FIELDS */
67 char delimiter; /* The delimiter used to separate regexps */
68
69 /* address storage */
70 int beg_line; /* 'sed 1p' 0 == no begining line, apply commands to all lines */
71 int end_line; /* 'sed 1,3p' 0 == no end line, use only beginning. -1 == $ */
72 regex_t *beg_match; /* sed -e '/match/cmd' */
73 regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */
74
75 /* the command */
76 char cmd; /* p,d,s (add more at your leisure :-) */
77
78
79 /* SUBSTITUTION COMMAND SPECIFIC FIELDS */
80
81 /* sed -e 's/sub_match/replace/' */
82 regex_t *sub_match;
83 char *replace;
84 unsigned int num_backrefs:4; /* how many back references (\1..\9) */
85 /* Note: GNU/POSIX sed does not save more than nine backrefs, so
86 * we only use 4 bits to hold the number */
87 unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */
88 unsigned int sub_p:2; /* sed -e 's/foo/bar/p' (print substitution) */
89
90
91 /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */
92
93 char *editline;
94
95
96 /* FILE COMMAND (r) SPEICIFIC FIELDS */
97
98 char *filename;
99};
100
101/* globals */
102static struct sed_cmd *sed_cmds = NULL; /* growable arrary holding a sequence of sed cmds */
103static int ncmds = 0; /* number of sed commands */
104
105/*static char *cur_file = NULL;*/ /* file currently being processed XXX: do I need this? */
106
107#ifdef BB_FEATURE_CLEAN_UP
108static void destroy_cmd_strs()
109{
110 if (sed_cmds == NULL)
111 return;
112
113 /* destroy all the elements in the array */
114 while (--ncmds >= 0) {
115
116 if (sed_cmds[ncmds].beg_match) {
117 regfree(sed_cmds[ncmds].beg_match);
118 free(sed_cmds[ncmds].beg_match);
119 }
120 if (sed_cmds[ncmds].end_match) {
121 regfree(sed_cmds[ncmds].end_match);
122 free(sed_cmds[ncmds].end_match);
123 }
124 if (sed_cmds[ncmds].sub_match) {
125 regfree(sed_cmds[ncmds].sub_match);
126 free(sed_cmds[ncmds].sub_match);
127 }
128 if (sed_cmds[ncmds].replace)
129 free(sed_cmds[ncmds].replace);
130 }
131
132 /* destroy the array */
133 free(sed_cmds);
134 sed_cmds = NULL;
135}
136#endif
137
138
139/*
140 * index_of_next_unescaped_regexp_delim - walks left to right through a string
141 * beginning at a specified index and returns the index of the next regular
142 * expression delimiter (typically a forward * slash ('/')) not preceeded by
143 * a backslash ('\').
144 */
145static int index_of_next_unescaped_regexp_delim(struct sed_cmd *sed_cmd, const char *str, int idx)
146{
147 int bracket = -1;
148 int escaped = 0;
149
150 for ( ; str[idx]; idx++) {
151 if (bracket != -1) {
152 if (str[idx] == ']' && !(bracket == idx - 1 ||
153 (bracket == idx - 2 && str[idx-1] == '^')))
154 bracket = -1;
155 } else if (escaped)
156 escaped = 0;
157 else if (str[idx] == '\\')
158 escaped = 1;
159 else if (str[idx] == '[')
160 bracket = idx;
161 else if (str[idx] == sed_cmd->delimiter)
162 return idx;
163 }
164
165 /* if we make it to here, we've hit the end of the string */
166 return -1;
167}
168
169/*
170 * returns the index in the string just past where the address ends.
171 */
172static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex)
173{
174 char *my_str = strdup(str);
175 int idx = 0;
176 char olddelimiter;
177 olddelimiter = sed_cmd->delimiter;
178 sed_cmd->delimiter = '/';
179
180 if (isdigit(my_str[idx])) {
181 do {
182 idx++;
183 } while (isdigit(my_str[idx]));
184 my_str[idx] = 0;
185 *linenum = atoi(my_str);
186 }
187 else if (my_str[idx] == '$') {
188 *linenum = -1;
189 idx++;
190 }
191 else if (my_str[idx] == '/') {
192 idx = index_of_next_unescaped_regexp_delim(sed_cmd, my_str, ++idx);
193 if (idx == -1)
194 error_msg_and_die("unterminated match expression");
195 my_str[idx] = '\0';
196 *regex = (regex_t *)xmalloc(sizeof(regex_t));
197 xregcomp(*regex, my_str+1, REG_NEWLINE);
198 idx++; /* so it points to the next character after the last '/' */
199 }
200 else {
201 error_msg("get_address: no address found in string\n"
202 "\t(you probably didn't check the string you passed me)");
203 idx = -1;
204 }
205
206 free(my_str);
207 sed_cmd->delimiter = olddelimiter;
208 return idx;
209}
210
211static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
212{
213 int oldidx, cflags = REG_NEWLINE;
214 char *match;
215 int idx = 0;
216 int j;
217
218 /*
219 * the string that gets passed to this function should look like this:
220 * s/match/replace/gIp
221 * || | |||
222 * mandatory optional
223 *
224 * (all three of the '/' slashes are mandatory)
225 */
226
227 /* verify that the 's' is followed by something. That something
228 * (typically a 'slash') is now our regexp delimiter... */
229 if (!substr[++idx])
230 error_msg_and_die("bad format in substitution expression");
231 else
232 sed_cmd->delimiter=substr[idx];
233
234 /* save the match string */
235 oldidx = idx+1;
236 idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx);
237 if (idx == -1)
238 error_msg_and_die("bad format in substitution expression");
239 match = xstrndup(substr + oldidx, idx - oldidx);
240
241 /* determine the number of back references in the match string */
242 /* Note: we compute this here rather than in the do_subst_command()
243 * function to save processor time, at the expense of a little more memory
244 * (4 bits) per sed_cmd */
245
246 /* sed_cmd->num_backrefs = 0; */ /* XXX: not needed? --apparently not */
247 for (j = 0; match[j]; j++) {
248 /* GNU/POSIX sed does not save more than nine backrefs */
249 if (match[j] == '\\' && match[j+1] == '(' && sed_cmd->num_backrefs <= 9)
250 sed_cmd->num_backrefs++;
251 }
252
253 /* save the replacement string */
254 oldidx = idx+1;
255 idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx);
256 if (idx == -1)
257 error_msg_and_die("bad format in substitution expression");
258 sed_cmd->replace = xstrndup(substr + oldidx, idx - oldidx);
259
260 /* process the flags */
261 while (substr[++idx]) {
262 switch (substr[idx]) {
263 case 'g':
264 sed_cmd->sub_g = 1;
265 break;
266 case 'I':
267 cflags |= REG_ICASE;
268 break;
269 case 'p':
270 sed_cmd->sub_p = 1;
271 break;
272 default:
273 /* any whitespace or semicolon trailing after a s/// is ok */
274 if (strchr("; \t\v\n\r", substr[idx]))
275 goto out;
276 /* else */
277 error_msg_and_die("bad option in substitution expression");
278 }
279 }
280
281out:
282 /* compile the match string into a regex */
283 sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t));
284 xregcomp(sed_cmd->sub_match, match, cflags);
285 free(match);
286
287 return idx;
288}
289
290static int parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
291{
292 int idx = 0;
293 int slashes_eaten = 0;
294 char *ptr; /* shorthand */
295
296 /*
297 * the string that gets passed to this function should look like this:
298 *
299 * need one of these
300 * |
301 * | this backslash (immediately following the edit command) is mandatory
302 * | |
303 * [aic]\
304 * TEXT1\
305 * TEXT2\
306 * TEXTN
307 *
308 * as soon as we hit a TEXT line that has no trailing '\', we're done.
309 * this means a command like:
310 *
311 * i\
312 * INSERTME
313 *
314 * is a-ok.
315 *
316 */
317
318 if (editstr[1] != '\\' && (editstr[2] != '\n' || editstr[2] != '\r'))
319 error_msg_and_die("bad format in edit expression");
320
321 /* store the edit line text */
322 /* make editline big enough to accomodate the extra '\n' we will tack on
323 * to the end */
324 sed_cmd->editline = xmalloc(strlen(&editstr[3]) + 2);
325 strcpy(sed_cmd->editline, &editstr[3]);
326 ptr = sed_cmd->editline;
327
328 /* now we need to go through * and: s/\\[\r\n]$/\n/g on the edit line */
329 while (ptr[idx]) {
330 while (ptr[idx] != '\\' || (ptr[idx+1] != '\n' && ptr[idx+1] != '\r')) {
331 idx++;
332 if (!ptr[idx]) {
333 goto out;
334 }
335 }
336 /* move the newline over the '\' before it (effectively eats the '\') */
337 memmove(&ptr[idx], &ptr[idx+1], strlen(&ptr[idx+1]));
338 ptr[strlen(ptr)-1] = 0;
339 slashes_eaten++;
340 /* substitue \r for \n if needed */
341 if (ptr[idx] == '\r')
342 ptr[idx] = '\n';
343 }
344
345out:
346 /* this accounts for discrepancies between the modified string and the
347 * original string passed in to this function */
348 idx += slashes_eaten;
349
350 /* figure out if we need to add a newline */
351 if (ptr[idx-1] != '\n') {
352 ptr[idx] = '\n';
353 idx++;
354 }
355
356 /* terminate string */
357 ptr[idx]= 0;
358 /* adjust for opening 2 chars [aic]\ */
359 idx += 2;
360
361 return idx;
362}
363
364
365static int parse_file_cmd(struct sed_cmd *sed_cmd, const char *filecmdstr)
366{
367 int idx = 0;
368 int filenamelen = 0;
369
370 /*
371 * the string that gets passed to this function should look like this:
372 * '[ ]filename'
373 * | |
374 * | a filename
375 * |
376 * optional whitespace
377
378 * re: the file to be read, the GNU manual says the following: "Note that
379 * if filename cannot be read, it is treated as if it were an empty file,
380 * without any error indication." Thus, all of the following commands are
381 * perfectly leagal:
382 *
383 * sed -e '1r noexist'
384 * sed -e '1r ;'
385 * sed -e '1r'
386 */
387
388 /* the file command may be followed by whitespace; move past it. */
389 while (isspace(filecmdstr[++idx]))
390 { ; }
391
392 /* the first non-whitespace we get is a filename. the filename ends when we
393 * hit a normal sed command terminator or end of string */
394 filenamelen = strcspn(&filecmdstr[idx], "; \n\r\t\v\0");
395 sed_cmd->filename = xmalloc(filenamelen + 1);
396 safe_strncpy(sed_cmd->filename, &filecmdstr[idx], filenamelen + 1);
397
398 return idx + filenamelen;
399}
400
401
402static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
403{
404 int idx = 0;
405
406 /* parse the command
407 * format is: [addr][,addr]cmd
408 * |----||-----||-|
409 * part1 part2 part3
410 */
411
412 /* first part (if present) is an address: either a number or a /regex/ */
413 if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/')
414 idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
415
416 /* second part (if present) will begin with a comma */
417 if (cmdstr[idx] == ',')
418 idx += get_address(sed_cmd, &cmdstr[++idx], &sed_cmd->end_line, &sed_cmd->end_match);
419
420 /* last part (mandatory) will be a command */
421 if (cmdstr[idx] == '\0')
422 error_msg_and_die("missing command");
423 sed_cmd->cmd = cmdstr[idx];
424
425 /* if it was a single-letter command that takes no arguments (such as 'p'
426 * or 'd') all we need to do is increment the index past that command */
427 if (strchr("pd", cmdstr[idx])) {
428 idx++;
429 }
430 /* handle (s)ubstitution command */
431 else if (sed_cmd->cmd == 's') {
432 idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);
433 }
434 /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
435 else if (strchr("aic", sed_cmd->cmd)) {
436 if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')
437 error_msg_and_die("only a beginning address can be specified for edit commands");
438 idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]);
439 }
440 /* handle file cmds: (r)ead */
441 else if (sed_cmd->cmd == 'r') {
442 if (sed_cmd->end_line || sed_cmd->end_match)
443 error_msg_and_die("Command only uses one address");
444 idx += parse_file_cmd(sed_cmd, &cmdstr[idx]);
445 }
446 else {
447 error_msg_and_die("invalid command");
448 }
449
450 /* give back whatever's left over */
451 return (char *)&cmdstr[idx];
452}
453
454static void add_cmd_str(const char *cmdstr)
455{
456 char *mystr = (char *)cmdstr;
457
458 do {
459
460 /* trim leading whitespace and semicolons */
461 memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr));
462 /* if we ate the whole thing, that means there was just trailing
463 * whitespace or a final / no-op semicolon. either way, get out */
464 if (strlen(mystr) == 0)
465 return;
466 /* if this is a comment, jump past it and keep going */
467 if (mystr[0] == '#') {
468 mystr = strpbrk(mystr, ";\n\r");
469 continue;
470 }
471 /* grow the array */
472 sed_cmds = xrealloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds));
473 /* zero new element */
474 memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd));
475 /* load command string into new array element, get remainder */
476 mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr);
477
478 } while (mystr && strlen(mystr));
479}
480
481
482static void load_cmd_file(char *filename)
483{
484 FILE *cmdfile;
485 char *line;
486 char *nextline;
487
488 cmdfile = xfopen(filename, "r");
489
490 while ((line = get_line_from_file(cmdfile)) != NULL) {
491 /* if a line ends with '\' it needs the next line appended to it */
492 while (line[strlen(line)-2] == '\\' &&
493 (nextline = get_line_from_file(cmdfile)) != NULL) {
494 line = xrealloc(line, strlen(line) + strlen(nextline) + 1);
495 strcat(line, nextline);
496 free(nextline);
497 }
498 /* eat trailing newline (if any) --if I don't do this, edit commands
499 * (aic) will print an extra newline */
500 chomp(line);
501 add_cmd_str(line);
502 free(line);
503 }
504}
505
506#define PIPE_MAGIC 0x7f
507#define PIPE_GROW 64
508#define pipeputc(c) \
509{ if (pipeline[pipeline_idx] == PIPE_MAGIC) { \
510 pipeline = xrealloc(pipeline, pipeline_len+PIPE_GROW); \
511 memset(pipeline+pipeline_len, 0, PIPE_GROW); \
512 pipeline_len += PIPE_GROW; \
513 pipeline[pipeline_len-1] = PIPE_MAGIC; } \
514 pipeline[pipeline_idx++] = (c); }
515
516static void print_subst_w_backrefs(const char *line, const char *replace,
517 regmatch_t *regmatch, char **pipeline_p, int *pipeline_idx_p,
518 int *pipeline_len_p, int matches)
519{
520 char *pipeline = *pipeline_p;
521 int pipeline_idx = *pipeline_idx_p;
522 int pipeline_len = *pipeline_len_p;
523 int i;
524
525 /* go through the replacement string */
526 for (i = 0; replace[i]; i++) {
527 /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */
528 if (replace[i] == '\\' && isdigit(replace[i+1])) {
529 int j;
530 char tmpstr[2];
531 int backref;
532 ++i; /* i now indexes the backref number, instead of the leading slash */
533 tmpstr[0] = replace[i];
534 tmpstr[1] = 0;
535 backref = atoi(tmpstr);
536 /* print out the text held in regmatch[backref] */
537 if (backref <= matches && regmatch[backref].rm_so != -1)
538 for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++)
539 pipeputc(line[j]);
540 }
541
542 /* if we find a backslash escaped character, print the character */
543 else if (replace[i] == '\\') {
544 ++i;
545 pipeputc(replace[i]);
546 }
547
548 /* if we find an unescaped '&' print out the whole matched text.
549 * fortunately, regmatch[0] contains the indicies to the whole matched
550 * expression (kinda seems like it was designed for just such a
551 * purpose...) */
552 else if (replace[i] == '&' && replace[i-1] != '\\') {
553 int j;
554 for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++)
555 pipeputc(line[j]);
556 }
557 /* nothing special, just print this char of the replacement string to stdout */
558 else
559 pipeputc(replace[i]);
560 }
561 *pipeline_p = pipeline;
562 *pipeline_idx_p = pipeline_idx;
563 *pipeline_len_p = pipeline_len;
564}
565
566static int do_subst_command(const struct sed_cmd *sed_cmd, char **line)
567{
568 char *hackline = *line;
569 char *pipeline = 0;
570 int pipeline_idx = 0;
571 int pipeline_len = 0;
572 int altered = 0;
573 regmatch_t *regmatch = NULL;
574
575 /* we only proceed if the substitution 'search' expression matches */
576 if (regexec(sed_cmd->sub_match, hackline, 0, NULL, 0) == REG_NOMATCH)
577 return 0;
578
579 /* whaddaya know, it matched. get the number of back references */
580 regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1));
581
582 /* allocate more PIPE_GROW bytes
583 if replaced string is larger than original */
584 pipeline_len = strlen(hackline)+PIPE_GROW;
585 pipeline = xmalloc(pipeline_len);
586 memset(pipeline, 0, pipeline_len);
587 /* buffer magic */
588 pipeline[pipeline_len-1] = PIPE_MAGIC;
589
590 /* and now, as long as we've got a line to try matching and if we can match
591 * the search string, we make substitutions */
592 while ((*hackline || !altered) && (regexec(sed_cmd->sub_match, hackline,
593 sed_cmd->num_backrefs+1, regmatch, 0) != REG_NOMATCH) ) {
594 int i;
595
596 /* print everything before the match */
597 for (i = 0; i < regmatch[0].rm_so; i++)
598 pipeputc(hackline[i]);
599
600 /* then print the substitution string */
601 print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch,
602 &pipeline, &pipeline_idx, &pipeline_len,
603 sed_cmd->num_backrefs);
604
605 /* advance past the match */
606 hackline += regmatch[0].rm_eo;
607 /* flag that something has changed */
608 altered++;
609
610 /* if we're not doing this globally, get out now */
611 if (!sed_cmd->sub_g)
612 break;
613 }
614
615 for (; *hackline; hackline++) pipeputc(*hackline);
616 if (pipeline[pipeline_idx] == PIPE_MAGIC) pipeline[pipeline_idx] = 0;
617
618 /* cleanup */
619 free(regmatch);
620
621 free(*line);
622 *line = pipeline;
623 return altered;
624}
625
626
627static void process_file(FILE *file)
628{
629 char *line = NULL;
630 static int linenum = 0; /* GNU sed does not restart counting lines at EOF */
631 unsigned int still_in_range = 0;
632 int altered;
633 int i;
634
635 /* go through every line in the file */
636 while ((line = get_line_from_file(file)) != NULL) {
637
638 chomp(line);
639 linenum++;
640 altered = 0;
641
642 /* for every line, go through all the commands */
643 for (i = 0; i < ncmds; i++) {
644
645
646 /*
647 * entry point into sedding...
648 */
649 if (
650 /* no range necessary */
651 (sed_cmds[i].beg_line == 0 && sed_cmds[i].end_line == 0 &&
652 sed_cmds[i].beg_match == NULL &&
653 sed_cmds[i].end_match == NULL) ||
654 /* this line number is the first address we're looking for */
655 (sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) ||
656 /* this line matches our first address regex */
657 (sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) ||
658 /* we are currently within the beginning & ending address range */
659 still_in_range
660 ) {
661
662 /*
663 * actual sedding
664 */
665 switch (sed_cmds[i].cmd) {
666
667 case 'p':
668 puts(line);
669 break;
670
671 case 'd':
672 altered++;
673 break;
674
675 case 's':
676
677 /*
678 * Some special cases for 's' printing to make it compliant with
679 * GNU sed printing behavior (aka "The -n | s///p Matrix"):
680 *
681 * -n ONLY = never print anything regardless of any successful
682 * substitution
683 *
684 * s///p ONLY = always print successful substitutions, even if
685 * the line is going to be printed anyway (line will be printed
686 * twice).
687 *
688 * -n AND s///p = print ONLY a successful substitution ONE TIME;
689 * no other lines are printed - this is the reason why the 'p'
690 * flag exists in the first place.
691 */
692
693 /* if the user specified that they didn't want anything printed (i.e., a -n
694 * flag and no 'p' flag after the s///), then there's really no point doing
695 * anything here. */
696 if (be_quiet && !sed_cmds[i].sub_p)
697 break;
698
699 /* we print the line once, unless we were told to be quiet */
700 if (!be_quiet)
701 altered |= do_subst_command(&sed_cmds[i], &line);
702
703 /* we also print the line if we were given the 'p' flag
704 * (this is quite possibly the second printing) */
705 if (sed_cmds[i].sub_p)
706 altered |= do_subst_command(&sed_cmds[i], &line);
707 if (altered && (i+1 >= ncmds || sed_cmds[i+1].cmd != 's'))
708 puts(line);
709
710 break;
711
712 case 'a':
713 puts(line);
714 fputs(sed_cmds[i].editline, stdout);
715 altered++;
716 break;
717
718 case 'i':
719 fputs(sed_cmds[i].editline, stdout);
720 break;
721
722 case 'c':
723 /* single-address case */
724 if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) {
725 fputs(sed_cmds[i].editline, stdout);
726 }
727 /* multi-address case */
728 else {
729 /* matching text */
730 if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
731 fputs(sed_cmds[i].editline, stdout);
732 /* matching line numbers */
733 if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum)
734 fputs(sed_cmds[i].editline, stdout);
735 }
736 altered++;
737
738 break;
739
740 case 'r': {
741 FILE *outfile;
742 puts(line);
743 outfile = fopen(sed_cmds[i].filename, "r");
744 if (outfile)
745 print_file(outfile);
746 /* else if we couldn't open the output file,
747 * no biggie, just don't print anything */
748 altered++;
749 }
750 break;
751 }
752
753 /*
754 * exit point from sedding...
755 */
756 if (
757 /* this is a single-address command or... */
758 (sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || (
759 /* we were in the middle of our address range (this
760 * isn't the first time through) and.. */
761 (still_in_range == 1) && (
762 /* this line number is the last address we're looking for or... */
763 (sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) ||
764 /* this line matches our last address regex */
765 (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
766 )
767 )
768 ) {
769 /* we're out of our address range */
770 still_in_range = 0;
771 }
772
773 /* didn't hit the exit? then we're still in the middle of an address range */
774 else {
775 still_in_range = 1;
776 }
777 }
778 }
779
780 /* we will print the line unless we were told to be quiet or if the
781 * line was altered (via a 'd'elete or 's'ubstitution), in which case
782 * the altered line was already printed */
783 if (!be_quiet && !altered)
784 puts(line);
785
786 free(line);
787 }
788}
789
790extern int sed_main(int argc, char **argv)
791{
792 int opt;
793
794#ifdef BB_FEATURE_CLEAN_UP
795 /* destroy command strings on exit */
796 if (atexit(destroy_cmd_strs) == -1)
797 perror_msg_and_die("atexit");
798#endif
799
800 /* do normal option parsing */
801 while ((opt = getopt(argc, argv, "ne:f:")) > 0) {
802 switch (opt) {
803 case 'n':
804 be_quiet++;
805 break;
806 case 'e':
807 add_cmd_str(optarg);
808 break;
809 case 'f':
810 load_cmd_file(optarg);
811 break;
812 default:
813 show_usage();
814 }
815 }
816
817 /* if we didn't get a pattern from a -e and no command file was specified,
818 * argv[optind] should be the pattern. no pattern, no worky */
819 if (ncmds == 0) {
820 if (argv[optind] == NULL)
821 show_usage();
822 else {
823 add_cmd_str(argv[optind]);
824 optind++;
825 }
826 }
827
828
829 /* argv[(optind)..(argc-1)] should be names of file to process. If no
830 * files were specified or '-' was specified, take input from stdin.
831 * Otherwise, we process all the files specified. */
832 if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
833 process_file(stdin);
834 }
835 else {
836 int i;
837 FILE *file;
838 for (i = optind; i < argc; i++) {
839 file = fopen(argv[i], "r");
840 if (file == NULL) {
841 perror_msg("%s", argv[i]);
842 } else {
843 process_file(file);
844 fclose(file);
845 }
846 }
847 }
848
849 return 0;
850}
diff --git a/setkeycodes.c b/setkeycodes.c
deleted file mode 100644
index c3c7e09aa..000000000
--- a/setkeycodes.c
+++ /dev/null
@@ -1,72 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * setkeycodes
4 *
5 * Copyright (C) 1994-1998 Andries E. Brouwer <aeb@cwi.nl>
6 *
7 * Adjusted for BusyBox by Erik Andersen <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <fcntl.h>
28#include <sys/ioctl.h>
29#include "busybox.h"
30
31
32/* From <linux/kd.h> */
33struct kbkeycode {
34 unsigned int scancode, keycode;
35};
36static const int KDSETKEYCODE = 0x4B4D; /* write kernel keycode table entry */
37
38extern int
39setkeycodes_main(int argc, char** argv)
40{
41 char *ep;
42 int fd, sc;
43 struct kbkeycode a;
44
45 if (argc % 2 != 1 || argc < 2) {
46 show_usage();
47 }
48
49 fd = get_console_fd("/dev/console");
50
51 while (argc > 2) {
52 a.keycode = atoi(argv[2]);
53 a.scancode = sc = strtol(argv[1], &ep, 16);
54 if (*ep) {
55 error_msg_and_die("error reading SCANCODE: '%s'", argv[1]);
56 }
57 if (a.scancode > 127) {
58 a.scancode -= 0xe000;
59 a.scancode += 128;
60 }
61 if (a.scancode > 255 || a.keycode > 127) {
62 error_msg_and_die("SCANCODE or KEYCODE outside bounds");
63 }
64 if (ioctl(fd,KDSETKEYCODE,&a)) {
65 perror("KDSETKEYCODE");
66 error_msg_and_die("failed to set SCANCODE %x to KEYCODE %d", sc, a.keycode);
67 }
68 argc -= 2;
69 argv += 2;
70 }
71 return EXIT_SUCCESS;
72}
diff --git a/shell/Makefile b/shell/Makefile
new file mode 100644
index 000000000..e0229973e
--- /dev/null
+++ b/shell/Makefile
@@ -0,0 +1,40 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := shell.a
22EXTRA_CFLAGS = -DBB_VER='"$(VERSION)"' -DBB_BT='"$(BUILDTIME)"'
23
24obj-y :=
25obj-n :=
26obj- :=
27
28obj-$(CONFIG_ASH) += ash.o
29obj-$(CONFIG_HUSH) += hush.o
30obj-$(CONFIG_LASH) += lash.o
31obj-$(CONFIG_MSH) += msh.o
32obj-$(CONFIG_FEATURE_COMMAND_EDITING) += cmdedit.o
33
34
35# Hand off to toplevel Rules.mak
36include $(TOPDIR)/Rules.mak
37
38clean:
39 rm -f $(L_TARGET) *.o core
40
diff --git a/shell/ash.c b/shell/ash.c
index 486386a25..9cc2208ab 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -265,7 +265,7 @@ union align {
265#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1)) 265#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
266#endif 266#endif
267 267
268#ifdef BB_LOCALE_SUPPORT 268#ifdef CONFIG_LOCALE_SUPPORT
269#include <locale.h> 269#include <locale.h>
270static void change_lc_all(const char *value); 270static void change_lc_all(const char *value);
271static void change_lc_ctype(const char *value); 271static void change_lc_ctype(const char *value);
@@ -1218,7 +1218,7 @@ static struct var vpath;
1218static struct var vps1; 1218static struct var vps1;
1219static struct var vps2; 1219static struct var vps2;
1220static struct var voptind; 1220static struct var voptind;
1221#ifdef BB_LOCALE_SUPPORT 1221#ifdef CONFIG_LOCALE_SUPPORT
1222static struct var vlc_all; 1222static struct var vlc_all;
1223static struct var vlc_ctype; 1223static struct var vlc_ctype;
1224#endif 1224#endif
@@ -1261,7 +1261,7 @@ static const struct varinit varinit[] = {
1261 NULL }, 1261 NULL },
1262 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", 1262 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1263 getoptsreset }, 1263 getoptsreset },
1264#ifdef BB_LOCALE_SUPPORT 1264#ifdef CONFIG_LOCALE_SUPPORT
1265 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=", 1265 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1266 change_lc_all }, 1266 change_lc_all },
1267 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=", 1267 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
@@ -1556,7 +1556,7 @@ static int hashcmd (int, char **);
1556static int helpcmd (int, char **); 1556static int helpcmd (int, char **);
1557static int jobscmd (int, char **); 1557static int jobscmd (int, char **);
1558static int localcmd (int, char **); 1558static int localcmd (int, char **);
1559#ifndef BB_PWD 1559#ifndef CONFIG_PWD
1560static int pwdcmd (int, char **); 1560static int pwdcmd (int, char **);
1561#endif 1561#endif
1562static int readcmd (int, char **); 1562static int readcmd (int, char **);
@@ -1582,7 +1582,7 @@ static int typecmd (int, char **);
1582static int getoptscmd (int, char **); 1582static int getoptscmd (int, char **);
1583#endif 1583#endif
1584 1584
1585#ifndef BB_TRUE_FALSE 1585#ifndef CONFIG_TRUE_FALSE
1586static int true_main (int, char **); 1586static int true_main (int, char **);
1587static int false_main (int, char **); 1587static int false_main (int, char **);
1588#endif 1588#endif
@@ -1653,7 +1653,7 @@ static const struct builtincmd builtincmds[] = {
1653 { BUILTIN_REGULAR "let", letcmd }, 1653 { BUILTIN_REGULAR "let", letcmd },
1654#endif 1654#endif
1655 { BUILTIN_ASSIGN "local", localcmd }, 1655 { BUILTIN_ASSIGN "local", localcmd },
1656#ifndef BB_PWD 1656#ifndef CONFIG_PWD
1657 { BUILTIN_NOSPEC "pwd", pwdcmd }, 1657 { BUILTIN_NOSPEC "pwd", pwdcmd },
1658#endif 1658#endif
1659 { BUILTIN_REGULAR "read", readcmd }, 1659 { BUILTIN_REGULAR "read", readcmd },
@@ -1938,7 +1938,7 @@ updatepwd(const char *dir)
1938} 1938}
1939 1939
1940 1940
1941#ifndef BB_PWD 1941#ifndef CONFIG_PWD
1942static int 1942static int
1943pwdcmd(argc, argv) 1943pwdcmd(argc, argv)
1944 int argc; 1944 int argc;
@@ -3182,7 +3182,7 @@ returncmd(argc, argv)
3182} 3182}
3183 3183
3184 3184
3185#ifndef BB_TRUE_FALSE 3185#ifndef CONFIG_TRUE_FALSE
3186static int 3186static int
3187false_main(argc, argv) 3187false_main(argc, argv)
3188 int argc; 3188 int argc;
@@ -3224,7 +3224,7 @@ setinteractive(int on)
3224 is_interactive = on; 3224 is_interactive = on;
3225 if (do_banner==0 && is_interactive) { 3225 if (do_banner==0 && is_interactive) {
3226 /* Looks like they want an interactive shell */ 3226 /* Looks like they want an interactive shell */
3227#ifndef BB_FEATURE_SH_EXTRA_QUIET 3227#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
3228 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n"); 3228 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3229 printf( "Enter 'help' for a list of built-in commands.\n\n"); 3229 printf( "Enter 'help' for a list of built-in commands.\n\n");
3230#endif 3230#endif
@@ -3535,11 +3535,11 @@ tryexec(char *cmd, char **argv, char **envp)
3535{ 3535{
3536 int e; 3536 int e;
3537 3537
3538#ifdef BB_FEATURE_SH_STANDALONE_SHELL 3538#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3539 char *name = cmd; 3539 char *name = cmd;
3540 char** argv_l=argv; 3540 char** argv_l=argv;
3541 int argc_l; 3541 int argc_l;
3542#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 3542#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
3543 name = get_last_path_component(name); 3543 name = get_last_path_component(name);
3544#endif 3544#endif
3545 argv_l=envp; 3545 argv_l=envp;
@@ -3766,7 +3766,7 @@ static int helpcmd(int argc, char** argv)
3766 col = 0; 3766 col = 0;
3767 } 3767 }
3768 } 3768 }
3769#ifdef BB_FEATURE_SH_STANDALONE_SHELL 3769#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3770 { 3770 {
3771 extern const struct BB_applet applets[]; 3771 extern const struct BB_applet applets[];
3772 extern const size_t NUM_APPLETS; 3772 extern const size_t NUM_APPLETS;
@@ -6023,7 +6023,7 @@ reset(void) {
6023 * This file implements the input routines used by the parser. 6023 * This file implements the input routines used by the parser.
6024 */ 6024 */
6025 6025
6026#ifdef BB_FEATURE_COMMAND_EDITING 6026#ifdef CONFIG_FEATURE_COMMAND_EDITING
6027static const char * cmdedit_prompt; 6027static const char * cmdedit_prompt;
6028static inline void putprompt(const char *s) { 6028static inline void putprompt(const char *s) {
6029 cmdedit_prompt = s; 6029 cmdedit_prompt = s;
@@ -6090,7 +6090,7 @@ preadfd(void)
6090 parsenextc = buf; 6090 parsenextc = buf;
6091 6091
6092retry: 6092retry:
6093#ifdef BB_FEATURE_COMMAND_EDITING 6093#ifdef CONFIG_FEATURE_COMMAND_EDITING
6094 { 6094 {
6095 if (!iflag || parsefile->fd) 6095 if (!iflag || parsefile->fd)
6096 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 6096 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
@@ -7718,7 +7718,7 @@ ash_main(argc, argv)
7718 EXECCMD = find_builtin("exec"); 7718 EXECCMD = find_builtin("exec");
7719 EVALCMD = find_builtin("eval"); 7719 EVALCMD = find_builtin("eval");
7720 7720
7721#ifndef BB_FEATURE_SH_FANCY_PROMPT 7721#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
7722 unsetenv("PS1"); 7722 unsetenv("PS1");
7723 unsetenv("PS2"); 7723 unsetenv("PS2");
7724#endif 7724#endif
@@ -9331,7 +9331,7 @@ getoptsreset(const char *value)
9331 shellparam.optoff = -1; 9331 shellparam.optoff = -1;
9332} 9332}
9333 9333
9334#ifdef BB_LOCALE_SUPPORT 9334#ifdef CONFIG_LOCALE_SUPPORT
9335static void change_lc_all(const char *value) 9335static void change_lc_all(const char *value)
9336{ 9336{
9337 if(value != 0 && *value != 0) 9337 if(value != 0 && *value != 0)
@@ -12730,7 +12730,7 @@ findvar(struct var **vpp, const char *name)
12730/* 12730/*
12731 * Copyright (c) 1999 Herbert Xu <herbert@debian.org> 12731 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12732 * This file contains code for the times builtin. 12732 * This file contains code for the times builtin.
12733 * $Id: ash.c,v 1.28 2001/10/19 00:22:22 andersen Exp $ 12733 * $Id: ash.c,v 1.29 2001/10/24 05:00:16 andersen Exp $
12734 */ 12734 */
12735static int timescmd (int argc, char **argv) 12735static int timescmd (int argc, char **argv)
12736{ 12736{
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
index 16ec2f823..d1b9111ea 100644
--- a/shell/cmdedit.c
+++ b/shell/cmdedit.c
@@ -43,7 +43,7 @@
43 43
44#include "busybox.h" 44#include "busybox.h"
45 45
46#ifdef BB_LOCALE_SUPPORT 46#ifdef CONFIG_LOCALE_SUPPORT
47#define Isprint(c) isprint((c)) 47#define Isprint(c) isprint((c))
48#else 48#else
49#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') ) 49#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') )
@@ -55,32 +55,32 @@
55 55
56#else 56#else
57 57
58#define BB_FEATURE_COMMAND_EDITING 58#define CONFIG_FEATURE_COMMAND_EDITING
59#define BB_FEATURE_COMMAND_TAB_COMPLETION 59#define CONFIG_FEATURE_COMMAND_TAB_COMPLETION
60#define BB_FEATURE_COMMAND_USERNAME_COMPLETION 60#define CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
61#define BB_FEATURE_NONPRINTABLE_INVERSE_PUT 61#define CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
62#define BB_FEATURE_CLEAN_UP 62#define CONFIG_FEATURE_CLEAN_UP
63 63
64#define D(x) x 64#define D(x) x
65 65
66#endif /* TEST */ 66#endif /* TEST */
67 67
68#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION 68#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
69#include <dirent.h> 69#include <dirent.h>
70#include <sys/stat.h> 70#include <sys/stat.h>
71#endif 71#endif
72 72
73#ifdef BB_FEATURE_COMMAND_EDITING 73#ifdef CONFIG_FEATURE_COMMAND_EDITING
74 74
75#ifndef BB_FEATURE_COMMAND_TAB_COMPLETION 75#ifndef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
76#undef BB_FEATURE_COMMAND_USERNAME_COMPLETION 76#undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
77#endif 77#endif
78 78
79#if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(BB_FEATURE_SH_FANCY_PROMPT) 79#if defined(CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
80#define BB_FEATURE_GETUSERNAME_AND_HOMEDIR 80#define CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
81#endif 81#endif
82 82
83#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR 83#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
84# ifndef TEST 84# ifndef TEST
85# include "pwd_grp/pwd.h" 85# include "pwd_grp/pwd.h"
86# else 86# else
@@ -136,33 +136,33 @@ static int cursor; /* required global for signal handler */
136static int len; /* --- "" - - "" - -"- --""-- --""--- */ 136static int len; /* --- "" - - "" - -"- --""-- --""--- */
137static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ 137static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */
138static 138static
139#ifndef BB_FEATURE_SH_FANCY_PROMPT 139#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
140 const 140 const
141#endif 141#endif
142char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ 142char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */
143 143
144#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR 144#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
145static char *user_buf = ""; 145static char *user_buf = "";
146static char *home_pwd_buf = ""; 146static char *home_pwd_buf = "";
147static int my_euid; 147static int my_euid;
148#endif 148#endif
149 149
150#ifdef BB_FEATURE_SH_FANCY_PROMPT 150#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
151static char *hostname_buf = ""; 151static char *hostname_buf = "";
152static int num_ok_lines = 1; 152static int num_ok_lines = 1;
153#endif 153#endif
154 154
155 155
156#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION 156#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
157 157
158#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR 158#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
159static int my_euid; 159static int my_euid;
160#endif 160#endif
161 161
162static int my_uid; 162static int my_uid;
163static int my_gid; 163static int my_gid;
164 164
165#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ 165#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
166 166
167/* It seems that libc5 doesn't know what a sighandler_t is... */ 167/* It seems that libc5 doesn't know what a sighandler_t is... */
168#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) 168#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
@@ -207,7 +207,7 @@ static void cmdedit_reset_term(void)
207 handlers_sets &= ~SET_WCHG_HANDLERS; 207 handlers_sets &= ~SET_WCHG_HANDLERS;
208 } 208 }
209 fflush(stdout); 209 fflush(stdout);
210#ifdef BB_FEATURE_CLEAN_UP 210#ifdef CONFIG_FEATURE_CLEAN_UP
211 if (his_front) { 211 if (his_front) {
212 struct history *n; 212 struct history *n;
213 213
@@ -230,7 +230,7 @@ static void cmdedit_set_out_char(int next_char)
230 230
231 if (c == 0) 231 if (c == 0)
232 c = ' '; /* destroy end char? */ 232 c = ' '; /* destroy end char? */
233#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT 233#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
234 if (!Isprint(c)) { /* Inverse put non-printable characters */ 234 if (!Isprint(c)) { /* Inverse put non-printable characters */
235 if (c >= 128) 235 if (c >= 128)
236 c -= 128; 236 c -= 128;
@@ -321,7 +321,7 @@ static void put_prompt(void)
321 cmdedit_y = 0; /* new quasireal y */ 321 cmdedit_y = 0; /* new quasireal y */
322} 322}
323 323
324#ifndef BB_FEATURE_SH_FANCY_PROMPT 324#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
325static void parse_prompt(const char *prmt_ptr) 325static void parse_prompt(const char *prmt_ptr)
326{ 326{
327 cmdedit_prompt = prmt_ptr; 327 cmdedit_prompt = prmt_ptr;
@@ -359,7 +359,7 @@ static void parse_prompt(const char *prmt_ptr)
359 break; 359 break;
360 c = *prmt_ptr++; 360 c = *prmt_ptr++;
361 switch (c) { 361 switch (c) {
362#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR 362#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
363 case 'u': 363 case 'u':
364 pbuf = user_buf; 364 pbuf = user_buf;
365 break; 365 break;
@@ -382,7 +382,7 @@ static void parse_prompt(const char *prmt_ptr)
382 case '$': 382 case '$':
383 c = my_euid == 0 ? '#' : '$'; 383 c = my_euid == 0 ? '#' : '$';
384 break; 384 break;
385#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR 385#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
386 case 'w': 386 case 'w':
387 pbuf = pwd_buf; 387 pbuf = pwd_buf;
388 l = strlen(home_pwd_buf); 388 l = strlen(home_pwd_buf);
@@ -526,7 +526,7 @@ static void cmdedit_init(void)
526 } 526 }
527 527
528 if ((handlers_sets & SET_ATEXIT) == 0) { 528 if ((handlers_sets & SET_ATEXIT) == 0) {
529#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR 529#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
530 struct passwd *entry; 530 struct passwd *entry;
531 531
532 my_euid = geteuid(); 532 my_euid = geteuid();
@@ -537,20 +537,20 @@ static void cmdedit_init(void)
537 } 537 }
538#endif 538#endif
539 539
540#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION 540#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
541 541
542#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR 542#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
543 my_euid = geteuid(); 543 my_euid = geteuid();
544#endif 544#endif
545 my_uid = getuid(); 545 my_uid = getuid();
546 my_gid = getgid(); 546 my_gid = getgid();
547#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ 547#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
548 handlers_sets |= SET_ATEXIT; 548 handlers_sets |= SET_ATEXIT;
549 atexit(cmdedit_reset_term); /* be sure to do this only once */ 549 atexit(cmdedit_reset_term); /* be sure to do this only once */
550 } 550 }
551} 551}
552 552
553#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION 553#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
554 554
555static int is_execute(const struct stat *st) 555static int is_execute(const struct stat *st)
556{ 556{
@@ -561,7 +561,7 @@ static int is_execute(const struct stat *st)
561 return FALSE; 561 return FALSE;
562} 562}
563 563
564#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION 564#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
565 565
566static char **username_tab_completion(char *ud, int *num_matches) 566static char **username_tab_completion(char *ud, int *num_matches)
567{ 567{
@@ -623,7 +623,7 @@ static char **username_tab_completion(char *ud, int *num_matches)
623 return (matches); 623 return (matches);
624 } 624 }
625} 625}
626#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */ 626#endif /* CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION */
627 627
628enum { 628enum {
629 FIND_EXE_ONLY = 0, 629 FIND_EXE_ONLY = 0,
@@ -720,7 +720,7 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches,
720 strcpy(dirbuf, command); 720 strcpy(dirbuf, command);
721 /* set dir only */ 721 /* set dir only */
722 dirbuf[(pfind - command) + 1] = 0; 722 dirbuf[(pfind - command) + 1] = 0;
723#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION 723#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
724 if (dirbuf[0] == '~') /* ~/... or ~user/... */ 724 if (dirbuf[0] == '~') /* ~/... or ~user/... */
725 username_tab_completion(dirbuf, 0); 725 username_tab_completion(dirbuf, 0);
726#endif 726#endif
@@ -826,12 +826,12 @@ static int find_match(char *matchBuf, int *len_with_quotes)
826 collapse_pos(j, j + 1); 826 collapse_pos(j, j + 1);
827 int_buf[j] |= QUOT; 827 int_buf[j] |= QUOT;
828 i++; 828 i++;
829#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT 829#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
830 if (matchBuf[i] == '\t') /* algorithm equivalent */ 830 if (matchBuf[i] == '\t') /* algorithm equivalent */
831 int_buf[j] = ' ' | QUOT; 831 int_buf[j] = ' ' | QUOT;
832#endif 832#endif
833 } 833 }
834#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT 834#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
835 else if (matchBuf[i] == '\t') 835 else if (matchBuf[i] == '\t')
836 int_buf[j] = ' '; 836 int_buf[j] = ' ';
837#endif 837#endif
@@ -1000,7 +1000,7 @@ static void input_tab(int *lastWasTab)
1000 /* Free up any memory already allocated */ 1000 /* Free up any memory already allocated */
1001 input_tab(0); 1001 input_tab(0);
1002 1002
1003#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION 1003#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
1004 /* If the word starts with `~' and there is no slash in the word, 1004 /* If the word starts with `~' and there is no slash in the word,
1005 * then try completing this word as a username. */ 1005 * then try completing this word as a username. */
1006 1006
@@ -1119,7 +1119,7 @@ static void input_tab(int *lastWasTab)
1119 } 1119 }
1120 } 1120 }
1121} 1121}
1122#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ 1122#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
1123 1123
1124static void get_previous_history(struct history **hp, struct history *p) 1124static void get_previous_history(struct history **hp, struct history *p)
1125{ 1125{
@@ -1232,7 +1232,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1232 * if the len=0 and no chars to delete */ 1232 * if the len=0 and no chars to delete */
1233 if (len == 0) { 1233 if (len == 0) {
1234prepare_to_die: 1234prepare_to_die:
1235#if !defined(BB_ASH) 1235#if !defined(CONFIG_ASH)
1236 printf("exit"); 1236 printf("exit");
1237 goto_new_line(); 1237 goto_new_line();
1238 /* cmdedit_reset_term() called in atexit */ 1238 /* cmdedit_reset_term() called in atexit */
@@ -1259,7 +1259,7 @@ prepare_to_die:
1259 input_backspace(); 1259 input_backspace();
1260 break; 1260 break;
1261 case '\t': 1261 case '\t':
1262#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION 1262#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
1263 input_tab(&lastWasTab); 1263 input_tab(&lastWasTab);
1264#endif 1264#endif
1265 break; 1265 break;
@@ -1299,7 +1299,7 @@ prepare_to_die:
1299 goto prepare_to_die; 1299 goto prepare_to_die;
1300 } 1300 }
1301 switch (c) { 1301 switch (c) {
1302#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION 1302#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
1303 case '\t': /* Alt-Tab */ 1303 case '\t': /* Alt-Tab */
1304 1304
1305 input_tab(&lastWasTab); 1305 input_tab(&lastWasTab);
@@ -1367,7 +1367,7 @@ prepare_to_die:
1367 } 1367 }
1368 1368
1369 default: /* If it's regular input, do the normal thing */ 1369 default: /* If it's regular input, do the normal thing */
1370#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT 1370#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
1371 /* Control-V -- Add non-printable symbol */ 1371 /* Control-V -- Add non-printable symbol */
1372 if (c == 22) { 1372 if (c == 22) {
1373 if (safe_read(0, &c, 1) < 1) 1373 if (safe_read(0, &c, 1) < 1)
@@ -1457,7 +1457,7 @@ prepare_to_die:
1457 history_counter++; 1457 history_counter++;
1458 } 1458 }
1459 } 1459 }
1460#if defined(BB_FEATURE_SH_FANCY_PROMPT) 1460#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1461 num_ok_lines++; 1461 num_ok_lines++;
1462#endif 1462#endif
1463 } 1463 }
@@ -1465,10 +1465,10 @@ prepare_to_die:
1465 command[len++] = '\n'; /* set '\n' */ 1465 command[len++] = '\n'; /* set '\n' */
1466 command[len] = 0; 1466 command[len] = 0;
1467 } 1467 }
1468#if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION) 1468#if defined(CONFIG_FEATURE_CLEAN_UP) && defined(CONFIG_FEATURE_COMMAND_TAB_COMPLETION)
1469 input_tab(0); /* strong free */ 1469 input_tab(0); /* strong free */
1470#endif 1470#endif
1471#if defined(BB_FEATURE_SH_FANCY_PROMPT) 1471#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1472 free(cmdedit_prompt); 1472 free(cmdedit_prompt);
1473#endif 1473#endif
1474 cmdedit_reset_term(); 1474 cmdedit_reset_term();
@@ -1477,7 +1477,7 @@ prepare_to_die:
1477 1477
1478 1478
1479 1479
1480#endif /* BB_FEATURE_COMMAND_EDITING */ 1480#endif /* CONFIG_FEATURE_COMMAND_EDITING */
1481 1481
1482 1482
1483#ifdef TEST 1483#ifdef TEST
@@ -1485,7 +1485,7 @@ prepare_to_die:
1485const char *applet_name = "debug stuff usage"; 1485const char *applet_name = "debug stuff usage";
1486const char *memory_exhausted = "Memory exhausted"; 1486const char *memory_exhausted = "Memory exhausted";
1487 1487
1488#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT 1488#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
1489#include <locale.h> 1489#include <locale.h>
1490#endif 1490#endif
1491 1491
@@ -1493,7 +1493,7 @@ int main(int argc, char **argv)
1493{ 1493{
1494 char buff[BUFSIZ]; 1494 char buff[BUFSIZ];
1495 char *prompt = 1495 char *prompt =
1496#if defined(BB_FEATURE_SH_FANCY_PROMPT) 1496#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1497 "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\ 1497 "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\
1498\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \ 1498\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \
1499\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]"; 1499\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
@@ -1501,7 +1501,7 @@ int main(int argc, char **argv)
1501 "% "; 1501 "% ";
1502#endif 1502#endif
1503 1503
1504#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT 1504#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
1505 setlocale(LC_ALL, ""); 1505 setlocale(LC_ALL, "");
1506#endif 1506#endif
1507 while(1) { 1507 while(1) {
diff --git a/shell/config.in b/shell/config.in
new file mode 100644
index 000000000..e33669a7b
--- /dev/null
+++ b/shell/config.in
@@ -0,0 +1,51 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Bourne Shell'
8
9choice 'Choose your default shell' \
10 "ash CONFIG_FEATURE_SH_IS_ASH \
11 hush CONFIG_FEATURE_SH_IS_HUSH \
12 lash CONFIG_FEATURE_SH_IS_LASH \
13 msh CONFIG_FEATURE_SH_IS_MSH \
14 none CONFIG_FEATURE_SH_IS_NONE"
15
16if [ "$CONFIG_FEATURE_SH_IS_ASH" = "y" ] ; then
17 define_bool CONFIG_ASH y
18else
19 bool 'ash' CONFIG_ASH
20fi
21
22if [ "$CONFIG_FEATURE_SH_IS_HUSH" = "y" ] ; then
23 define_bool CONFIG_HUSH y
24else
25 bool 'hush' CONFIG_HUSH
26fi
27
28if [ "$CONFIG_FEATURE_SH_IS_LASH" = "y" ] ; then
29 define_bool CONFIG_LASH y
30else
31 bool 'lash' CONFIG_LASH
32fi
33
34if [ "$CONFIG_FEATURE_SH_IS_MSH" = "y" ] ; then
35 define_bool CONFIG_MSH y
36else
37 bool 'msh' CONFIG_MSH
38fi
39
40
41comment 'Bourne Shell Options'
42bool 'command line editing' CONFIG_FEATURE_COMMAND_EDITING
43bool 'tab completion' CONFIG_FEATURE_COMMAND_TAB_COMPLETION
44bool 'username completion' CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
45bool 'Standalone shell' CONFIG_FEATURE_SH_STANDALONE_SHELL
46bool 'Standalone shell -- applets always win' CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
47bool 'Fancy shell prompts' CONFIG_FEATURE_SH_FANCY_PROMPT
48bool 'Hide message on interactive shell startup' CONFIG_FEATURE_SH_EXTRA_QUIET
49
50endmenu
51
diff --git a/shell/hush.c b/shell/hush.c
index cb0e6e980..d37842b79 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -113,7 +113,8 @@
113#define applet_name "hush" 113#define applet_name "hush"
114#include "standalone.h" 114#include "standalone.h"
115#define hush_main main 115#define hush_main main
116#undef BB_FEATURE_SH_FANCY_PROMPT 116#undef CONFIG_FEATURE_SH_FANCY_PROMPT
117#define BB_BANNER
117#endif 118#endif
118 119
119typedef enum { 120typedef enum {
@@ -836,7 +837,7 @@ static int static_peek(struct in_str *i)
836 837
837static inline void cmdedit_set_initial_prompt(void) 838static inline void cmdedit_set_initial_prompt(void)
838{ 839{
839#ifndef BB_FEATURE_SH_FANCY_PROMPT 840#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
840 PS1 = NULL; 841 PS1 = NULL;
841#else 842#else
842 PS1 = getenv("PS1"); 843 PS1 = getenv("PS1");
@@ -848,7 +849,7 @@ static inline void cmdedit_set_initial_prompt(void)
848static inline void setup_prompt_string(int promptmode, char **prompt_str) 849static inline void setup_prompt_string(int promptmode, char **prompt_str)
849{ 850{
850 debug_printf("setup_prompt_string %d ",promptmode); 851 debug_printf("setup_prompt_string %d ",promptmode);
851#ifndef BB_FEATURE_SH_FANCY_PROMPT 852#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
852 /* Set up the prompt */ 853 /* Set up the prompt */
853 if (promptmode == 1) { 854 if (promptmode == 1) {
854 if (PS1) 855 if (PS1)
@@ -871,7 +872,7 @@ static void get_user_input(struct in_str *i)
871 static char the_command[BUFSIZ]; 872 static char the_command[BUFSIZ];
872 873
873 setup_prompt_string(i->promptmode, &prompt_str); 874 setup_prompt_string(i->promptmode, &prompt_str);
874#ifdef BB_FEATURE_COMMAND_EDITING 875#ifdef CONFIG_FEATURE_COMMAND_EDITING
875 /* 876 /*
876 ** enable command line editing only while a command line 877 ** enable command line editing only while a command line
877 ** is actually being read; otherwise, we'll end up bequeathing 878 ** is actually being read; otherwise, we'll end up bequeathing
@@ -1085,18 +1086,18 @@ static void pseudo_exec(struct child_prog *child)
1085 * really dislike relying on /proc for things. We could exec ourself 1086 * really dislike relying on /proc for things. We could exec ourself
1086 * from global_argv[0], but if we are in a chroot, we may not be able 1087 * from global_argv[0], but if we are in a chroot, we may not be able
1087 * to find ourself... */ 1088 * to find ourself... */
1088#ifdef BB_FEATURE_SH_STANDALONE_SHELL 1089#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
1089 { 1090 {
1090 int argc_l; 1091 int argc_l;
1091 char** argv_l=child->argv; 1092 char** argv_l=child->argv;
1092 char *name = child->argv[0]; 1093 char *name = child->argv[0];
1093 1094
1094#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 1095#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
1095 /* Following discussions from November 2000 on the busybox mailing 1096 /* Following discussions from November 2000 on the busybox mailing
1096 * list, the default configuration, (without 1097 * list, the default configuration, (without
1097 * get_last_path_component()) lets the user force use of an 1098 * get_last_path_component()) lets the user force use of an
1098 * external command by specifying the full (with slashes) filename. 1099 * external command by specifying the full (with slashes) filename.
1099 * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets 1100 * If you enable CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets
1100 * _aways_ override external commands, so if you want to run 1101 * _aways_ override external commands, so if you want to run
1101 * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the 1102 * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the
1102 * filesystem and is _not_ busybox. Some systems may want this, 1103 * filesystem and is _not_ busybox. Some systems may want this,
@@ -2586,7 +2587,7 @@ int hush_main(int argc, char **argv)
2586 2587
2587 /* Initialize some more globals to non-zero values */ 2588 /* Initialize some more globals to non-zero values */
2588 set_cwd(); 2589 set_cwd();
2589#ifdef BB_FEATURE_COMMAND_EDITING 2590#ifdef CONFIG_FEATURE_COMMAND_EDITING
2590 cmdedit_set_initial_prompt(); 2591 cmdedit_set_initial_prompt();
2591#else 2592#else
2592 PS1 = NULL; 2593 PS1 = NULL;
@@ -2655,7 +2656,7 @@ int hush_main(int argc, char **argv)
2655 debug_printf("\ninteractive=%d\n", interactive); 2656 debug_printf("\ninteractive=%d\n", interactive);
2656 if (interactive) { 2657 if (interactive) {
2657 /* Looks like they want an interactive shell */ 2658 /* Looks like they want an interactive shell */
2658#ifndef BB_FEATURE_SH_EXTRA_QUIET 2659#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
2659 printf( "\n\n" BB_BANNER " hush - the humble shell v0.01 (testing)\n"); 2660 printf( "\n\n" BB_BANNER " hush - the humble shell v0.01 (testing)\n");
2660 printf( "Enter 'help' for a list of built-in commands.\n\n"); 2661 printf( "Enter 'help' for a list of built-in commands.\n\n");
2661#endif 2662#endif
@@ -2673,7 +2674,7 @@ int hush_main(int argc, char **argv)
2673 input = xfopen(argv[optind], "r"); 2674 input = xfopen(argv[optind], "r");
2674 opt = parse_file_outer(input); 2675 opt = parse_file_outer(input);
2675 2676
2676#ifdef BB_FEATURE_CLEAN_UP 2677#ifdef CONFIG_FEATURE_CLEAN_UP
2677 fclose(input); 2678 fclose(input);
2678 if (cwd && cwd != unknown) 2679 if (cwd && cwd != unknown)
2679 free((char*)cwd); 2680 free((char*)cwd);
diff --git a/shell/lash.c b/shell/lash.c
index ffdec8781..004d9495a 100644
--- a/shell/lash.c
+++ b/shell/lash.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * lash -- the BusyBox Lame-Ass SHell 3 * lash -- the BusyBox Lame-Ass SHell
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is 8 * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is
9 * under the following liberal license: "We have placed this source code in the 9 * under the following liberal license: "We have placed this source code in the
@@ -25,8 +25,10 @@
25 * 25 *
26 */ 26 */
27 27
28/* This shell's parsing engine is officially at a dead-end. 28/* This shell's parsing engine is officially at a dead-end. Future
29 * Future work shell work should be done using hush.c 29 * work shell work should be done using hush, msh, or ash. This is
30 * still a very useful, small shell -- it just don't need any more
31 * features beyond what it already has...
30 */ 32 */
31 33
32//For debugging/development on the shell only... 34//For debugging/development on the shell only...
@@ -48,7 +50,7 @@
48#include "busybox.h" 50#include "busybox.h"
49#include "cmdedit.h" 51#include "cmdedit.h"
50 52
51#ifdef BB_LOCALE_SUPPORT 53#ifdef CONFIG_LOCALE_SUPPORT
52#include <locale.h> 54#include <locale.h>
53#endif 55#endif
54 56
@@ -390,12 +392,12 @@ static int builtin_export(struct child_prog *child)
390 res = putenv(v); 392 res = putenv(v);
391 if (res) 393 if (res)
392 fprintf(stderr, "export: %m\n"); 394 fprintf(stderr, "export: %m\n");
393#ifdef BB_FEATURE_SH_FANCY_PROMPT 395#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
394 if (strncmp(v, "PS1=", 4)==0) 396 if (strncmp(v, "PS1=", 4)==0)
395 PS1 = getenv("PS1"); 397 PS1 = getenv("PS1");
396#endif 398#endif
397 399
398#ifdef BB_LOCALE_SUPPORT 400#ifdef CONFIG_LOCALE_SUPPORT
399 if(strncmp(v, "LC_ALL=", 7)==0) 401 if(strncmp(v, "LC_ALL=", 7)==0)
400 setlocale(LC_ALL, getenv("LC_ALL")); 402 setlocale(LC_ALL, getenv("LC_ALL"));
401 if(strncmp(v, "LC_CTYPE=", 9)==0) 403 if(strncmp(v, "LC_CTYPE=", 9)==0)
@@ -661,7 +663,7 @@ static void restore_redirects(int squirrel[])
661 663
662static inline void cmdedit_set_initial_prompt(void) 664static inline void cmdedit_set_initial_prompt(void)
663{ 665{
664#ifndef BB_FEATURE_SH_FANCY_PROMPT 666#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
665 PS1 = NULL; 667 PS1 = NULL;
666#else 668#else
667 PS1 = getenv("PS1"); 669 PS1 = getenv("PS1");
@@ -672,7 +674,7 @@ static inline void cmdedit_set_initial_prompt(void)
672 674
673static inline void setup_prompt_string(char **prompt_str) 675static inline void setup_prompt_string(char **prompt_str)
674{ 676{
675#ifndef BB_FEATURE_SH_FANCY_PROMPT 677#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
676 /* Set up the prompt */ 678 /* Set up the prompt */
677 if (shell_context == 0) { 679 if (shell_context == 0) {
678 if (PS1) 680 if (PS1)
@@ -706,7 +708,7 @@ static int get_command(FILE * source, char *command)
706 if (source == stdin) { 708 if (source == stdin) {
707 setup_prompt_string(&prompt_str); 709 setup_prompt_string(&prompt_str);
708 710
709#ifdef BB_FEATURE_COMMAND_EDITING 711#ifdef CONFIG_FEATURE_COMMAND_EDITING
710 /* 712 /*
711 ** enable command line editing only while a command line 713 ** enable command line editing only while a command line
712 ** is actually being read; otherwise, we'll end up bequeathing 714 ** is actually being read; otherwise, we'll end up bequeathing
@@ -1201,7 +1203,7 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1201static int pseudo_exec(struct child_prog *child) 1203static int pseudo_exec(struct child_prog *child)
1202{ 1204{
1203 struct built_in_command *x; 1205 struct built_in_command *x;
1204#ifdef BB_FEATURE_SH_STANDALONE_SHELL 1206#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
1205 char *name; 1207 char *name;
1206#endif 1208#endif
1207 1209
@@ -1223,7 +1225,7 @@ static int pseudo_exec(struct child_prog *child)
1223 exit (x->function(child)); 1225 exit (x->function(child));
1224 } 1226 }
1225 } 1227 }
1226#ifdef BB_FEATURE_SH_STANDALONE_SHELL 1228#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
1227 /* Check if the command matches any busybox internal 1229 /* Check if the command matches any busybox internal
1228 * commands ("applets") here. Following discussions from 1230 * commands ("applets") here. Following discussions from
1229 * November 2000 on busybox@opensource.lineo.com, don't use 1231 * November 2000 on busybox@opensource.lineo.com, don't use
@@ -1237,8 +1239,8 @@ static int pseudo_exec(struct child_prog *child)
1237 */ 1239 */
1238 name = child->argv[0]; 1240 name = child->argv[0];
1239 1241
1240#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 1242#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
1241 /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then 1243 /* If you enable CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN, then
1242 * if you run /bin/cat, it will use BusyBox cat even if 1244 * if you run /bin/cat, it will use BusyBox cat even if
1243 * /bin/cat exists on the filesystem and is _not_ busybox. 1245 * /bin/cat exists on the filesystem and is _not_ busybox.
1244 * Some systems want this, others do not. Choose wisely. :-) 1246 * Some systems want this, others do not. Choose wisely. :-)
@@ -1504,7 +1506,7 @@ static int busy_loop(FILE * input)
1504} 1506}
1505 1507
1506 1508
1507#ifdef BB_FEATURE_CLEAN_UP 1509#ifdef CONFIG_FEATURE_CLEAN_UP
1508void free_memory(void) 1510void free_memory(void)
1509{ 1511{
1510 if (cwd && cwd!=unknown) { 1512 if (cwd && cwd!=unknown) {
@@ -1611,7 +1613,7 @@ int lash_main(int argc_l, char **argv_l)
1611 if (interactive==TRUE) { 1613 if (interactive==TRUE) {
1612 //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); 1614 //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
1613 /* Looks like they want an interactive shell */ 1615 /* Looks like they want an interactive shell */
1614#ifndef BB_FEATURE_SH_EXTRA_QUIET 1616#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1615 printf( "\n\n" BB_BANNER " Built-in shell (lash)\n"); 1617 printf( "\n\n" BB_BANNER " Built-in shell (lash)\n");
1616 printf( "Enter 'help' for a list of built-in commands.\n\n"); 1618 printf( "Enter 'help' for a list of built-in commands.\n\n");
1617#endif 1619#endif
@@ -1626,11 +1628,11 @@ int lash_main(int argc_l, char **argv_l)
1626 if (!cwd) 1628 if (!cwd)
1627 cwd = unknown; 1629 cwd = unknown;
1628 1630
1629#ifdef BB_FEATURE_CLEAN_UP 1631#ifdef CONFIG_FEATURE_CLEAN_UP
1630 atexit(free_memory); 1632 atexit(free_memory);
1631#endif 1633#endif
1632 1634
1633#ifdef BB_FEATURE_COMMAND_EDITING 1635#ifdef CONFIG_FEATURE_COMMAND_EDITING
1634 cmdedit_set_initial_prompt(); 1636 cmdedit_set_initial_prompt();
1635#else 1637#else
1636 PS1 = NULL; 1638 PS1 = NULL;
diff --git a/shell/msh.c b/shell/msh.c
index 5c4ec1019..a2f98c837 100644
--- a/shell/msh.c
+++ b/shell/msh.c
@@ -681,7 +681,7 @@ static void * brktop;
681static void * brkaddr; 681static void * brkaddr;
682 682
683 683
684#ifdef BB_FEATURE_COMMAND_EDITING 684#ifdef CONFIG_FEATURE_COMMAND_EDITING
685static char * current_prompt; 685static char * current_prompt;
686#endif 686#endif
687 687
@@ -732,7 +732,7 @@ extern int msh_main(int argc, char **argv)
732 setval(ifs, " \t\n"); 732 setval(ifs, " \t\n");
733 733
734 prompt = lookup("PS1"); 734 prompt = lookup("PS1");
735#ifdef BB_FEATURE_SH_FANCY_PROMPT 735#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
736 if (prompt->value == null) 736 if (prompt->value == null)
737#endif 737#endif
738 setval(prompt, "$ "); 738 setval(prompt, "$ ");
@@ -741,7 +741,7 @@ extern int msh_main(int argc, char **argv)
741 prompt->status &= ~EXPORT; 741 prompt->status &= ~EXPORT;
742 } 742 }
743 cprompt = lookup("PS2"); 743 cprompt = lookup("PS2");
744#ifdef BB_FEATURE_SH_FANCY_PROMPT 744#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
745 if (cprompt->value == null) 745 if (cprompt->value == null)
746#endif 746#endif
747 setval(cprompt, "> "); 747 setval(cprompt, "> ");
@@ -801,7 +801,7 @@ extern int msh_main(int argc, char **argv)
801 PUSHIO(afile, 0, iof); 801 PUSHIO(afile, 0, iof);
802 if (isatty(0) && isatty(1) && !cflag) { 802 if (isatty(0) && isatty(1) && !cflag) {
803 interactive++; 803 interactive++;
804#ifndef BB_FEATURE_SH_EXTRA_QUIET 804#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
805 printf( "\n\n" BB_BANNER " Built-in shell (msh)\n"); 805 printf( "\n\n" BB_BANNER " Built-in shell (msh)\n");
806 printf( "Enter 'help' for a list of built-in commands.\n\n"); 806 printf( "Enter 'help' for a list of built-in commands.\n\n");
807#endif 807#endif
@@ -835,7 +835,7 @@ extern int msh_main(int argc, char **argv)
835 835
836 for (;;) { 836 for (;;) {
837 if (interactive && e.iop <= iostack) { 837 if (interactive && e.iop <= iostack) {
838#ifdef BB_FEATURE_COMMAND_EDITING 838#ifdef CONFIG_FEATURE_COMMAND_EDITING
839 current_prompt=prompt->value; 839 current_prompt=prompt->value;
840#else 840#else
841 prs(prompt->value); 841 prs(prompt->value);
@@ -2171,7 +2171,7 @@ loop:
2171 startl = 1; 2171 startl = 1;
2172 if (multiline || cf & CONTIN) { 2172 if (multiline || cf & CONTIN) {
2173 if (interactive && e.iop <= iostack) { 2173 if (interactive && e.iop <= iostack) {
2174#ifdef BB_FEATURE_COMMAND_EDITING 2174#ifdef CONFIG_FEATURE_COMMAND_EDITING
2175 current_prompt=cprompt->value; 2175 current_prompt=cprompt->value;
2176#else 2176#else
2177 prs(cprompt->value); 2177 prs(cprompt->value);
@@ -2224,7 +2224,7 @@ register int c, c1;
2224 return(YYERRCODE); 2224 return(YYERRCODE);
2225 } 2225 }
2226 if (interactive && c == '\n' && e.iop <= iostack) { 2226 if (interactive && c == '\n' && e.iop <= iostack) {
2227#ifdef BB_FEATURE_COMMAND_EDITING 2227#ifdef CONFIG_FEATURE_COMMAND_EDITING
2228 current_prompt=cprompt->value; 2228 current_prompt=cprompt->value;
2229#else 2229#else
2230 prs(cprompt->value); 2230 prs(cprompt->value);
@@ -2838,9 +2838,9 @@ char *c, **v, **envp;
2838 register char *sp, *tp; 2838 register char *sp, *tp;
2839 int eacces = 0, asis = 0; 2839 int eacces = 0, asis = 0;
2840 2840
2841#ifdef BB_FEATURE_SH_STANDALONE_SHELL 2841#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
2842 char *name = c; 2842 char *name = c;
2843#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 2843#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
2844 name = get_last_path_component(name); 2844 name = get_last_path_component(name);
2845#endif 2845#endif
2846 optind = 1; 2846 optind = 1;
@@ -2960,7 +2960,7 @@ static int dohelp()
2960 col = 0; 2960 col = 0;
2961 } 2961 }
2962 } 2962 }
2963#ifdef BB_FEATURE_SH_STANDALONE_SHELL 2963#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
2964 { 2964 {
2965 int i; 2965 int i;
2966 const struct BB_applet *applet; 2966 const struct BB_applet *applet;
@@ -4256,7 +4256,7 @@ readc()
4256 if (multiline) 4256 if (multiline)
4257 return e.iop->prev = 0; 4257 return e.iop->prev = 0;
4258 if (interactive && e.iop == iostack+1) { 4258 if (interactive && e.iop == iostack+1) {
4259#ifdef BB_FEATURE_COMMAND_EDITING 4259#ifdef CONFIG_FEATURE_COMMAND_EDITING
4260 current_prompt=prompt->value; 4260 current_prompt=prompt->value;
4261#else 4261#else
4262 prs(prompt->value); 4262 prs(prompt->value);
@@ -4462,7 +4462,7 @@ register struct ioarg *ap;
4462 return *bp->bufp++ & 0177; 4462 return *bp->bufp++ & 0177;
4463 } 4463 }
4464 4464
4465#ifdef BB_FEATURE_COMMAND_EDITING 4465#ifdef CONFIG_FEATURE_COMMAND_EDITING
4466 if (interactive) { 4466 if (interactive) {
4467 static char mycommand[BUFSIZ]; 4467 static char mycommand[BUFSIZ];
4468 static int position = 0, size = 0; 4468 static int position = 0, size = 0;
@@ -4721,7 +4721,7 @@ int ec;
4721 e.iobase = e.iop; 4721 e.iobase = e.iop;
4722 for (;;) { 4722 for (;;) {
4723 if (interactive && e.iop <= iostack) { 4723 if (interactive && e.iop <= iostack) {
4724#ifdef BB_FEATURE_COMMAND_EDITING 4724#ifdef CONFIG_FEATURE_COMMAND_EDITING
4725 current_prompt=cprompt->value; 4725 current_prompt=cprompt->value;
4726#else 4726#else
4727 prs(cprompt->value); 4727 prs(cprompt->value);
diff --git a/sleep.c b/sleep.c
deleted file mode 100644
index 3bcab88ee..000000000
--- a/sleep.c
+++ /dev/null
@@ -1,38 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini sleep implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <stdio.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include "busybox.h"
28
29extern int sleep_main(int argc, char **argv)
30{
31 if ((argc < 2) || (**(argv + 1) == '-')) {
32 show_usage();
33 }
34
35 if (sleep(atoi(*(++argv))) != 0)
36 perror_msg_and_die("sleep");
37 return EXIT_SUCCESS;
38}
diff --git a/sort.c b/sort.c
deleted file mode 100644
index 4f4979cc5..000000000
--- a/sort.c
+++ /dev/null
@@ -1,106 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini sort implementation for busybox
4 *
5 *
6 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <getopt.h>
25#include <string.h>
26#include <stdlib.h>
27#include "busybox.h"
28
29static int compare_ascii(const void *x, const void *y)
30{
31 return strcmp(*(char **)x, *(char **)y);
32}
33
34static int compare_numeric(const void *x, const void *y)
35{
36 int z = atoi(*(char **)x) - atoi(*(char **)y);
37 return z ? z : strcmp(*(char **)x, *(char **)y);
38}
39
40int sort_main(int argc, char **argv)
41{
42 FILE *fp;
43 char *line, **lines = NULL;
44 int i, opt, nlines = 0;
45 int (*compare)(const void *, const void *) = compare_ascii;
46#ifdef BB_FEATURE_SORT_REVERSE
47 int reverse = FALSE;
48#endif
49#ifdef BB_FEATURE_SORT_UNIQUE
50 int unique = FALSE;
51#endif
52
53 while ((opt = getopt(argc, argv, "nru")) != -1) {
54 switch (opt) {
55 case 'n':
56 compare = compare_numeric;
57 break;
58#ifdef BB_FEATURE_SORT_REVERSE
59 case 'r':
60 reverse = TRUE;
61 break;
62#endif
63#ifdef BB_FEATURE_SORT_UNIQUE
64 case 'u':
65 unique = TRUE;
66 break;
67#endif
68 default:
69 show_usage();
70 }
71 }
72
73 /* read the input */
74 for (i = optind; i == optind || i < argc; i++) {
75 if (argv[i] == NULL)
76 fp = stdin;
77 else
78 fp = xfopen(argv[i], "r");
79
80 while ((line = get_line_from_file(fp)) != NULL) {
81 lines = xrealloc(lines, sizeof(char *) * (nlines + 1));
82 chomp(line);
83 lines[nlines++] = line;
84 }
85 }
86
87 /* sort it */
88 qsort(lines, nlines, sizeof(char *), compare);
89
90 /* print it */
91#ifdef BB_FEATURE_SORT_REVERSE
92 if (reverse) {
93 for (i = --nlines; 0 <= i; i--)
94#ifdef BB_FEATURE_SORT_UNIQUE
95 if((!unique) || (i == nlines) || (strcmp(lines[i + 1], lines[i])))
96#endif
97 puts(lines[i]);
98 } else
99#endif
100 for (i = 0; i < nlines; i++)
101#ifdef BB_FEATURE_SORT_UNIQUE
102 if((!unique) || (!i) || (strcmp(lines[i - 1], lines[i])))
103#endif
104 puts(lines[i]);
105 return EXIT_SUCCESS;
106}
diff --git a/start_stop_daemon.c b/start_stop_daemon.c
deleted file mode 100644
index 0152283ad..000000000
--- a/start_stop_daemon.c
+++ /dev/null
@@ -1,271 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini start-stop-daemon implementation(s) for busybox
4 *
5 * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
6 * public domain.
7 * Adapted for busybox David Kimdon <dwhedon@gordian.com>
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <stdarg.h>
14#include <signal.h>
15#include <errno.h>
16#include <sys/stat.h>
17#include <dirent.h>
18#include <unistd.h>
19#include <pwd.h>
20
21#include "busybox.h"
22
23static int start = 0;
24static int stop = 0;
25static int signal_nr = 15;
26static int user_id = -1;
27static const char *userspec = NULL;
28static const char *cmdname = NULL;
29static char *execname = NULL;
30static char *startas = NULL;
31static const char *progname = "";
32
33struct pid_list {
34 struct pid_list *next;
35 int pid;
36};
37
38static struct pid_list *found = NULL;
39static struct pid_list *killed = NULL;
40
41static void
42push(struct pid_list **list, int pid)
43{
44 struct pid_list *p;
45
46 p = xmalloc(sizeof(*p));
47 p->next = *list;
48 p->pid = pid;
49 *list = p;
50}
51
52
53static void
54parse_options(int argc, char * const *argv)
55{
56
57 int c;
58
59 for (;;) {
60 c = getopt (argc, argv, "a:n:s:u:x:KS");
61 if (c == EOF)
62 break;
63 switch (c) {
64 case 'K':
65 stop = 1;
66 break;
67 case 'S':
68 start = 1;
69 break;
70 case 'a':
71 startas = optarg;
72 break;
73 case 'n':
74 cmdname = optarg;
75 break;
76 case 's':
77 if (sscanf(optarg, "%d", &signal_nr) != 1)
78 error_msg_and_die ("-s takes a numeric argument");
79 break;
80 case 'u':
81 userspec = optarg;
82 break;
83 case 'x':
84 execname = optarg;
85 break;
86 default:
87 show_usage();
88 exit(1);
89 }
90 }
91
92 if (start == stop)
93 error_msg_and_die ("need one of -S or -K");
94
95 if (!execname && !userspec)
96 error_msg_and_die ("need at least one of -x or -u");
97
98 if (!startas)
99 startas = execname;
100
101 if (start && !startas)
102 error_msg_and_die ("-S needs -x or -a");
103}
104
105
106static int
107pid_is_exec(int pid, const char *exec)
108{
109 char buf[PATH_MAX];
110 FILE *fp;
111
112 sprintf(buf, "/proc/%d/cmdline", pid);
113 fp = fopen(buf, "r");
114 if (fp && fgets (buf, sizeof (buf), fp) ) {
115 if (strncmp (buf, exec, strlen(exec)) == 0)
116 return 1;
117 }
118 return 0;
119}
120
121
122static int
123pid_is_user(int pid, int uid)
124{
125 struct stat sb;
126 char buf[32];
127
128 sprintf(buf, "/proc/%d", pid);
129 if (stat(buf, &sb) != 0)
130 return 0;
131 return (sb.st_uid == uid);
132}
133
134
135static int
136pid_is_cmd(int pid, const char *name)
137{
138 char buf[32];
139 FILE *f;
140 int c;
141
142 sprintf(buf, "/proc/%d/stat", pid);
143 f = fopen(buf, "r");
144 if (!f)
145 return 0;
146 while ((c = getc(f)) != EOF && c != '(')
147 ;
148 if (c != '(') {
149 fclose(f);
150 return 0;
151 }
152 /* this hopefully handles command names containing ')' */
153 while ((c = getc(f)) != EOF && c == *name)
154 name++;
155 fclose(f);
156 return (c == ')' && *name == '\0');
157}
158
159
160static void
161check(int pid)
162{
163 if (execname && !pid_is_exec(pid, execname)) {
164 return;
165 }
166 if (userspec && !pid_is_user(pid, user_id)) {
167 return;
168 }
169 if (cmdname && !pid_is_cmd(pid, cmdname)) {
170 return;
171 }
172 push(&found, pid);
173}
174
175
176
177static void
178do_procfs(void)
179{
180 DIR *procdir;
181 struct dirent *entry;
182 int foundany, pid;
183
184 procdir = opendir("/proc");
185 if (!procdir)
186 perror_msg_and_die ("opendir /proc");
187
188 foundany = 0;
189 while ((entry = readdir(procdir)) != NULL) {
190 if (sscanf(entry->d_name, "%d", &pid) != 1)
191 continue;
192 foundany++;
193 check(pid);
194 }
195 closedir(procdir);
196 if (!foundany)
197 error_msg_and_die ("nothing in /proc - not mounted?");
198}
199
200
201static void
202do_stop(void)
203{
204 char what[1024];
205 struct pid_list *p;
206
207 if (cmdname)
208 strcpy(what, cmdname);
209 else if (execname)
210 strcpy(what, execname);
211 else if (userspec)
212 sprintf(what, "process(es) owned by `%s'", userspec);
213 else
214 error_msg_and_die ("internal error, please report");
215
216 if (!found) {
217 printf("no %s found; none killed.\n", what);
218 exit(0);
219 }
220 for (p = found; p; p = p->next) {
221 if (kill(p->pid, signal_nr) == 0)
222 push(&killed, p->pid);
223 else
224 printf("%s: warning: failed to kill %d: %s\n",
225 progname, p->pid, strerror(errno));
226 }
227 if (killed) {
228 printf("stopped %s (pid", what);
229 for (p = killed; p; p = p->next)
230 printf(" %d", p->pid);
231 printf(").\n");
232 }
233}
234
235
236int
237start_stop_daemon_main(int argc, char **argv)
238{
239 progname = argv[0];
240
241 parse_options(argc, argv);
242 argc -= optind;
243 argv += optind;
244
245 if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
246 struct passwd *pw;
247
248 pw = getpwnam(userspec);
249 if (!pw)
250 error_msg_and_die ("user `%s' not found\n", userspec);
251
252 user_id = pw->pw_uid;
253 }
254
255 do_procfs();
256
257 if (stop) {
258 do_stop();
259 exit(0);
260 }
261
262 if (found) {
263 printf("%s already running.\n", execname);
264 printf("%d\n",found->pid);
265 exit(0);
266 }
267 *--argv = startas;
268 execv(startas, argv);
269 perror_msg_and_die ("unable to start %s", startas);
270}
271
diff --git a/stty.c b/stty.c
deleted file mode 100644
index 2e00a496d..000000000
--- a/stty.c
+++ /dev/null
@@ -1,1376 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/* stty -- change and print terminal line settings
3 Copyright (C) 1990-1999 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 You should have received a copy of the GNU General Public License
11 along with this program; if not, write to the Free Software Foundation,
12 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
13
14/* Usage: stty [-ag] [-F device] [setting...]
15
16 Options:
17 -a Write all current settings to stdout in human-readable form.
18 -g Write all current settings to stdout in stty-readable form.
19 -F Open and use the specified device instead of stdin
20
21 If no args are given, write to stdout the baud rate and settings that
22 have been changed from their defaults. Mode reading and changes
23 are done on the specified device, or stdin if none was specified.
24
25 David MacKenzie <djm@gnu.ai.mit.edu>
26
27 Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
28
29 */
30
31//#define TEST
32
33#include <termios.h>
34#include <sys/ioctl.h>
35#include <getopt.h>
36
37#include <sys/param.h>
38#include <unistd.h>
39
40#ifndef STDIN_FILENO
41# define STDIN_FILENO 0
42#endif
43
44#ifndef STDOUT_FILENO
45# define STDOUT_FILENO 1
46#endif
47
48#include <stdlib.h>
49#include <string.h>
50#include <assert.h>
51#include <ctype.h>
52#include <errno.h>
53#include <limits.h>
54#include <memory.h>
55#include <fcntl.h>
56#include "busybox.h"
57
58#define STREQ(a, b) (strcmp ((a), (b)) == 0)
59
60
61#ifndef _POSIX_VDISABLE
62# define _POSIX_VDISABLE ((unsigned char) 0)
63#endif
64
65#define Control(c) ((c) & 0x1f)
66/* Canonical values for control characters. */
67#ifndef CINTR
68# define CINTR Control ('c')
69#endif
70#ifndef CQUIT
71# define CQUIT 28
72#endif
73#ifndef CERASE
74# define CERASE 127
75#endif
76#ifndef CKILL
77# define CKILL Control ('u')
78#endif
79#ifndef CEOF
80# define CEOF Control ('d')
81#endif
82#ifndef CEOL
83# define CEOL _POSIX_VDISABLE
84#endif
85#ifndef CSTART
86# define CSTART Control ('q')
87#endif
88#ifndef CSTOP
89# define CSTOP Control ('s')
90#endif
91#ifndef CSUSP
92# define CSUSP Control ('z')
93#endif
94#if defined(VEOL2) && !defined(CEOL2)
95# define CEOL2 _POSIX_VDISABLE
96#endif
97/* ISC renamed swtch to susp for termios, but we'll accept either name. */
98#if defined(VSUSP) && !defined(VSWTCH)
99# define VSWTCH VSUSP
100# define CSWTCH CSUSP
101#endif
102#if defined(VSWTCH) && !defined(CSWTCH)
103# define CSWTCH _POSIX_VDISABLE
104#endif
105
106/* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
107 So the default is to disable `swtch.' */
108#if defined (__sparc__) && defined (__svr4__)
109# undef CSWTCH
110# define CSWTCH _POSIX_VDISABLE
111#endif
112
113#if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
114# define VWERASE VWERSE
115#endif
116#if defined(VDSUSP) && !defined (CDSUSP)
117# define CDSUSP Control ('y')
118#endif
119#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
120# define VREPRINT VRPRNT
121#endif
122#if defined(VREPRINT) && !defined(CRPRNT)
123# define CRPRNT Control ('r')
124#endif
125#if defined(VWERASE) && !defined(CWERASE)
126# define CWERASE Control ('w')
127#endif
128#if defined(VLNEXT) && !defined(CLNEXT)
129# define CLNEXT Control ('v')
130#endif
131#if defined(VDISCARD) && !defined(VFLUSHO)
132# define VFLUSHO VDISCARD
133#endif
134#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
135# define VFLUSHO VFLUSH
136#endif
137#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
138# define ECHOCTL CTLECH
139#endif
140#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
141# define ECHOCTL TCTLECH
142#endif
143#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
144# define ECHOKE CRTKIL
145#endif
146#if defined(VFLUSHO) && !defined(CFLUSHO)
147# define CFLUSHO Control ('o')
148#endif
149#if defined(VSTATUS) && !defined(CSTATUS)
150# define CSTATUS Control ('t')
151#endif
152
153/* Which speeds to set. */
154enum speed_setting {
155 input_speed, output_speed, both_speeds
156};
157
158/* What to output and how. */
159enum output_type {
160 changed, all, recoverable /* Default, -a, -g. */
161};
162
163/* Which member(s) of `struct termios' a mode uses. */
164enum mode_type {
165 control, input, output, local, combination
166};
167
168
169static const char evenp [] = "evenp";
170static const char raw [] = "raw";
171static const char stty_min [] = "min";
172static const char stty_time [] = "time";
173static const char stty_swtch[] = "swtch";
174static const char stty_eol [] = "eol";
175static const char stty_eof [] = "eof";
176static const char parity [] = "parity";
177static const char stty_oddp [] = "oddp";
178static const char stty_nl [] = "nl";
179static const char stty_ek [] = "ek";
180static const char stty_sane [] = "sane";
181static const char cbreak [] = "cbreak";
182static const char stty_pass8[] = "pass8";
183static const char litout [] = "litout";
184static const char cooked [] = "cooked";
185static const char decctlq [] = "decctlq";
186static const char stty_tabs [] = "tabs";
187static const char stty_lcase[] = "lcase";
188static const char stty_LCASE[] = "LCASE";
189static const char stty_crt [] = "crt";
190static const char stty_dec [] = "dec";
191
192
193/* Flags for `struct mode_info'. */
194#define SANE_SET 1 /* Set in `sane' mode. */
195#define SANE_UNSET 2 /* Unset in `sane' mode. */
196#define REV 4 /* Can be turned off by prepending `-'. */
197#define OMIT 8 /* Don't display value. */
198
199/* Each mode. */
200struct mode_info {
201 const char *name; /* Name given on command line. */
202 enum mode_type type; /* Which structure element to change. */
203 char flags; /* Setting and display options. */
204 unsigned long bits; /* Bits to set for this mode. */
205 unsigned long mask; /* Other bits to turn off for this mode. */
206};
207
208static const struct mode_info mode_info[] = {
209 {"parenb", control, REV, PARENB, 0 },
210 {"parodd", control, REV, PARODD, 0 },
211 {"cs5", control, 0, CS5, CSIZE},
212 {"cs6", control, 0, CS6, CSIZE},
213 {"cs7", control, 0, CS7, CSIZE},
214 {"cs8", control, 0, CS8, CSIZE},
215 {"hupcl", control, REV, HUPCL, 0 },
216 {"hup", control, REV | OMIT, HUPCL, 0 },
217 {"cstopb", control, REV, CSTOPB, 0 },
218 {"cread", control, SANE_SET | REV, CREAD, 0 },
219 {"clocal", control, REV, CLOCAL, 0 },
220#ifdef CRTSCTS
221 {"crtscts", control, REV, CRTSCTS, 0 },
222#endif
223 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 },
224 {"brkint", input, SANE_SET | REV, BRKINT, 0 },
225 {"ignpar", input, REV, IGNPAR, 0 },
226 {"parmrk", input, REV, PARMRK, 0 },
227 {"inpck", input, REV, INPCK, 0 },
228 {"istrip", input, REV, ISTRIP, 0 },
229 {"inlcr", input, SANE_UNSET | REV, INLCR, 0 },
230 {"igncr", input, SANE_UNSET | REV, IGNCR, 0 },
231 {"icrnl", input, SANE_SET | REV, ICRNL, 0 },
232 {"ixon", input, REV, IXON, 0 },
233 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0 },
234 {"tandem", input, REV | OMIT, IXOFF, 0 },
235#ifdef IUCLC
236 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0 },
237#endif
238#ifdef IXANY
239 {"ixany", input, SANE_UNSET | REV, IXANY, 0 },
240#endif
241#ifdef IMAXBEL
242 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0 },
243#endif
244 {"opost", output, SANE_SET | REV, OPOST, 0 },
245#ifdef OLCUC
246 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0 },
247#endif
248#ifdef OCRNL
249 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0 },
250#endif
251#ifdef ONLCR
252 {"onlcr", output, SANE_SET | REV, ONLCR, 0 },
253#endif
254#ifdef ONOCR
255 {"onocr", output, SANE_UNSET | REV, ONOCR, 0 },
256#endif
257#ifdef ONLRET
258 {"onlret", output, SANE_UNSET | REV, ONLRET, 0 },
259#endif
260#ifdef OFILL
261 {"ofill", output, SANE_UNSET | REV, OFILL, 0 },
262#endif
263#ifdef OFDEL
264 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0 },
265#endif
266#ifdef NLDLY
267 {"nl1", output, SANE_UNSET, NL1, NLDLY},
268 {"nl0", output, SANE_SET, NL0, NLDLY},
269#endif
270#ifdef CRDLY
271 {"cr3", output, SANE_UNSET, CR3, CRDLY},
272 {"cr2", output, SANE_UNSET, CR2, CRDLY},
273 {"cr1", output, SANE_UNSET, CR1, CRDLY},
274 {"cr0", output, SANE_SET, CR0, CRDLY},
275#endif
276
277#ifdef TABDLY
278 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
279 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
280 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
281 {"tab0", output, SANE_SET, TAB0, TABDLY},
282#else
283# ifdef OXTABS
284 {"tab3", output, SANE_UNSET, OXTABS, 0 },
285# endif
286#endif
287
288#ifdef BSDLY
289 {"bs1", output, SANE_UNSET, BS1, BSDLY},
290 {"bs0", output, SANE_SET, BS0, BSDLY},
291#endif
292#ifdef VTDLY
293 {"vt1", output, SANE_UNSET, VT1, VTDLY},
294 {"vt0", output, SANE_SET, VT0, VTDLY},
295#endif
296#ifdef FFDLY
297 {"ff1", output, SANE_UNSET, FF1, FFDLY},
298 {"ff0", output, SANE_SET, FF0, FFDLY},
299#endif
300 {"isig", local, SANE_SET | REV, ISIG, 0 },
301 {"icanon", local, SANE_SET | REV, ICANON, 0 },
302#ifdef IEXTEN
303 {"iexten", local, SANE_SET | REV, IEXTEN, 0 },
304#endif
305 {"echo", local, SANE_SET | REV, ECHO, 0 },
306 {"echoe", local, SANE_SET | REV, ECHOE, 0 },
307 {"crterase", local, REV | OMIT, ECHOE, 0 },
308 {"echok", local, SANE_SET | REV, ECHOK, 0 },
309 {"echonl", local, SANE_UNSET | REV, ECHONL, 0 },
310 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0 },
311#ifdef XCASE
312 {"xcase", local, SANE_UNSET | REV, XCASE, 0 },
313#endif
314#ifdef TOSTOP
315 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0 },
316#endif
317#ifdef ECHOPRT
318 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 },
319 {"prterase", local, REV | OMIT, ECHOPRT, 0 },
320#endif
321#ifdef ECHOCTL
322 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0 },
323 {"ctlecho", local, REV | OMIT, ECHOCTL, 0 },
324#endif
325#ifdef ECHOKE
326 {"echoke", local, SANE_SET | REV, ECHOKE, 0 },
327 {"crtkill", local, REV | OMIT, ECHOKE, 0 },
328#endif
329 {evenp, combination, REV | OMIT, 0, 0 },
330 {parity, combination, REV | OMIT, 0, 0 },
331 {stty_oddp, combination, REV | OMIT, 0, 0 },
332 {stty_nl, combination, REV | OMIT, 0, 0 },
333 {stty_ek, combination, OMIT, 0, 0 },
334 {stty_sane, combination, OMIT, 0, 0 },
335 {cooked, combination, REV | OMIT, 0, 0 },
336 {raw, combination, REV | OMIT, 0, 0 },
337 {stty_pass8, combination, REV | OMIT, 0, 0 },
338 {litout, combination, REV | OMIT, 0, 0 },
339 {cbreak, combination, REV | OMIT, 0, 0 },
340#ifdef IXANY
341 {decctlq, combination, REV | OMIT, 0, 0 },
342#endif
343#if defined (TABDLY) || defined (OXTABS)
344 {stty_tabs, combination, REV | OMIT, 0, 0 },
345#endif
346#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
347 {stty_lcase, combination, REV | OMIT, 0, 0 },
348 {stty_LCASE, combination, REV | OMIT, 0, 0 },
349#endif
350 {stty_crt, combination, OMIT, 0, 0 },
351 {stty_dec, combination, OMIT, 0, 0 },
352};
353
354static const int NUM_mode_info =
355
356 (sizeof(mode_info) / sizeof(struct mode_info));
357
358/* Control character settings. */
359struct control_info {
360 const char *name; /* Name given on command line. */
361 unsigned char saneval; /* Value to set for `stty sane'. */
362 int offset; /* Offset in c_cc. */
363};
364
365/* Control characters. */
366
367static const struct control_info control_info[] = {
368 {"intr", CINTR, VINTR},
369 {"quit", CQUIT, VQUIT},
370 {"erase", CERASE, VERASE},
371 {"kill", CKILL, VKILL},
372 {stty_eof, CEOF, VEOF},
373 {stty_eol, CEOL, VEOL},
374#ifdef VEOL2
375 {"eol2", CEOL2, VEOL2},
376#endif
377#ifdef VSWTCH
378 {stty_swtch, CSWTCH, VSWTCH},
379#endif
380 {"start", CSTART, VSTART},
381 {"stop", CSTOP, VSTOP},
382 {"susp", CSUSP, VSUSP},
383#ifdef VDSUSP
384 {"dsusp", CDSUSP, VDSUSP},
385#endif
386#ifdef VREPRINT
387 {"rprnt", CRPRNT, VREPRINT},
388#endif
389#ifdef VWERASE
390 {"werase", CWERASE, VWERASE},
391#endif
392#ifdef VLNEXT
393 {"lnext", CLNEXT, VLNEXT},
394#endif
395#ifdef VFLUSHO
396 {"flush", CFLUSHO, VFLUSHO},
397#endif
398#ifdef VSTATUS
399 {"status", CSTATUS, VSTATUS},
400#endif
401 /* These must be last because of the display routines. */
402 {stty_min, 1, VMIN},
403 {stty_time, 0, VTIME},
404};
405
406static const int NUM_control_info =
407 (sizeof(control_info) / sizeof(struct control_info));
408
409
410static const char * visible(unsigned int ch);
411static unsigned long baud_to_value(speed_t speed);
412static int recover_mode(char *arg, struct termios *mode);
413static int screen_columns(void);
414static int set_mode(const struct mode_info *info,
415 int reversed, struct termios *mode);
416static speed_t string_to_baud(const char *arg);
417static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode);
418static void display_all(struct termios *mode, int fd,
419 const char *device_name);
420static void display_changed(struct termios *mode);
421static void display_recoverable(struct termios *mode);
422static void display_settings(enum output_type output_type,
423 struct termios *mode, int fd,
424 const char *device_name);
425static void display_speed(struct termios *mode, int fancy);
426static void display_window_size(int fancy, int fd,
427 const char *device_name);
428static void sane_mode(struct termios *mode);
429static void set_control_char(const struct control_info *info,
430 const char *arg, struct termios *mode);
431static void set_speed(enum speed_setting type,
432 const char *arg, struct termios *mode);
433static void set_window_size(int rows, int cols, int fd,
434 const char *device_name);
435
436/* The width of the screen, for output wrapping. */
437static int max_col;
438
439/* Current position, to know when to wrap. */
440static int current_col;
441
442/* Print format string MESSAGE and optional args.
443 Wrap to next line first if it won't fit.
444 Print a space first unless MESSAGE will start a new line. */
445
446static void wrapf(const char *message, ...)
447{
448 va_list args;
449 char buf[1024]; /* Plenty long for our needs. */
450 int buflen;
451
452 va_start(args, message);
453 vsprintf(buf, message, args);
454 va_end(args);
455 buflen = strlen(buf);
456 if (current_col + (current_col > 0) + buflen >= max_col) {
457 putchar('\n');
458 current_col = 0;
459 }
460 if (current_col > 0) {
461 putchar(' ');
462 current_col++;
463 }
464 fputs(buf, stdout);
465 current_col += buflen;
466}
467
468static const struct suffix_mult stty_suffixes[] = {
469 {"b", 512 },
470 {"k", 1024},
471 {"B", 1024},
472 {NULL, 0 }
473};
474
475#ifndef TEST
476extern int stty_main(int argc, char **argv)
477#else
478extern int main(int argc, char **argv)
479#endif
480{
481 struct termios mode;
482 enum output_type output_type;
483 int optc;
484 int require_set_attr;
485 int speed_was_set;
486 int verbose_output;
487 int recoverable_output;
488 int k;
489 int noargs = 1;
490 char * file_name = NULL;
491 int fd;
492 const char *device_name;
493
494 output_type = changed;
495 verbose_output = 0;
496 recoverable_output = 0;
497
498 /* Don't print error messages for unrecognized options. */
499 opterr = 0;
500
501 while ((optc = getopt(argc, argv, "agF:")) != -1) {
502 switch (optc) {
503 case 'a':
504 verbose_output = 1;
505 output_type = all;
506 break;
507
508 case 'g':
509 recoverable_output = 1;
510 output_type = recoverable;
511 break;
512
513 case 'F':
514 if (file_name)
515 error_msg_and_die("only one device may be specified");
516 file_name = optarg;
517 break;
518
519 default: /* unrecognized option */
520 noargs = 0;
521 break;
522 }
523
524 if (noargs == 0)
525 break;
526 }
527
528 if (optind < argc)
529 noargs = 0;
530
531 /* Specifying both -a and -g gets an error. */
532 if (verbose_output && recoverable_output)
533 error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
534
535 /* Specifying any other arguments with -a or -g gets an error. */
536 if (!noargs && (verbose_output || recoverable_output))
537 error_msg_and_die ("modes may not be set when specifying an output style");
538
539 /* FIXME: it'd be better not to open the file until we've verified
540 that all arguments are valid. Otherwise, we could end up doing
541 only some of the requested operations and then failing, probably
542 leaving things in an undesirable state. */
543
544 if (file_name) {
545 int fdflags;
546
547 device_name = file_name;
548 fd = open(device_name, O_RDONLY | O_NONBLOCK);
549 if (fd < 0)
550 perror_msg_and_die("%s", device_name);
551 if ((fdflags = fcntl(fd, F_GETFL)) == -1
552 || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
553 perror_msg_and_die("%s: couldn't reset non-blocking mode",
554 device_name);
555 } else {
556 fd = 0;
557 device_name = "standard input";
558 }
559
560 /* Initialize to all zeroes so there is no risk memcmp will report a
561 spurious difference in an uninitialized portion of the structure. */
562 memset(&mode, 0, sizeof(mode));
563 if (tcgetattr(fd, &mode))
564 perror_msg_and_die("%s", device_name);
565
566 if (verbose_output || recoverable_output || noargs) {
567 max_col = screen_columns();
568 current_col = 0;
569 display_settings(output_type, &mode, fd, device_name);
570 return EXIT_SUCCESS;
571 }
572
573 speed_was_set = 0;
574 require_set_attr = 0;
575 k = optind;
576 while (k < argc) {
577 int match_found = 0;
578 int reversed = 0;
579 int i;
580
581 if (argv[k][0] == '-') {
582 ++argv[k];
583 reversed = 1;
584 }
585 for (i = 0; i < NUM_mode_info; ++i)
586 if (STREQ(argv[k], mode_info[i].name)) {
587 match_found = set_mode(&mode_info[i], reversed, &mode);
588 require_set_attr = 1;
589 break;
590 }
591
592 if (match_found == 0 && reversed)
593 error_msg_and_die("invalid argument `%s'", --argv[k]);
594
595 if (match_found == 0)
596 for (i = 0; i < NUM_control_info; ++i)
597 if (STREQ(argv[k], control_info[i].name)) {
598 if (k == argc - 1)
599 error_msg_and_die("missing argument to `%s'", argv[k]);
600 match_found = 1;
601 ++k;
602 set_control_char(&control_info[i], argv[k], &mode);
603 require_set_attr = 1;
604 break;
605 }
606
607 if (match_found == 0) {
608 if (STREQ(argv[k], "ispeed")) {
609 if (k == argc - 1)
610 error_msg_and_die("missing argument to `%s'", argv[k]);
611 ++k;
612 set_speed(input_speed, argv[k], &mode);
613 speed_was_set = 1;
614 require_set_attr = 1;
615 } else if (STREQ(argv[k], "ospeed")) {
616 if (k == argc - 1)
617 error_msg_and_die("missing argument to `%s'", argv[k]);
618 ++k;
619 set_speed(output_speed, argv[k], &mode);
620 speed_was_set = 1;
621 require_set_attr = 1;
622 }
623#ifdef TIOCGWINSZ
624 else if (STREQ(argv[k], "rows")) {
625 if (k == argc - 1)
626 error_msg_and_die("missing argument to `%s'", argv[k]);
627 ++k;
628 set_window_size((int) parse_number(argv[k], stty_suffixes),
629 -1, fd, device_name);
630 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
631 if (k == argc - 1)
632 error_msg_and_die("missing argument to `%s'", argv[k]);
633 ++k;
634 set_window_size(-1,
635 (int) parse_number(argv[k], stty_suffixes),
636 fd, device_name);
637 } else if (STREQ(argv[k], "size")) {
638 max_col = screen_columns();
639 current_col = 0;
640 display_window_size(0, fd, device_name);
641 }
642#endif
643#ifdef HAVE_C_LINE
644 else if (STREQ(argv[k], "line")) {
645 if (k == argc - 1)
646 error_msg_and_die("missing argument to `%s'", argv[k]);
647 ++k;
648 mode.c_line = parse_number(argv[k], stty_suffixes);
649 require_set_attr = 1;
650 }
651#endif
652 else if (STREQ(argv[k], "speed")) {
653 max_col = screen_columns();
654 display_speed(&mode, 0);
655 } else if (recover_mode(argv[k], &mode) == 1)
656 require_set_attr = 1;
657 else if (string_to_baud(argv[k]) != (speed_t) - 1) {
658 set_speed(both_speeds, argv[k], &mode);
659 speed_was_set = 1;
660 require_set_attr = 1;
661 } else
662 error_msg_and_die("invalid argument `%s'", argv[k]);
663 }
664 k++;
665 }
666
667 if (require_set_attr) {
668 struct termios new_mode;
669
670 if (tcsetattr(fd, TCSADRAIN, &mode))
671 perror_msg_and_die("%s", device_name);
672
673 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
674 it performs *any* of the requested operations. This means it
675 can report `success' when it has actually failed to perform
676 some proper subset of the requested operations. To detect
677 this partial failure, get the current terminal attributes and
678 compare them to the requested ones. */
679
680 /* Initialize to all zeroes so there is no risk memcmp will report a
681 spurious difference in an uninitialized portion of the structure. */
682 memset(&new_mode, 0, sizeof(new_mode));
683 if (tcgetattr(fd, &new_mode))
684 perror_msg_and_die("%s", device_name);
685
686 /* Normally, one shouldn't use memcmp to compare structures that
687 may have `holes' containing uninitialized data, but we have been
688 careful to initialize the storage of these two variables to all
689 zeroes. One might think it more efficient simply to compare the
690 modified fields, but that would require enumerating those fields --
691 and not all systems have the same fields in this structure. */
692
693 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
694#ifdef CIBAUD
695 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
696 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
697 sometimes (m1 != m2). The only difference is in the four bits
698 of the c_cflag field corresponding to the baud rate. To save
699 Sun users a little confusion, don't report an error if this
700 happens. But suppress the error only if we haven't tried to
701 set the baud rate explicitly -- otherwise we'd never give an
702 error for a true failure to set the baud rate. */
703
704 new_mode.c_cflag &= (~CIBAUD);
705 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
706#endif
707 error_msg_and_die ("%s: unable to perform all requested operations",
708 device_name);
709 }
710 }
711
712 return EXIT_SUCCESS;
713}
714
715/* Return 0 if not applied because not reversible; otherwise return 1. */
716
717static int
718set_mode(const struct mode_info *info, int reversed, struct termios *mode)
719{
720 tcflag_t *bitsp;
721
722 if (reversed && (info->flags & REV) == 0)
723 return 0;
724
725 bitsp = mode_type_flag(info->type, mode);
726
727 if (bitsp == NULL) {
728 /* Combination mode. */
729 if (info->name == evenp || info->name == parity) {
730 if (reversed)
731 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
732 else
733 mode->c_cflag =
734 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
735 } else if (info->name == stty_oddp) {
736 if (reversed)
737 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
738 else
739 mode->c_cflag =
740 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
741 } else if (info->name == stty_nl) {
742 if (reversed) {
743 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
744 mode->c_oflag = (mode->c_oflag
745#ifdef ONLCR
746 | ONLCR
747#endif
748 )
749#ifdef OCRNL
750 & ~OCRNL
751#endif
752#ifdef ONLRET
753 & ~ONLRET
754#endif
755 ;
756 } else {
757 mode->c_iflag = mode->c_iflag & ~ICRNL;
758#ifdef ONLCR
759 mode->c_oflag = mode->c_oflag & ~ONLCR;
760#endif
761 }
762 } else if (info->name == stty_ek) {
763 mode->c_cc[VERASE] = CERASE;
764 mode->c_cc[VKILL] = CKILL;
765 } else if (info->name == stty_sane)
766 sane_mode(mode);
767 else if (info->name == cbreak) {
768 if (reversed)
769 mode->c_lflag |= ICANON;
770 else
771 mode->c_lflag &= ~ICANON;
772 } else if (info->name == stty_pass8) {
773 if (reversed) {
774 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
775 mode->c_iflag |= ISTRIP;
776 } else {
777 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
778 mode->c_iflag &= ~ISTRIP;
779 }
780 } else if (info->name == litout) {
781 if (reversed) {
782 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
783 mode->c_iflag |= ISTRIP;
784 mode->c_oflag |= OPOST;
785 } else {
786 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
787 mode->c_iflag &= ~ISTRIP;
788 mode->c_oflag &= ~OPOST;
789 }
790 } else if (info->name == raw || info->name == cooked) {
791 if ((info->name[0] == 'r' && reversed)
792 || (info->name[0] == 'c' && !reversed)) {
793 /* Cooked mode. */
794 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
795 mode->c_oflag |= OPOST;
796 mode->c_lflag |= ISIG | ICANON;
797#if VMIN == VEOF
798 mode->c_cc[VEOF] = CEOF;
799#endif
800#if VTIME == VEOL
801 mode->c_cc[VEOL] = CEOL;
802#endif
803 } else {
804 /* Raw mode. */
805 mode->c_iflag = 0;
806 mode->c_oflag &= ~OPOST;
807 mode->c_lflag &= ~(ISIG | ICANON
808#ifdef XCASE
809 | XCASE
810#endif
811 );
812 mode->c_cc[VMIN] = 1;
813 mode->c_cc[VTIME] = 0;
814 }
815 }
816#ifdef IXANY
817 else if (info->name == decctlq) {
818 if (reversed)
819 mode->c_iflag |= IXANY;
820 else
821 mode->c_iflag &= ~IXANY;
822 }
823#endif
824#ifdef TABDLY
825 else if (info->name == stty_tabs) {
826 if (reversed)
827 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
828 else
829 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
830 }
831#else
832# ifdef OXTABS
833 else if (info->name == stty_tabs) {
834 if (reversed)
835 mode->c_oflag = mode->c_oflag | OXTABS;
836 else
837 mode->c_oflag = mode->c_oflag & ~OXTABS;
838 }
839# endif
840#endif
841#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
842 else if (info->name == stty_lcase || info->name == stty_LCASE) {
843 if (reversed) {
844 mode->c_lflag &= ~XCASE;
845 mode->c_iflag &= ~IUCLC;
846 mode->c_oflag &= ~OLCUC;
847 } else {
848 mode->c_lflag |= XCASE;
849 mode->c_iflag |= IUCLC;
850 mode->c_oflag |= OLCUC;
851 }
852 }
853#endif
854 else if (info->name == stty_crt)
855 mode->c_lflag |= ECHOE
856#ifdef ECHOCTL
857 | ECHOCTL
858#endif
859#ifdef ECHOKE
860 | ECHOKE
861#endif
862 ;
863 else if (info->name == stty_dec) {
864 mode->c_cc[VINTR] = 3; /* ^C */
865 mode->c_cc[VERASE] = 127; /* DEL */
866 mode->c_cc[VKILL] = 21; /* ^U */
867 mode->c_lflag |= ECHOE
868#ifdef ECHOCTL
869 | ECHOCTL
870#endif
871#ifdef ECHOKE
872 | ECHOKE
873#endif
874 ;
875#ifdef IXANY
876 mode->c_iflag &= ~IXANY;
877#endif
878 }
879 } else if (reversed)
880 *bitsp = *bitsp & ~info->mask & ~info->bits;
881 else
882 *bitsp = (*bitsp & ~info->mask) | info->bits;
883
884 return 1;
885}
886
887static void
888set_control_char(const struct control_info *info, const char *arg,
889 struct termios *mode)
890{
891 unsigned char value;
892
893 if (info->name == stty_min || info->name == stty_time)
894 value = parse_number(arg, stty_suffixes);
895 else if (arg[0] == '\0' || arg[1] == '\0')
896 value = arg[0];
897 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
898 value = _POSIX_VDISABLE;
899 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
900 if (arg[1] == '?')
901 value = 127;
902 else
903 value = arg[1] & ~0140; /* Non-letters get weird results. */
904 } else
905 value = parse_number(arg, stty_suffixes);
906 mode->c_cc[info->offset] = value;
907}
908
909static void
910set_speed(enum speed_setting type, const char *arg, struct termios *mode)
911{
912 speed_t baud;
913
914 baud = string_to_baud(arg);
915 if (type == input_speed || type == both_speeds)
916 cfsetispeed(mode, baud);
917 if (type == output_speed || type == both_speeds)
918 cfsetospeed(mode, baud);
919}
920
921#ifdef TIOCGWINSZ
922
923static int get_win_size(int fd, struct winsize *win)
924{
925 int err = ioctl(fd, TIOCGWINSZ, (char *) win);
926
927 return err;
928}
929
930static void
931set_window_size(int rows, int cols, int fd, const char *device_name)
932{
933 struct winsize win;
934
935 if (get_win_size(fd, &win)) {
936 if (errno != EINVAL)
937 perror_msg_and_die("%s", device_name);
938 memset(&win, 0, sizeof(win));
939 }
940
941 if (rows >= 0)
942 win.ws_row = rows;
943 if (cols >= 0)
944 win.ws_col = cols;
945
946# ifdef TIOCSSIZE
947 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
948 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
949 This comment from sys/ttold.h describes Sun's twisted logic - a better
950 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
951 At any rate, the problem is gone in Solaris 2.x. */
952
953 if (win.ws_row == 0 || win.ws_col == 0) {
954 struct ttysize ttysz;
955
956 ttysz.ts_lines = win.ws_row;
957 ttysz.ts_cols = win.ws_col;
958
959 win.ws_row = 1;
960 win.ws_col = 1;
961
962 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
963 perror_msg_and_die("%s", device_name);
964
965 if (ioctl(fd, TIOCSSIZE, (char *) &ttysz))
966 perror_msg_and_die("%s", device_name);
967 return;
968 }
969# endif
970
971 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
972 perror_msg_and_die("%s", device_name);
973}
974
975static void display_window_size(int fancy, int fd, const char *device_name)
976{
977 struct winsize win;
978
979 if (get_win_size(fd, &win)) {
980 if (errno != EINVAL)
981 perror_msg_and_die("%s", device_name);
982 if (!fancy)
983 perror_msg_and_die("%s: no size information for this device",
984 device_name);
985 } else {
986 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
987 win.ws_row, win.ws_col);
988 if (!fancy)
989 current_col = 0;
990 }
991}
992#endif
993
994static int screen_columns(void)
995{
996#ifdef TIOCGWINSZ
997 struct winsize win;
998
999 /* With Solaris 2.[123], this ioctl fails and errno is set to
1000 EINVAL for telnet (but not rlogin) sessions.
1001 On ISC 3.0, it fails for the console and the serial port
1002 (but it works for ptys).
1003 It can also fail on any system when stdout isn't a tty.
1004 In case of any failure, just use the default. */
1005 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1006 return win.ws_col;
1007#endif
1008
1009 if (getenv("COLUMNS"))
1010 return atoi(getenv("COLUMNS"));
1011 return 80;
1012}
1013
1014static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1015{
1016 switch (type) {
1017 case control:
1018 return &mode->c_cflag;
1019
1020 case input:
1021 return &mode->c_iflag;
1022
1023 case output:
1024 return &mode->c_oflag;
1025
1026 case local:
1027 return &mode->c_lflag;
1028
1029 default: /* combination: */
1030 return NULL;
1031 }
1032}
1033
1034static void
1035display_settings(enum output_type output_type, struct termios *mode,
1036 int fd, const char *device_name)
1037{
1038 switch (output_type) {
1039 case changed:
1040 display_changed(mode);
1041 break;
1042
1043 case all:
1044 display_all(mode, fd, device_name);
1045 break;
1046
1047 case recoverable:
1048 display_recoverable(mode);
1049 break;
1050 }
1051}
1052
1053static void display_changed(struct termios *mode)
1054{
1055 int i;
1056 int empty_line;
1057 tcflag_t *bitsp;
1058 unsigned long mask;
1059 enum mode_type prev_type = control;
1060
1061 display_speed(mode, 1);
1062#ifdef HAVE_C_LINE
1063 wrapf("line = %d;", mode->c_line);
1064#endif
1065 putchar('\n');
1066 current_col = 0;
1067
1068 empty_line = 1;
1069 for (i = 0; control_info[i].name != stty_min; ++i) {
1070 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1071 continue;
1072 /* If swtch is the same as susp, don't print both. */
1073#if VSWTCH == VSUSP
1074 if (control_info[i].name == stty_swtch)
1075 continue;
1076#endif
1077 /* If eof uses the same slot as min, only print whichever applies. */
1078#if VEOF == VMIN
1079 if ((mode->c_lflag & ICANON) == 0
1080 && (control_info[i].name == stty_eof
1081 || control_info[i].name == stty_eol)) continue;
1082#endif
1083
1084 empty_line = 0;
1085 wrapf("%s = %s;", control_info[i].name,
1086 visible(mode->c_cc[control_info[i].offset]));
1087 }
1088 if ((mode->c_lflag & ICANON) == 0) {
1089 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1090 (int) mode->c_cc[VTIME]);
1091 } else if (empty_line == 0)
1092 putchar('\n');
1093 current_col = 0;
1094
1095 empty_line = 1;
1096 for (i = 0; i < NUM_mode_info; ++i) {
1097 if (mode_info[i].flags & OMIT)
1098 continue;
1099 if (mode_info[i].type != prev_type) {
1100 if (empty_line == 0) {
1101 putchar('\n');
1102 current_col = 0;
1103 empty_line = 1;
1104 }
1105 prev_type = mode_info[i].type;
1106 }
1107
1108 bitsp = mode_type_flag(mode_info[i].type, mode);
1109 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1110 if ((*bitsp & mask) == mode_info[i].bits) {
1111 if (mode_info[i].flags & SANE_UNSET) {
1112 wrapf("%s", mode_info[i].name);
1113 empty_line = 0;
1114 }
1115 }
1116 else if ((mode_info[i].flags & (SANE_SET | REV)) ==
1117 (SANE_SET | REV)) {
1118 wrapf("-%s", mode_info[i].name);
1119 empty_line = 0;
1120 }
1121 }
1122 if (empty_line == 0)
1123 putchar('\n');
1124 current_col = 0;
1125}
1126
1127static void
1128display_all(struct termios *mode, int fd, const char *device_name)
1129{
1130 int i;
1131 tcflag_t *bitsp;
1132 unsigned long mask;
1133 enum mode_type prev_type = control;
1134
1135 display_speed(mode, 1);
1136#ifdef TIOCGWINSZ
1137 display_window_size(1, fd, device_name);
1138#endif
1139#ifdef HAVE_C_LINE
1140 wrapf("line = %d;", mode->c_line);
1141#endif
1142 putchar('\n');
1143 current_col = 0;
1144
1145 for (i = 0; control_info[i].name != stty_min; ++i) {
1146 /* If swtch is the same as susp, don't print both. */
1147#if VSWTCH == VSUSP
1148 if (control_info[i].name == stty_swtch)
1149 continue;
1150#endif
1151 /* If eof uses the same slot as min, only print whichever applies. */
1152#if VEOF == VMIN
1153 if ((mode->c_lflag & ICANON) == 0
1154 && (control_info[i].name == stty_eof
1155 || control_info[i].name == stty_eol)) continue;
1156#endif
1157 wrapf("%s = %s;", control_info[i].name,
1158 visible(mode->c_cc[control_info[i].offset]));
1159 }
1160#if VEOF == VMIN
1161 if ((mode->c_lflag & ICANON) == 0)
1162#endif
1163 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1164 if (current_col != 0)
1165 putchar('\n');
1166 current_col = 0;
1167
1168 for (i = 0; i < NUM_mode_info; ++i) {
1169 if (mode_info[i].flags & OMIT)
1170 continue;
1171 if (mode_info[i].type != prev_type) {
1172 putchar('\n');
1173 current_col = 0;
1174 prev_type = mode_info[i].type;
1175 }
1176
1177 bitsp = mode_type_flag(mode_info[i].type, mode);
1178 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1179 if ((*bitsp & mask) == mode_info[i].bits)
1180 wrapf("%s", mode_info[i].name);
1181 else if (mode_info[i].flags & REV)
1182 wrapf("-%s", mode_info[i].name);
1183 }
1184 putchar('\n');
1185 current_col = 0;
1186}
1187
1188static void display_speed(struct termios *mode, int fancy)
1189{
1190 if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode))
1191 wrapf(fancy ? "speed %lu baud;" : "%lu\n",
1192 baud_to_value(cfgetospeed(mode)));
1193 else
1194 wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1195 baud_to_value(cfgetispeed(mode)),
1196 baud_to_value(cfgetospeed(mode)));
1197 if (!fancy)
1198 current_col = 0;
1199}
1200
1201static void display_recoverable(struct termios *mode)
1202{
1203 int i;
1204
1205 printf("%lx:%lx:%lx:%lx",
1206 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1207 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1208 for (i = 0; i < NCCS; ++i)
1209 printf(":%x", (unsigned int) mode->c_cc[i]);
1210 putchar('\n');
1211}
1212
1213static int recover_mode(char *arg, struct termios *mode)
1214{
1215 int i, n;
1216 unsigned int chr;
1217 unsigned long iflag, oflag, cflag, lflag;
1218
1219 /* Scan into temporaries since it is too much trouble to figure out
1220 the right format for `tcflag_t'. */
1221 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1222 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1223 return 0;
1224 mode->c_iflag = iflag;
1225 mode->c_oflag = oflag;
1226 mode->c_cflag = cflag;
1227 mode->c_lflag = lflag;
1228 arg += n;
1229 for (i = 0; i < NCCS; ++i) {
1230 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1231 return 0;
1232 mode->c_cc[i] = chr;
1233 arg += n;
1234 }
1235
1236 /* Fail if there are too many fields. */
1237 if (*arg != '\0')
1238 return 0;
1239
1240 return 1;
1241}
1242
1243struct speed_map {
1244 speed_t speed; /* Internal form. */
1245 unsigned long value; /* Numeric value. */
1246};
1247
1248static const struct speed_map speeds[] = {
1249 {B0, 0},
1250 {B50, 50},
1251 {B75, 75},
1252 {B110, 110},
1253 {B134, 134},
1254 {B150, 150},
1255 {B200, 200},
1256 {B300, 300},
1257 {B600, 600},
1258 {B1200, 1200},
1259 {B1800, 1800},
1260 {B2400, 2400},
1261 {B4800, 4800},
1262 {B9600, 9600},
1263 {B19200, 19200},
1264 {B38400, 38400},
1265#ifdef B57600
1266 {B57600, 57600},
1267#endif
1268#ifdef B115200
1269 {B115200, 115200},
1270#endif
1271#ifdef B230400
1272 {B230400, 230400},
1273#endif
1274#ifdef B460800
1275 {B460800, 460800},
1276#endif
1277};
1278
1279static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
1280
1281static speed_t string_to_baud(const char *arg)
1282{
1283 int i;
1284
1285 for (i = 0; i < NUM_SPEEDS; ++i)
1286 if (parse_number(arg, 0) == speeds[i].value)
1287 return speeds[i].speed;
1288 return (speed_t) - 1;
1289}
1290
1291static unsigned long baud_to_value(speed_t speed)
1292{
1293 int i;
1294
1295 for (i = 0; i < NUM_SPEEDS; ++i)
1296 if (speed == speeds[i].speed)
1297 return speeds[i].value;
1298 return 0;
1299}
1300
1301static void sane_mode(struct termios *mode)
1302{
1303 int i;
1304 tcflag_t *bitsp;
1305
1306 for (i = 0; i < NUM_control_info; ++i) {
1307#if VMIN == VEOF
1308 if (control_info[i].name == stty_min)
1309 break;
1310#endif
1311 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1312 }
1313
1314 for (i = 0; i < NUM_mode_info; ++i) {
1315 if (mode_info[i].flags & SANE_SET) {
1316 bitsp = mode_type_flag(mode_info[i].type, mode);
1317 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1318 } else if (mode_info[i].flags & SANE_UNSET) {
1319 bitsp = mode_type_flag(mode_info[i].type, mode);
1320 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1321 }
1322 }
1323}
1324
1325/* Return a string that is the printable representation of character CH. */
1326/* Adapted from `cat' by Torbjorn Granlund. */
1327
1328static const char *visible(unsigned int ch)
1329{
1330 static char buf[10];
1331 char *bpout = buf;
1332
1333 if (ch == _POSIX_VDISABLE)
1334 return "<undef>";
1335
1336 if (ch >= 32) {
1337 if (ch < 127)
1338 *bpout++ = ch;
1339 else if (ch == 127) {
1340 *bpout++ = '^';
1341 *bpout++ = '?';
1342 } else {
1343 *bpout++ = 'M', *bpout++ = '-';
1344 if (ch >= 128 + 32) {
1345 if (ch < 128 + 127)
1346 *bpout++ = ch - 128;
1347 else {
1348 *bpout++ = '^';
1349 *bpout++ = '?';
1350 }
1351 } else {
1352 *bpout++ = '^';
1353 *bpout++ = ch - 128 + 64;
1354 }
1355 }
1356 } else {
1357 *bpout++ = '^';
1358 *bpout++ = ch + 64;
1359 }
1360 *bpout = '\0';
1361 return (const char *) buf;
1362}
1363
1364#ifdef TEST
1365
1366const char *applet_name = "stty";
1367
1368#endif
1369
1370/*
1371Local Variables:
1372c-file-style: "linux"
1373c-basic-offset: 4
1374tab-width: 4
1375End:
1376*/
diff --git a/swaponoff.c b/swaponoff.c
deleted file mode 100644
index d9eb5baae..000000000
--- a/swaponoff.c
+++ /dev/null
@@ -1,115 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini swapon/swapoff implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <mntent.h>
27#include <dirent.h>
28#include <errno.h>
29#include <string.h>
30#include <stdlib.h>
31#include <sys/mount.h>
32
33#if __GNU_LIBRARY__ < 5
34/* libc5 doesn't have sys/swap.h, define these here. */
35extern int swapon (__const char *__path, int __flags);
36extern int swapoff (__const char *__path);
37#else
38#include <sys/swap.h>
39#endif
40
41#include "busybox.h"
42
43static int whichApp;
44
45static const int SWAPON_APP = 1;
46static const int SWAPOFF_APP = 2;
47
48
49static void swap_enable_disable(char *device)
50{
51 int status;
52
53 if (whichApp == SWAPON_APP)
54 status = swapon(device, 0);
55 else
56 status = swapoff(device);
57
58 if (status != 0)
59 perror_msg_and_die(applet_name);
60}
61
62static void do_em_all(void)
63{
64 struct mntent *m;
65 FILE *f = setmntent("/etc/fstab", "r");
66
67 if (f == NULL)
68 perror_msg_and_die("/etc/fstab");
69 while ((m = getmntent(f)) != NULL) {
70 if (strcmp(m->mnt_type, MNTTYPE_SWAP)==0) {
71 swap_enable_disable(m->mnt_fsname);
72 }
73 }
74 endmntent(f);
75 exit(EXIT_SUCCESS);
76}
77
78
79extern int swap_on_off_main(int argc, char **argv)
80{
81 if (strcmp(applet_name, "swapon") == 0) {
82 whichApp = SWAPON_APP;
83 } else {
84 whichApp = SWAPOFF_APP;
85 }
86
87 if (argc != 2) {
88 goto usage_and_exit;
89 }
90 argc--;
91 argv++;
92
93 /* Parse any options */
94 while (**argv == '-') {
95 while (*++(*argv))
96 switch (**argv) {
97 case 'a':
98 {
99 struct stat statBuf;
100
101 if (stat("/etc/fstab", &statBuf) < 0)
102 error_msg_and_die("/etc/fstab file missing");
103 }
104 do_em_all();
105 break;
106 default:
107 goto usage_and_exit;
108 }
109 }
110 swap_enable_disable(*argv);
111 return EXIT_SUCCESS;
112
113 usage_and_exit:
114 show_usage();
115}
diff --git a/sync.c b/sync.c
deleted file mode 100644
index ee22ae109..000000000
--- a/sync.c
+++ /dev/null
@@ -1,35 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini sync implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include "busybox.h"
28
29extern int sync_main(int argc, char **argv)
30{
31 if (argc > 1 && **(argv + 1) == '-')
32 show_usage();
33 sync();
34 return(EXIT_SUCCESS);
35}
diff --git a/sysdeps/linux/config.in b/sysdeps/linux/config.in
new file mode 100644
index 000000000..c4191d65f
--- /dev/null
+++ b/sysdeps/linux/config.in
@@ -0,0 +1,23 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5mainmenu_name "BusyBox Configuration"
6
7
8source archival/config.in
9source console-tools/config.in
10source editors/config.in
11source fileutils/config.in
12source findutils/config.in
13source init/config.in
14source miscutils/config.in
15source modutils/config.in
16source networking/config.in
17source procps/config.in
18source shell/config.in
19source shellutils/config.in
20source sysklogd/config.in
21source textutils/config.in
22source util-linux/config.in
23
diff --git a/sysdeps/linux/defconfig b/sysdeps/linux/defconfig
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/sysdeps/linux/defconfig
diff --git a/sysklogd/Makefile b/sysklogd/Makefile
new file mode 100644
index 000000000..3bfe90324
--- /dev/null
+++ b/sysklogd/Makefile
@@ -0,0 +1,38 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := sysklogd.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27
28obj-$(CONFIG_KLOGD) += klogd.o
29obj-$(CONFIG_LOGGER) += logger.o
30obj-$(CONFIG_LOGREAD) += logread.o
31obj-$(CONFIG_SYSLOGD) += syslogd.o
32
33# Hand off to toplevel Rules.mak
34include $(TOPDIR)/Rules.mak
35
36clean:
37 rm -f $(L_TARGET) *.o core
38
diff --git a/sysklogd/config.in b/sysklogd/config.in
new file mode 100644
index 000000000..8a8e42086
--- /dev/null
+++ b/sysklogd/config.in
@@ -0,0 +1,16 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'System Logging Utilities'
8
9bool 'klogd' CONFIG_KLOGD
10bool 'logger' CONFIG_LOGGER
11bool 'logread' CONFIG_LOGREAD
12bool 'syslogd' CONFIG_SYSLOGD
13
14
15endmenu
16
diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c
index d7b54e9c8..33bc783fe 100644
--- a/sysklogd/klogd.c
+++ b/sysklogd/klogd.c
@@ -6,8 +6,8 @@
6 * Changes: Made this a standalone busybox module which uses standalone 6 * Changes: Made this a standalone busybox module which uses standalone
7 * syslog() client interface. 7 * syslog() client interface.
8 * 8 *
9 * Copyright (C) 1999,2000,2001 by Lineo, inc. 9 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
10 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 10 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
11 * 11 *
12 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org> 12 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
13 * 13 *
diff --git a/sysklogd/logger.c b/sysklogd/logger.c
index 9f730915f..380bde5ca 100644
--- a/sysklogd/logger.c
+++ b/sysklogd/logger.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini logger implementation for busybox 3 * Mini logger implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@
30#include <stdlib.h> 30#include <stdlib.h>
31 31
32#include "busybox.h" 32#include "busybox.h"
33#if !defined BB_SYSLOGD 33#if !defined CONFIG_SYSLOGD
34 34
35#define SYSLOG_NAMES 35#define SYSLOG_NAMES
36#include <sys/syslog.h> 36#include <sys/syslog.h>
diff --git a/sysklogd/logread.c b/sysklogd/logread.c
index d3349625c..13ff1aeb9 100644
--- a/sysklogd/logread.c
+++ b/sysklogd/logread.c
@@ -38,7 +38,7 @@
38#if __GNU_LIBRARY__ < 5 38#if __GNU_LIBRARY__ < 5
39#error Sorry. Looks like you are using libc5. 39#error Sorry. Looks like you are using libc5.
40#error libc5 shm support isnt good enough. 40#error libc5 shm support isnt good enough.
41#error Please disable BB_FEATURE_IPC_SYSLOG 41#error Please disable CONFIG_FEATURE_IPC_SYSLOG
42#endif 42#endif
43 43
44 44
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index 25bc68f20..db6401c52 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -2,8 +2,8 @@
2/* 2/*
3 * Mini syslogd implementation for busybox 3 * Mini syslogd implementation for busybox
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * 7 *
8 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org> 8 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
9 * 9 *
@@ -65,7 +65,7 @@ static int MarkInterval = 20 * 60;
65/* localhost's name */ 65/* localhost's name */
66static char LocalHostName[32]; 66static char LocalHostName[32];
67 67
68#ifdef BB_FEATURE_REMOTE_LOG 68#ifdef CONFIG_FEATURE_REMOTE_LOG
69#include <netinet/in.h> 69#include <netinet/in.h>
70/* udp socket for logging to remote host */ 70/* udp socket for logging to remote host */
71static int remotefd = -1; 71static int remotefd = -1;
@@ -79,7 +79,7 @@ static int local_logging = FALSE;
79#endif 79#endif
80 80
81/* circular buffer variables/structures */ 81/* circular buffer variables/structures */
82#ifdef BB_FEATURE_IPC_SYSLOG 82#ifdef CONFIG_FEATURE_IPC_SYSLOG
83 83
84#include <sys/ipc.h> 84#include <sys/ipc.h>
85#include <sys/sem.h> 85#include <sys/sem.h>
@@ -269,7 +269,7 @@ static void message (char *fmt, ...)
269 fl.l_start = 0; 269 fl.l_start = 0;
270 fl.l_len = 1; 270 fl.l_len = 1;
271 271
272#ifdef BB_FEATURE_IPC_SYSLOG 272#ifdef CONFIG_FEATURE_IPC_SYSLOG
273 if ((circular_logging == TRUE) && (buf != NULL)){ 273 if ((circular_logging == TRUE) && (buf != NULL)){
274 char b[1024]; 274 char b[1024];
275 va_start (arguments, fmt); 275 va_start (arguments, fmt);
@@ -339,7 +339,7 @@ static void logMessage (int pri, char *msg)
339 339
340 /* todo: supress duplicates */ 340 /* todo: supress duplicates */
341 341
342#ifdef BB_FEATURE_REMOTE_LOG 342#ifdef CONFIG_FEATURE_REMOTE_LOG
343 /* send message to remote logger */ 343 /* send message to remote logger */
344 if ( -1 != remotefd){ 344 if ( -1 != remotefd){
345static const int IOV_COUNT = 2; 345static const int IOV_COUNT = 2;
@@ -372,7 +372,7 @@ static void quit_signal(int sig)
372{ 372{
373 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting."); 373 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
374 unlink(lfile); 374 unlink(lfile);
375#ifdef BB_FEATURE_IPC_SYSLOG 375#ifdef CONFIG_FEATURE_IPC_SYSLOG
376 ipcsyslog_cleanup(); 376 ipcsyslog_cleanup();
377#endif 377#endif
378 378
@@ -392,7 +392,7 @@ static void domark(int sig)
392#define BUFSIZE 1023 392#define BUFSIZE 1023
393static int serveConnection (int conn) 393static int serveConnection (int conn)
394{ 394{
395 RESERVE_BB_BUFFER(tmpbuf, BUFSIZE + 1); 395 RESERVE_CONFIG_BUFFER(tmpbuf, BUFSIZE + 1);
396 int n_read; 396 int n_read;
397 char *p = tmpbuf; 397 char *p = tmpbuf;
398 398
@@ -433,12 +433,12 @@ static int serveConnection (int conn)
433 /* Now log it */ 433 /* Now log it */
434 logMessage (pri, line); 434 logMessage (pri, line);
435 } 435 }
436 RELEASE_BB_BUFFER (tmpbuf); 436 RELEASE_CONFIG_BUFFER (tmpbuf);
437 return n_read; 437 return n_read;
438} 438}
439 439
440 440
441#ifdef BB_FEATURE_REMOTE_LOG 441#ifdef CONFIG_FEATURE_REMOTE_LOG
442static void init_RemoteLog (void){ 442static void init_RemoteLog (void){
443 443
444 struct sockaddr_in remoteaddr; 444 struct sockaddr_in remoteaddr;
@@ -512,13 +512,13 @@ static void doSyslogd (void)
512 FD_ZERO (&fds); 512 FD_ZERO (&fds);
513 FD_SET (sock_fd, &fds); 513 FD_SET (sock_fd, &fds);
514 514
515#ifdef BB_FEATURE_IPC_SYSLOG 515#ifdef CONFIG_FEATURE_IPC_SYSLOG
516 if (circular_logging == TRUE ){ 516 if (circular_logging == TRUE ){
517 ipcsyslog_init(); 517 ipcsyslog_init();
518 } 518 }
519#endif 519#endif
520 520
521 #ifdef BB_FEATURE_REMOTE_LOG 521 #ifdef CONFIG_FEATURE_REMOTE_LOG
522 if (doRemoteLog == TRUE){ 522 if (doRemoteLog == TRUE){
523 init_RemoteLog(); 523 init_RemoteLog();
524 } 524 }
@@ -585,7 +585,7 @@ extern int syslogd_main(int argc, char **argv)
585 case 'O': 585 case 'O':
586 logFilePath = strdup(optarg); 586 logFilePath = strdup(optarg);
587 break; 587 break;
588#ifdef BB_FEATURE_REMOTE_LOG 588#ifdef CONFIG_FEATURE_REMOTE_LOG
589 case 'R': 589 case 'R':
590 RemoteHost = strdup(optarg); 590 RemoteHost = strdup(optarg);
591 if ( (p = strchr(RemoteHost, ':'))){ 591 if ( (p = strchr(RemoteHost, ':'))){
@@ -598,7 +598,7 @@ extern int syslogd_main(int argc, char **argv)
598 local_logging = TRUE; 598 local_logging = TRUE;
599 break; 599 break;
600#endif 600#endif
601#ifdef BB_FEATURE_IPC_SYSLOG 601#ifdef CONFIG_FEATURE_IPC_SYSLOG
602 case 'C': 602 case 'C':
603 circular_logging = TRUE; 603 circular_logging = TRUE;
604 break; 604 break;
@@ -608,7 +608,7 @@ extern int syslogd_main(int argc, char **argv)
608 } 608 }
609 } 609 }
610 610
611#ifdef BB_FEATURE_REMOTE_LOG 611#ifdef CONFIG_FEATURE_REMOTE_LOG
612 /* If they have not specified remote logging, then log locally */ 612 /* If they have not specified remote logging, then log locally */
613 if (doRemoteLog == FALSE) 613 if (doRemoteLog == FALSE)
614 local_logging = TRUE; 614 local_logging = TRUE;
diff --git a/syslogd.c b/syslogd.c
deleted file mode 100644
index 25bc68f20..000000000
--- a/syslogd.c
+++ /dev/null
@@ -1,641 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini syslogd implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
9 *
10 * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>
11 *
12 * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <ctype.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <netdb.h>
36#include <paths.h>
37#include <signal.h>
38#include <stdarg.h>
39#include <time.h>
40#include <string.h>
41#include <unistd.h>
42#include <sys/socket.h>
43#include <sys/types.h>
44#include <sys/un.h>
45#include <sys/param.h>
46
47#include "busybox.h"
48
49/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
50#define SYSLOG_NAMES
51#include <sys/syslog.h>
52#include <sys/uio.h>
53
54/* Path for the file where all log messages are written */
55#define __LOG_FILE "/var/log/messages"
56
57/* Path to the unix socket */
58static char lfile[BUFSIZ];
59
60static char *logFilePath = __LOG_FILE;
61
62/* interval between marks in seconds */
63static int MarkInterval = 20 * 60;
64
65/* localhost's name */
66static char LocalHostName[32];
67
68#ifdef BB_FEATURE_REMOTE_LOG
69#include <netinet/in.h>
70/* udp socket for logging to remote host */
71static int remotefd = -1;
72/* where do we log? */
73static char *RemoteHost;
74/* what port to log to? */
75static int RemotePort = 514;
76/* To remote log or not to remote log, that is the question. */
77static int doRemoteLog = FALSE;
78static int local_logging = FALSE;
79#endif
80
81/* circular buffer variables/structures */
82#ifdef BB_FEATURE_IPC_SYSLOG
83
84#include <sys/ipc.h>
85#include <sys/sem.h>
86#include <sys/shm.h>
87
88/* our shared key */
89static const long KEY_ID = 0x414e4547; /*"GENA"*/
90
91// Semaphore operation structures
92static struct shbuf_ds {
93 int size; // size of data written
94 int head; // start of message list
95 int tail; // end of message list
96 char data[1]; // data/messages
97} *buf = NULL; // shared memory pointer
98
99static struct sembuf SMwup[1] = {{1, -1, IPC_NOWAIT}}; // set SMwup
100static struct sembuf SMwdn[3] = {{0, 0}, {1, 0}, {1, +1}}; // set SMwdn
101
102static int shmid = -1; // ipc shared memory id
103static int s_semid = -1; // ipc semaphore id
104int data_size = 16000; // data size
105int shm_size = 16000 + sizeof(*buf); // our buffer size
106static int circular_logging = FALSE;
107
108/*
109 * sem_up - up()'s a semaphore.
110 */
111static inline void sem_up(int semid)
112{
113 if ( semop(semid, SMwup, 1) == -1 )
114 perror_msg_and_die("semop[SMwup]");
115}
116
117/*
118 * sem_down - down()'s a semaphore
119 */
120static inline void sem_down(int semid)
121{
122 if ( semop(semid, SMwdn, 3) == -1 )
123 perror_msg_and_die("semop[SMwdn]");
124}
125
126
127void ipcsyslog_cleanup(void){
128 printf("Exiting Syslogd!\n");
129 if (shmid != -1)
130 shmdt(buf);
131
132 if (shmid != -1)
133 shmctl(shmid, IPC_RMID, NULL);
134 if (s_semid != -1)
135 semctl(s_semid, 0, IPC_RMID, 0);
136}
137
138void ipcsyslog_init(void){
139 if (buf == NULL){
140 if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1)
141 perror_msg_and_die("shmget");
142
143
144 if ((buf = shmat(shmid, NULL, 0)) == NULL)
145 perror_msg_and_die("shmat");
146
147
148 buf->size=data_size;
149 buf->head=buf->tail=0;
150
151 // we'll trust the OS to set initial semval to 0 (let's hope)
152 if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1){
153 if (errno == EEXIST){
154 if ((s_semid = semget(KEY_ID, 2, 0)) == -1)
155 perror_msg_and_die("semget");
156 }else
157 perror_msg_and_die("semget");
158 }
159 }else{
160 printf("Buffer already allocated just grab the semaphore?");
161 }
162}
163
164/* write message to buffer */
165void circ_message(const char *msg){
166 int l=strlen(msg)+1; /* count the whole message w/ '\0' included */
167
168 sem_down(s_semid);
169
170 /*
171 * Circular Buffer Algorithm:
172 * --------------------------
173 *
174 * Start-off w/ empty buffer of specific size SHM_SIZ
175 * Start filling it up w/ messages. I use '\0' as separator to break up messages.
176 * This is also very handy since we can do printf on message.
177 *
178 * Once the buffer is full we need to get rid of the first message in buffer and
179 * insert the new message. (Note: if the message being added is >1 message then
180 * we will need to "remove" >1 old message from the buffer). The way this is done
181 * is the following:
182 * When we reach the end of the buffer we set a mark and start from the beginning.
183 * Now what about the beginning and end of the buffer? Well we have the "head"
184 * index/pointer which is the starting point for the messages and we have "tail"
185 * index/pointer which is the ending point for the messages. When we "display" the
186 * messages we start from the beginning and continue until we reach "tail". If we
187 * reach end of buffer, then we just start from the beginning (offset 0). "head" and
188 * "tail" are actually offsets from the beginning of the buffer.
189 *
190 * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
191 * a threasafe way of handling shared memory operations.
192 */
193 if ( (buf->tail + l) < buf->size ){
194 /* before we append the message we need to check the HEAD so that we won't
195 overwrite any of the message that we still need and adjust HEAD to point
196 to the next message! */
197 if ( buf->tail < buf->head){
198 if ( (buf->tail + l) >= buf->head ){
199 /* we need to move the HEAD to point to the next message
200 * Theoretically we have enough room to add the whole message to the
201 * buffer, because of the first outer IF statement, so we don't have
202 * to worry about overflows here!
203 */
204 int k= buf->tail + l - buf->head; /* we need to know how many bytes
205 we are overwriting to make
206 enough room */
207 char *c=memchr(buf->data+buf->head + k,'\0',buf->size - (buf->head + k));
208 if (c != NULL) {/* do a sanity check just in case! */
209 buf->head = c - buf->data + 1; /* we need to convert pointer to
210 offset + skip the '\0' since
211 we need to point to the beginning
212 of the next message */
213 /* Note: HEAD is only used to "retrieve" messages, it's not used
214 when writing messages into our buffer */
215 }else{ /* show an error message to know we messed up? */
216 printf("Weird! Can't find the terminator token??? \n");
217 buf->head=0;
218 }
219 }
220 } /* in other cases no overflows have been done yet, so we don't care! */
221
222 /* we should be ok to append the message now */
223 strncpy(buf->data + buf->tail,msg,l); /* append our message */
224 buf->tail+=l; /* count full message w/ '\0' terminating char */
225 }else{
226 /* we need to break up the message and "circle" it around */
227 char *c;
228 int k=buf->tail + l - buf->size; /* count # of bytes we don't fit */
229
230 /* We need to move HEAD! This is always the case since we are going
231 * to "circle" the message.
232 */
233 c=memchr(buf->data + k ,'\0', buf->size - k);
234
235 if (c != NULL) /* if we don't have '\0'??? weird!!! */{
236 /* move head pointer*/
237 buf->head=c-buf->data+1;
238
239 /* now write the first part of the message */
240 strncpy(buf->data + buf->tail, msg, l - k - 1);
241
242 /* ALWAYS terminate end of buffer w/ '\0' */
243 buf->data[buf->size-1]='\0';
244
245 /* now write out the rest of the string to the beginning of the buffer */
246 strcpy(buf->data, &msg[l-k-1]);
247
248 /* we need to place the TAIL at the end of the message */
249 buf->tail = k + 1;
250 }else{
251 printf("Weird! Can't find the terminator token from the beginning??? \n");
252 buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
253 }
254
255 }
256 sem_up(s_semid);
257}
258#endif
259/* Note: There is also a function called "message()" in init.c */
260/* Print a message to the log file. */
261static void message (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
262static void message (char *fmt, ...)
263{
264 int fd;
265 struct flock fl;
266 va_list arguments;
267
268 fl.l_whence = SEEK_SET;
269 fl.l_start = 0;
270 fl.l_len = 1;
271
272#ifdef BB_FEATURE_IPC_SYSLOG
273 if ((circular_logging == TRUE) && (buf != NULL)){
274 char b[1024];
275 va_start (arguments, fmt);
276 vsprintf (b, fmt, arguments);
277 va_end (arguments);
278 circ_message(b);
279
280 }else
281#endif
282 if ((fd = device_open (logFilePath,
283 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
284 O_NONBLOCK)) >= 0) {
285 fl.l_type = F_WRLCK;
286 fcntl (fd, F_SETLKW, &fl);
287 va_start (arguments, fmt);
288 vdprintf (fd, fmt, arguments);
289 va_end (arguments);
290 fl.l_type = F_UNLCK;
291 fcntl (fd, F_SETLKW, &fl);
292 close (fd);
293 } else {
294 /* Always send console messages to /dev/console so people will see them. */
295 if ((fd = device_open (_PATH_CONSOLE,
296 O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
297 va_start (arguments, fmt);
298 vdprintf (fd, fmt, arguments);
299 va_end (arguments);
300 close (fd);
301 } else {
302 fprintf (stderr, "Bummer, can't print: ");
303 va_start (arguments, fmt);
304 vfprintf (stderr, fmt, arguments);
305 fflush (stderr);
306 va_end (arguments);
307 }
308 }
309}
310
311static void logMessage (int pri, char *msg)
312{
313 time_t now;
314 char *timestamp;
315 static char res[20] = "";
316 CODE *c_pri, *c_fac;
317
318 if (pri != 0) {
319 for (c_fac = facilitynames;
320 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
321 for (c_pri = prioritynames;
322 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
323 if (c_fac->c_name == NULL || c_pri->c_name == NULL)
324 snprintf(res, sizeof(res), "<%d>", pri);
325 else
326 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
327 }
328
329 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
330 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
331 time(&now);
332 timestamp = ctime(&now) + 4;
333 timestamp[15] = '\0';
334 } else {
335 timestamp = msg;
336 timestamp[15] = '\0';
337 msg += 16;
338 }
339
340 /* todo: supress duplicates */
341
342#ifdef BB_FEATURE_REMOTE_LOG
343 /* send message to remote logger */
344 if ( -1 != remotefd){
345static const int IOV_COUNT = 2;
346 struct iovec iov[IOV_COUNT];
347 struct iovec *v = iov;
348
349 memset(&res, 0, sizeof(res));
350 snprintf(res, sizeof(res), "<%d>", pri);
351 v->iov_base = res ;
352 v->iov_len = strlen(res);
353 v++;
354
355 v->iov_base = msg;
356 v->iov_len = strlen(msg);
357
358 if ( -1 == writev(remotefd,iov, IOV_COUNT)){
359 error_msg_and_die("syslogd: cannot write to remote file handle on"
360 "%s:%d",RemoteHost,RemotePort);
361 }
362 }
363 if (local_logging == TRUE)
364#endif
365 /* now spew out the message to wherever it is supposed to go */
366 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
367
368
369}
370
371static void quit_signal(int sig)
372{
373 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
374 unlink(lfile);
375#ifdef BB_FEATURE_IPC_SYSLOG
376 ipcsyslog_cleanup();
377#endif
378
379 exit(TRUE);
380}
381
382static void domark(int sig)
383{
384 if (MarkInterval > 0) {
385 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
386 alarm(MarkInterval);
387 }
388}
389
390/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
391 * enabled, we otherwise get a "storage size isn't constant error. */
392#define BUFSIZE 1023
393static int serveConnection (int conn)
394{
395 RESERVE_BB_BUFFER(tmpbuf, BUFSIZE + 1);
396 int n_read;
397 char *p = tmpbuf;
398
399 n_read = read (conn, tmpbuf, BUFSIZE );
400
401 while (p < tmpbuf + n_read) {
402
403 int pri = (LOG_USER | LOG_NOTICE);
404 char line[ BUFSIZE + 1 ];
405 unsigned char c;
406
407 char *q = line;
408
409 tmpbuf[ n_read - 1 ] = '\0';
410
411 while (p && (c = *p) && q < &line[ sizeof (line) - 1 ]) {
412 if (c == '<') {
413 /* Parse the magic priority number. */
414 pri = 0;
415 while (isdigit (*(++p))) {
416 pri = 10 * pri + (*p - '0');
417 }
418 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)){
419 pri = (LOG_USER | LOG_NOTICE);
420 }
421 } else if (c == '\n') {
422 *q++ = ' ';
423 } else if (iscntrl (c) && (c < 0177)) {
424 *q++ = '^';
425 *q++ = c ^ 0100;
426 } else {
427 *q++ = c;
428 }
429 p++;
430 }
431 *q = '\0';
432 p++;
433 /* Now log it */
434 logMessage (pri, line);
435 }
436 RELEASE_BB_BUFFER (tmpbuf);
437 return n_read;
438}
439
440
441#ifdef BB_FEATURE_REMOTE_LOG
442static void init_RemoteLog (void){
443
444 struct sockaddr_in remoteaddr;
445 struct hostent *hostinfo;
446 int len = sizeof(remoteaddr);
447
448 memset(&remoteaddr, 0, len);
449
450 remotefd = socket(AF_INET, SOCK_DGRAM, 0);
451
452 if (remotefd < 0) {
453 error_msg_and_die("syslogd: cannot create socket");
454 }
455
456 hostinfo = xgethostbyname(RemoteHost);
457
458 remoteaddr.sin_family = AF_INET;
459 remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
460 remoteaddr.sin_port = htons(RemotePort);
461
462 /*
463 Since we are using UDP sockets, connect just sets the default host and port
464 for future operations
465 */
466 if ( 0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))){
467 error_msg_and_die("syslogd: cannot connect to remote host %s:%d", RemoteHost, RemotePort);
468 }
469
470}
471#endif
472
473static void doSyslogd (void) __attribute__ ((noreturn));
474static void doSyslogd (void)
475{
476 struct sockaddr_un sunx;
477 socklen_t addrLength;
478
479
480 int sock_fd;
481 fd_set fds;
482
483 /* Set up signal handlers. */
484 signal (SIGINT, quit_signal);
485 signal (SIGTERM, quit_signal);
486 signal (SIGQUIT, quit_signal);
487 signal (SIGHUP, SIG_IGN);
488 signal (SIGCHLD, SIG_IGN);
489#ifdef SIGCLD
490 signal (SIGCLD, SIG_IGN);
491#endif
492 signal (SIGALRM, domark);
493 alarm (MarkInterval);
494
495 /* Create the syslog file so realpath() can work. */
496 if (realpath (_PATH_LOG, lfile) != NULL)
497 unlink (lfile);
498
499 memset (&sunx, 0, sizeof (sunx));
500 sunx.sun_family = AF_UNIX;
501 strncpy (sunx.sun_path, lfile, sizeof (sunx.sun_path));
502 if ((sock_fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
503 perror_msg_and_die ("Couldn't get file descriptor for socket " _PATH_LOG);
504
505 addrLength = sizeof (sunx.sun_family) + strlen (sunx.sun_path);
506 if ((bind (sock_fd, (struct sockaddr *) &sunx, addrLength)) || (listen (sock_fd, 5)))
507 perror_msg_and_die ("Could not connect to socket " _PATH_LOG);
508
509 if (chmod (lfile, 0666) < 0)
510 perror_msg_and_die ("Could not set permission on " _PATH_LOG);
511
512 FD_ZERO (&fds);
513 FD_SET (sock_fd, &fds);
514
515#ifdef BB_FEATURE_IPC_SYSLOG
516 if (circular_logging == TRUE ){
517 ipcsyslog_init();
518 }
519#endif
520
521 #ifdef BB_FEATURE_REMOTE_LOG
522 if (doRemoteLog == TRUE){
523 init_RemoteLog();
524 }
525 #endif
526
527 logMessage (LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
528
529 for (;;) {
530
531 fd_set readfds;
532 int n_ready;
533 int fd;
534
535 memcpy (&readfds, &fds, sizeof (fds));
536
537 if ((n_ready = select (FD_SETSIZE, &readfds, NULL, NULL, NULL)) < 0) {
538 if (errno == EINTR) continue; /* alarm may have happened. */
539 perror_msg_and_die ("select error");
540 }
541
542 for (fd = 0; (n_ready > 0) && (fd < FD_SETSIZE); fd++) {
543 if (FD_ISSET (fd, &readfds)) {
544
545 --n_ready;
546
547 if (fd == sock_fd) {
548 int conn;
549
550 //printf("New Connection request.\n");
551 if ((conn = accept (sock_fd, (struct sockaddr *) &sunx, &addrLength)) < 0) {
552 perror_msg_and_die ("accept error");
553 }
554
555 FD_SET(conn, &fds);
556 //printf("conn: %i, set_size: %i\n",conn,FD_SETSIZE);
557 } else {
558 //printf("Serving connection: %i\n",fd);
559 if ( serveConnection(fd) <= 0 ) {
560 close (fd);
561 FD_CLR(fd, &fds);
562 }
563 } /* fd == sock_fd */
564 }/* FD_ISSET() */
565 }/* for */
566 } /* for main loop */
567}
568
569extern int syslogd_main(int argc, char **argv)
570{
571 int opt;
572 int doFork = TRUE;
573
574 char *p;
575
576 /* do normal option parsing */
577 while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) {
578 switch (opt) {
579 case 'm':
580 MarkInterval = atoi(optarg) * 60;
581 break;
582 case 'n':
583 doFork = FALSE;
584 break;
585 case 'O':
586 logFilePath = strdup(optarg);
587 break;
588#ifdef BB_FEATURE_REMOTE_LOG
589 case 'R':
590 RemoteHost = strdup(optarg);
591 if ( (p = strchr(RemoteHost, ':'))){
592 RemotePort = atoi(p+1);
593 *p = '\0';
594 }
595 doRemoteLog = TRUE;
596 break;
597 case 'L':
598 local_logging = TRUE;
599 break;
600#endif
601#ifdef BB_FEATURE_IPC_SYSLOG
602 case 'C':
603 circular_logging = TRUE;
604 break;
605#endif
606 default:
607 show_usage();
608 }
609 }
610
611#ifdef BB_FEATURE_REMOTE_LOG
612 /* If they have not specified remote logging, then log locally */
613 if (doRemoteLog == FALSE)
614 local_logging = TRUE;
615#endif
616
617
618 /* Store away localhost's name before the fork */
619 gethostname(LocalHostName, sizeof(LocalHostName));
620 if ((p = strchr(LocalHostName, '.'))) {
621 *p++ = '\0';
622 }
623
624 umask(0);
625
626 if (doFork == TRUE) {
627 if (daemon(0, 1) < 0)
628 perror_msg_and_die("daemon");
629 }
630 doSyslogd();
631
632 return EXIT_SUCCESS;
633}
634
635/*
636Local Variables
637c-file-style: "linux"
638c-basic-offset: 4
639tab-width: 4
640End:
641*/
diff --git a/tail.c b/tail.c
deleted file mode 100644
index 5e5fbc14f..000000000
--- a/tail.c
+++ /dev/null
@@ -1,251 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini tail implementation for busybox
4 *
5 *
6 * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24
25#include <fcntl.h>
26#include <getopt.h>
27#include <string.h>
28#include <stdlib.h>
29#include <unistd.h>
30#include <sys/types.h>
31#include "busybox.h"
32
33static const struct suffix_mult tail_suffixes[] = {
34 { "b", 512 },
35 { "k", 1024 },
36 { "m", 1048576 },
37 { NULL, 0 }
38};
39
40static const int BYTES = 0;
41static const int LINES = 1;
42
43static char *tailbuf;
44static int taillen;
45static int newline;
46
47static void tailbuf_append(char *buf, int len)
48{
49 tailbuf = xrealloc(tailbuf, taillen + len);
50 memcpy(tailbuf + taillen, buf, len);
51 taillen += len;
52}
53
54static void tailbuf_trunc(void)
55{
56 char *s;
57 s = memchr(tailbuf, '\n', taillen);
58 memmove(tailbuf, s + 1, taillen - ((s + 1) - tailbuf));
59 taillen -= (s + 1) - tailbuf;
60 newline = 0;
61}
62
63int tail_main(int argc, char **argv)
64{
65 int from_top = 0, units = LINES, count = 10, sleep_period = 1;
66 int show_headers = 0, hide_headers = 0, follow = 0;
67 int *fds, nfiles = 0, status = EXIT_SUCCESS, nread, nwrite, seen = 0;
68 char *s, *start, *end, buf[BUFSIZ];
69 int i, opt;
70
71 while ((opt = getopt(argc, argv, "c:fhn:q:s:v")) > 0) {
72 switch (opt) {
73 case 'f':
74 follow = 1;
75 break;
76#ifdef BB_FEATURE_FANCY_TAIL
77 case 'c':
78 units = BYTES;
79 /* FALLS THROUGH */
80#endif
81 case 'n':
82 count = parse_number(optarg, tail_suffixes);
83 if (count < 0)
84 count = -count;
85 if (optarg[0] == '+')
86 from_top = 1;
87 break;
88#ifdef BB_FEATURE_FANCY_TAIL
89 case 'q':
90 hide_headers = 1;
91 break;
92 case 's':
93 sleep_period = parse_number(optarg, 0);
94 break;
95 case 'v':
96 show_headers = 1;
97 break;
98#endif
99 default:
100 show_usage();
101 }
102 }
103
104 /* open all the files */
105 fds = (int *)xmalloc(sizeof(int) * (argc - optind + 1));
106 if (argc == optind) {
107 fds[nfiles++] = STDIN_FILENO;
108 argv[optind] = "standard input";
109 } else {
110 for (i = optind; i < argc; i++) {
111 if (strcmp(argv[i], "-") == 0) {
112 fds[nfiles++] = STDIN_FILENO;
113 argv[i] = "standard input";
114 } else if ((fds[nfiles++] = open(argv[i], O_RDONLY)) < 0) {
115 perror_msg("%s", argv[i]);
116 status = EXIT_FAILURE;
117 }
118 }
119 }
120
121#ifdef BB_FEATURE_FANCY_TAIL
122 /* tail the files */
123 if (!from_top && units == BYTES)
124 tailbuf = xmalloc(count);
125#endif
126
127 for (i = 0; i < nfiles; i++) {
128 if (fds[i] == -1)
129 continue;
130 if (!count) {
131 lseek(fds[i], 0, SEEK_END);
132 continue;
133 }
134 seen = 0;
135 if (show_headers || (!hide_headers && nfiles > 1))
136 printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]);
137 while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) {
138 if (from_top) {
139#ifdef BB_FEATURE_FANCY_TAIL
140 if (units == BYTES) {
141 if (count - 1 <= seen)
142 nwrite = nread;
143 else if (count - 1 <= seen + nread)
144 nwrite = nread + seen - (count - 1);
145 else
146 nwrite = 0;
147 seen += nread;
148 } else {
149#else
150 {
151#endif
152 if (count - 1 <= seen)
153 nwrite = nread;
154 else {
155 nwrite = 0;
156 for (s = memchr(buf, '\n', nread); s != NULL;
157 s = memchr(s+1, '\n', nread - (s + 1 - buf))) {
158 if (count - 1 <= ++seen) {
159 nwrite = nread - (s + 1 - buf);
160 break;
161 }
162 }
163 }
164 }
165 if (full_write(STDOUT_FILENO, buf + nread - nwrite,
166 nwrite) < 0) {
167 perror_msg("write");
168 status = EXIT_FAILURE;
169 break;
170 }
171 } else {
172#ifdef BB_FEATURE_FANCY_TAIL
173 if (units == BYTES) {
174 if (nread < count) {
175 memmove(tailbuf, tailbuf + nread, count - nread);
176 memcpy(tailbuf + count - nread, buf, nread);
177 } else {
178 memcpy(tailbuf, buf + nread - count, count);
179 }
180 seen += nread;
181 } else {
182#else
183 {
184#endif
185 for (start = buf, end = memchr(buf, '\n', nread);
186 end != NULL; start = end+1,
187 end = memchr(start, '\n', nread - (start - buf))) {
188 if (newline && count <= seen)
189 tailbuf_trunc();
190 tailbuf_append(start, end - start + 1);
191 seen++;
192 newline = 1;
193 }
194 if (newline && count <= seen && nread - (start - buf) > 0)
195 tailbuf_trunc();
196 tailbuf_append(start, nread - (start - buf));
197 }
198 }
199 }
200
201 if (nread < 0) {
202 perror_msg("read");
203 status = EXIT_FAILURE;
204 }
205
206#ifdef BB_FEATURE_FANCY_TAIL
207 if (!from_top && units == BYTES) {
208 if (count < seen)
209 seen = count;
210 if (full_write(STDOUT_FILENO, tailbuf + count - seen, seen) < 0) {
211 perror_msg("write");
212 status = EXIT_FAILURE;
213 }
214 }
215#endif
216
217 if (!from_top && units == LINES) {
218 if (full_write(STDOUT_FILENO, tailbuf, taillen) < 0) {
219 perror_msg("write");
220 status = EXIT_FAILURE;
221 }
222 }
223
224 taillen = 0;
225 }
226
227 while (follow) {
228 sleep(sleep_period);
229
230 for (i = 0; i < nfiles; i++) {
231 if (fds[i] == -1)
232 continue;
233
234 if ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) {
235 if (show_headers || (!hide_headers && nfiles > 1))
236 printf("\n==> %s <==\n", argv[optind + i]);
237
238 do {
239 full_write(STDOUT_FILENO, buf, nread);
240 } while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0);
241 }
242
243 if (nread < 0) {
244 perror_msg("read");
245 status = EXIT_FAILURE;
246 }
247 }
248 }
249
250 return status;
251}
diff --git a/tar.c b/tar.c
deleted file mode 100644
index f7a3da66f..000000000
--- a/tar.c
+++ /dev/null
@@ -1,745 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini tar implementation for busybox
4 *
5 * Modifed to use common extraction code used by ar, cpio, dpkg-deb, dpkg
6 * Glenn McGrath <bug1@optushome.com.au>
7 *
8 * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
9 * ground up. It still has remnents of the old code lying about, but it is
10 * very different now (i.e., cleaner, less global variables, etc.)
11 *
12 * Copyright (C) 1999,2000,2001 by Lineo, inc.
13 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
14 *
15 * Based in part in the tar implementation in sash
16 * Copyright (c) 1999 by David I. Bell
17 * Permission is granted to use, distribute, or modify this source,
18 * provided that this copyright notice remains intact.
19 * Permission to distribute sash derived code under the GPL has been granted.
20 *
21 * Based in part on the tar implementation from busybox-0.28
22 * Copyright (C) 1995 Bruce Perens
23 * This is free software under the GNU General Public License.
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 2 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 * General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program; if not, write to the Free Software
37 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
38 *
39 */
40
41#include <fcntl.h>
42#include <getopt.h>
43#include <search.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <unistd.h>
47#include <fnmatch.h>
48#include <string.h>
49#include <errno.h>
50#include "busybox.h"
51
52#ifdef BB_FEATURE_TAR_CREATE
53
54/* Tar file constants */
55# define TAR_MAGIC "ustar" /* ustar and a null */
56# define TAR_VERSION " " /* Be compatable with GNU tar format */
57
58# ifndef MAJOR
59# define MAJOR(dev) (((dev)>>8)&0xff)
60# define MINOR(dev) ((dev)&0xff)
61# endif
62
63static const int TAR_BLOCK_SIZE = 512;
64static const int TAR_MAGIC_LEN = 6;
65static const int TAR_VERSION_LEN = 2;
66
67/* POSIX tar Header Block, from POSIX 1003.1-1990 */
68enum { NAME_SIZE = 100 }; /* because gcc won't let me use 'static const int' */
69struct TarHeader
70{ /* byte offset */
71 char name[NAME_SIZE]; /* 0-99 */
72 char mode[8]; /* 100-107 */
73 char uid[8]; /* 108-115 */
74 char gid[8]; /* 116-123 */
75 char size[12]; /* 124-135 */
76 char mtime[12]; /* 136-147 */
77 char chksum[8]; /* 148-155 */
78 char typeflag; /* 156-156 */
79 char linkname[NAME_SIZE]; /* 157-256 */
80 char magic[6]; /* 257-262 */
81 char version[2]; /* 263-264 */
82 char uname[32]; /* 265-296 */
83 char gname[32]; /* 297-328 */
84 char devmajor[8]; /* 329-336 */
85 char devminor[8]; /* 337-344 */
86 char prefix[155]; /* 345-499 */
87 char padding[12]; /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */
88};
89typedef struct TarHeader TarHeader;
90
91/*
92** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
93** the only functions that deal with the HardLinkInfo structure.
94** Even these functions use the xxxHardLinkInfo() functions.
95*/
96typedef struct HardLinkInfo HardLinkInfo;
97struct HardLinkInfo
98{
99 HardLinkInfo *next; /* Next entry in list */
100 dev_t dev; /* Device number */
101 ino_t ino; /* Inode number */
102 short linkCount; /* (Hard) Link Count */
103 char name[1]; /* Start of filename (must be last) */
104};
105
106/* Some info to be carried along when creating a new tarball */
107struct TarBallInfo
108{
109 char* fileName; /* File name of the tarball */
110 int tarFd; /* Open-for-write file descriptor
111 for the tarball */
112 struct stat statBuf; /* Stat info for the tarball, letting
113 us know the inode and device that the
114 tarball lives, so we can avoid trying
115 to include the tarball into itself */
116 int verboseFlag; /* Whether to print extra stuff or not */
117 char** excludeList; /* List of files to not include */
118 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
119 HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
120};
121typedef struct TarBallInfo TarBallInfo;
122
123/* A nice enum with all the possible tar file content types */
124enum TarFileType
125{
126 REGTYPE = '0', /* regular file */
127 REGTYPE0 = '\0', /* regular file (ancient bug compat)*/
128 LNKTYPE = '1', /* hard link */
129 SYMTYPE = '2', /* symbolic link */
130 CHRTYPE = '3', /* character special */
131 BLKTYPE = '4', /* block special */
132 DIRTYPE = '5', /* directory */
133 FIFOTYPE = '6', /* FIFO special */
134 CONTTYPE = '7', /* reserved */
135 GNULONGLINK = 'K', /* GNU long (>100 chars) link name */
136 GNULONGNAME = 'L', /* GNU long (>100 chars) file name */
137};
138typedef enum TarFileType TarFileType;
139
140/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
141static void
142addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino,
143 short linkCount, const char *name)
144{
145 /* Note: hlInfoHeadPtr can never be NULL! */
146 HardLinkInfo *hlInfo;
147
148 hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1);
149 if (hlInfo) {
150 hlInfo->next = *hlInfoHeadPtr;
151 *hlInfoHeadPtr = hlInfo;
152 hlInfo->dev = dev;
153 hlInfo->ino = ino;
154 hlInfo->linkCount = linkCount;
155 strcpy(hlInfo->name, name);
156 }
157 return;
158}
159
160static void
161freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr)
162{
163 HardLinkInfo *hlInfo = NULL;
164 HardLinkInfo *hlInfoNext = NULL;
165
166 if (hlInfoHeadPtr) {
167 hlInfo = *hlInfoHeadPtr;
168 while (hlInfo) {
169 hlInfoNext = hlInfo->next;
170 free(hlInfo);
171 hlInfo = hlInfoNext;
172 }
173 *hlInfoHeadPtr = NULL;
174 }
175 return;
176}
177
178/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
179static HardLinkInfo *
180findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino)
181{
182 while(hlInfo) {
183 if ((ino == hlInfo->ino) && (dev == hlInfo->dev))
184 break;
185 hlInfo = hlInfo->next;
186 }
187 return(hlInfo);
188}
189
190/* Put an octal string into the specified buffer.
191 * The number is zero and space padded and possibly null padded.
192 * Returns TRUE if successful. */
193static int putOctal (char *cp, int len, long value)
194{
195 int tempLength;
196 char tempBuffer[32];
197 char *tempString = tempBuffer;
198
199 /* Create a string of the specified length with an initial space,
200 * leading zeroes and the octal number, and a trailing null. */
201 sprintf (tempString, "%0*lo", len - 1, value);
202
203 /* If the string is too large, suppress the leading space. */
204 tempLength = strlen (tempString) + 1;
205 if (tempLength > len) {
206 tempLength--;
207 tempString++;
208 }
209
210 /* If the string is still too large, suppress the trailing null. */
211 if (tempLength > len)
212 tempLength--;
213
214 /* If the string is still too large, fail. */
215 if (tempLength > len)
216 return FALSE;
217
218 /* Copy the string to the field. */
219 memcpy (cp, tempString, len);
220
221 return TRUE;
222}
223
224/* Write out a tar header for the specified file/directory/whatever */
225static int
226writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name,
227 const char *real_name, struct stat *statbuf)
228{
229 long chksum=0;
230 struct TarHeader header;
231 const unsigned char *cp = (const unsigned char *) &header;
232 ssize_t size = sizeof(struct TarHeader);
233
234 memset( &header, 0, size);
235
236 strncpy(header.name, header_name, sizeof(header.name));
237
238 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
239 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
240 putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
241 putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */
242 putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
243 strncpy(header.magic, TAR_MAGIC TAR_VERSION,
244 TAR_MAGIC_LEN + TAR_VERSION_LEN );
245
246 /* Enter the user and group names (default to root if it fails) */
247 my_getpwuid(header.uname, statbuf->st_uid);
248 if (! *header.uname)
249 strcpy(header.uname, "root");
250 my_getgrgid(header.gname, statbuf->st_gid);
251 if (! *header.uname)
252 strcpy(header.uname, "root");
253
254 if (tbInfo->hlInfo) {
255 /* This is a hard link */
256 header.typeflag = LNKTYPE;
257 strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
258 } else if (S_ISLNK(statbuf->st_mode)) {
259 char *lpath = xreadlink(real_name);
260 if (!lpath) /* Already printed err msg inside xreadlink() */
261 return ( FALSE);
262 header.typeflag = SYMTYPE;
263 strncpy(header.linkname, lpath, sizeof(header.linkname));
264 free(lpath);
265 } else if (S_ISDIR(statbuf->st_mode)) {
266 header.typeflag = DIRTYPE;
267 strncat(header.name, "/", sizeof(header.name));
268 } else if (S_ISCHR(statbuf->st_mode)) {
269 header.typeflag = CHRTYPE;
270 putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
271 putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
272 } else if (S_ISBLK(statbuf->st_mode)) {
273 header.typeflag = BLKTYPE;
274 putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
275 putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
276 } else if (S_ISFIFO(statbuf->st_mode)) {
277 header.typeflag = FIFOTYPE;
278 } else if (S_ISREG(statbuf->st_mode)) {
279 header.typeflag = REGTYPE;
280 putOctal(header.size, sizeof(header.size), statbuf->st_size);
281 } else {
282 error_msg("%s: Unknown file type", real_name);
283 return ( FALSE);
284 }
285
286 /* Calculate and store the checksum (i.e., the sum of all of the bytes of
287 * the header). The checksum field must be filled with blanks for the
288 * calculation. The checksum field is formatted differently from the
289 * other fields: it has [6] digits, a null, then a space -- rather than
290 * digits, followed by a null like the other fields... */
291 memset(header.chksum, ' ', sizeof(header.chksum));
292 cp = (const unsigned char *) &header;
293 while (size-- > 0)
294 chksum += *cp++;
295 putOctal(header.chksum, 7, chksum);
296
297 /* Now write the header out to disk */
298 if ((size=full_write(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) {
299 error_msg(io_error, real_name, strerror(errno));
300 return ( FALSE);
301 }
302 /* Pad the header up to the tar block size */
303 for (; size<TAR_BLOCK_SIZE; size++) {
304 write(tbInfo->tarFd, "\0", 1);
305 }
306 /* Now do the verbose thing (or not) */
307 if (tbInfo->verboseFlag==TRUE) {
308 FILE *vbFd = stdout;
309 if (tbInfo->tarFd == fileno(stdout)) // If the archive goes to stdout, verbose to stderr
310 vbFd = stderr;
311 fprintf(vbFd, "%s\n", header.name);
312 }
313
314 return ( TRUE);
315}
316
317static int exclude_file(char **excluded_files, const char *file)
318{
319 int i;
320
321 if (excluded_files == NULL)
322 return 0;
323
324 for (i = 0; excluded_files[i] != NULL; i++) {
325 if (excluded_files[i][0] == '/') {
326 if (fnmatch(excluded_files[i], file,
327 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
328 return 1;
329 } else {
330 const char *p;
331
332 for (p = file; p[0] != '\0'; p++) {
333 if ((p == file || p[-1] == '/') && p[0] != '/' &&
334 fnmatch(excluded_files[i], p,
335 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
336 return 1;
337 }
338 }
339 }
340
341 return 0;
342}
343
344static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData)
345{
346 struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
347 const char *header_name;
348
349 /*
350 ** Check to see if we are dealing with a hard link.
351 ** If so -
352 ** Treat the first occurance of a given dev/inode as a file while
353 ** treating any additional occurances as hard links. This is done
354 ** by adding the file information to the HardLinkInfo linked list.
355 */
356 tbInfo->hlInfo = NULL;
357 if (statbuf->st_nlink > 1) {
358 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev,
359 statbuf->st_ino);
360 if (tbInfo->hlInfo == NULL)
361 addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev,
362 statbuf->st_ino, statbuf->st_nlink, fileName);
363 }
364
365 /* It is against the rules to archive a socket */
366 if (S_ISSOCK(statbuf->st_mode)) {
367 error_msg("%s: socket ignored", fileName);
368 return( TRUE);
369 }
370
371 /* It is a bad idea to store the archive we are in the process of creating,
372 * so check the device and inode to be sure that this particular file isn't
373 * the new tarball */
374 if (tbInfo->statBuf.st_dev == statbuf->st_dev &&
375 tbInfo->statBuf.st_ino == statbuf->st_ino) {
376 error_msg("%s: file is the archive; skipping", fileName);
377 return( TRUE);
378 }
379
380 header_name = fileName;
381 while (header_name[0] == '/') {
382 static int alreadyWarned=FALSE;
383 if (alreadyWarned==FALSE) {
384 error_msg("Removing leading '/' from member names");
385 alreadyWarned=TRUE;
386 }
387 header_name++;
388 }
389
390 if (strlen(fileName) >= NAME_SIZE) {
391 error_msg(name_longer_than_foo, NAME_SIZE);
392 return ( TRUE);
393 }
394
395 if (header_name[0] == '\0')
396 return TRUE;
397
398# if defined BB_FEATURE_TAR_EXCLUDE
399 if (exclude_file(tbInfo->excludeList, header_name)) {
400 return SKIP;
401 }
402# endif //BB_FEATURE_TAR_EXCLUDE
403
404 if (writeTarHeader(tbInfo, header_name, fileName, statbuf)==FALSE) {
405 return( FALSE);
406 }
407
408 /* Now, if the file is a regular file, copy it out to the tarball */
409 if ((tbInfo->hlInfo == NULL)
410 && (S_ISREG(statbuf->st_mode))) {
411 int inputFileFd;
412 char buffer[BUFSIZ];
413 ssize_t size=0, readSize=0;
414
415 /* open the file we want to archive, and make sure all is well */
416 if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
417 error_msg("%s: Cannot open: %s", fileName, strerror(errno));
418 return( FALSE);
419 }
420
421 /* write the file to the archive */
422 while ( (size = full_read(inputFileFd, buffer, sizeof(buffer))) > 0 ) {
423 if (full_write(tbInfo->tarFd, buffer, size) != size ) {
424 /* Output file seems to have a problem */
425 error_msg(io_error, fileName, strerror(errno));
426 return( FALSE);
427 }
428 readSize+=size;
429 }
430 if (size == -1) {
431 error_msg(io_error, fileName, strerror(errno));
432 return( FALSE);
433 }
434 /* Pad the file up to the tar block size */
435 for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) {
436 write(tbInfo->tarFd, "\0", 1);
437 }
438 close( inputFileFd);
439 }
440
441 return( TRUE);
442}
443
444static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
445 char** excludeList)
446{
447 int tarFd=-1;
448 int errorFlag=FALSE;
449 ssize_t size;
450 struct TarBallInfo tbInfo;
451 tbInfo.verboseFlag = verboseFlag;
452 tbInfo.hlInfoHead = NULL;
453
454 /* Make sure there is at least one file to tar up. */
455 if (*argv == NULL)
456 error_msg_and_die("Cowardly refusing to create an empty archive");
457
458 /* Open the tar file for writing. */
459 if (!strcmp(tarName, "-"))
460 tbInfo.tarFd = fileno(stdout);
461 else
462 tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
463 if (tbInfo.tarFd < 0) {
464 perror_msg( "Error opening '%s'", tarName);
465 freeHardLinkInfo(&tbInfo.hlInfoHead);
466 return ( FALSE);
467 }
468 tbInfo.excludeList=excludeList;
469 /* Store the stat info for the tarball's file, so
470 * can avoid including the tarball into itself.... */
471 if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
472 error_msg_and_die(io_error, tarName, strerror(errno));
473
474 /* Read the directory/files and iterate over them one at a time */
475 while (*argv != NULL) {
476 if (recursive_action(*argv++, TRUE, FALSE, FALSE,
477 writeFileToTarball, writeFileToTarball,
478 (void*) &tbInfo) == FALSE) {
479 errorFlag = TRUE;
480 }
481 }
482 /* Write two empty blocks to the end of the archive */
483 for (size=0; size<(2*TAR_BLOCK_SIZE); size++) {
484 write(tbInfo.tarFd, "\0", 1);
485 }
486
487 /* To be pedantically correct, we would check if the tarball
488 * is smaller than 20 tar blocks, and pad it if it was smaller,
489 * but that isn't necessary for GNU tar interoperability, and
490 * so is considered a waste of space */
491
492 /* Hang up the tools, close up shop, head home */
493 close(tarFd);
494 if (errorFlag == TRUE) {
495 error_msg("Error exit delayed from previous errors");
496 freeHardLinkInfo(&tbInfo.hlInfoHead);
497 return(FALSE);
498 }
499 freeHardLinkInfo(&tbInfo.hlInfoHead);
500 return( TRUE);
501}
502#endif //tar_create
503
504void append_file_to_list(const char *new_name, char ***list, int *list_count)
505{
506 *list = realloc(*list, sizeof(char *) * (*list_count + 2));
507 (*list)[*list_count] = xstrdup(new_name);
508 (*list_count)++;
509 (*list)[*list_count] = NULL;
510}
511
512void append_file_list_to_list(char *filename, char ***name_list, int *num_of_entries)
513{
514 FILE *src_stream;
515 char *line;
516 char *line_ptr;
517
518 src_stream = xfopen(filename, "r");
519 while ((line = get_line_from_file(src_stream)) != NULL) {
520 line_ptr = last_char_is(line, '\n');
521 if (line_ptr) {
522 *line_ptr = '\0';
523 }
524 append_file_to_list(line, name_list, num_of_entries);
525 free(line);
526 }
527 fclose(src_stream);
528}
529
530#ifdef BB_FEATURE_TAR_EXCLUDE
531/*
532 * Create a list of names that are in the include list AND NOT in the exclude lists
533 */
534char **list_and_not_list(char **include_list, char **exclude_list)
535{
536 char **new_include_list = NULL;
537 int new_include_count = 0;
538 int include_count = 0;
539 int exclude_count;
540
541 if (include_list == NULL) {
542 return(NULL);
543 }
544
545 while (include_list[include_count] != NULL) {
546 int found = FALSE;
547 exclude_count = 0;
548 while (exclude_list[exclude_count] != NULL) {
549 if (strcmp(include_list[include_count], exclude_list[exclude_count]) == 0) {
550 found = TRUE;
551 break;
552 }
553 exclude_count++;
554 }
555
556 if (found == FALSE) {
557 new_include_list = realloc(new_include_list, sizeof(char *) * (include_count + 2));
558 new_include_list[new_include_count] = include_list[include_count];
559 new_include_count++;
560 } else {
561 free(include_list[include_count]);
562 }
563 include_count++;
564 }
565 new_include_list[new_include_count] = NULL;
566 return(new_include_list);
567}
568#endif
569
570int tar_main(int argc, char **argv)
571{
572 enum untar_funct_e {
573 /* These are optional */
574 untar_from_file = 1,
575 untar_from_stdin = 2,
576 untar_unzip = 4,
577 /* Require one and only one of these */
578 untar_list = 8,
579 untar_create = 16,
580 untar_extract = 32
581 };
582
583 FILE *src_stream = NULL;
584 FILE *uncompressed_stream = NULL;
585 char **include_list = NULL;
586 char **exclude_list = NULL;
587 char *src_filename = NULL;
588 char *dst_prefix = NULL;
589 char *file_list_name = NULL;
590 int opt;
591 unsigned short untar_funct = 0;
592 unsigned short untar_funct_required = 0;
593 unsigned short extract_function = 0;
594 int include_list_count = 0;
595 int exclude_list_count = 0;
596 int gunzip_pid;
597 int gz_fd = 0;
598
599 if (argc < 2) {
600 show_usage();
601 }
602
603 /* Prepend '-' to the first argument if required */
604 if (argv[1][0] != '-') {
605 char *tmp = xmalloc(strlen(argv[1]) + 2);
606 tmp[0] = '-';
607 strcpy(tmp + 1, argv[1]);
608 argv[1] = tmp;
609 }
610
611 while ((opt = getopt(argc, argv, "ctxT:X:C:f:Opvz")) != -1) {
612 switch (opt) {
613
614 /* One and only one of these is required */
615 case 'c':
616 untar_funct_required |= untar_create;
617 break;
618 case 't':
619 untar_funct_required |= untar_list;
620 extract_function |= extract_list |extract_unconditional;
621 break;
622 case 'x':
623 untar_funct_required |= untar_extract;
624 extract_function |= (extract_all_to_fs | extract_unconditional | extract_create_leading_dirs);
625 break;
626
627 /* These are optional */
628 /* Exclude or Include files listed in <filename>*/
629#ifdef BB_FEATURE_TAR_EXCLUDE
630 case 'X':
631 append_file_list_to_list(optarg, &exclude_list, &exclude_list_count);
632 break;
633#endif
634 case 'T':
635 // by default a list is an include list
636 append_file_list_to_list(optarg, &include_list, &include_list_count);
637 break;
638
639 case 'C': // Change to dir <optarg>
640 /* Make sure dst_prefix ends in a '/' */
641 dst_prefix = concat_path_file(optarg, "/");
642 break;
643 case 'f': // archive filename
644 if (strcmp(optarg, "-") == 0) {
645 // Untar from stdin to stdout
646 untar_funct |= untar_from_stdin;
647 } else {
648 untar_funct |= untar_from_file;
649 src_filename = xstrdup(optarg);
650 }
651 break;
652 case 'O':
653 extract_function |= extract_to_stdout;
654 break;
655 case 'p':
656 break;
657 case 'v':
658 if (extract_function & extract_list) {
659 extract_function |= extract_verbose_list;
660 }
661 extract_function |= extract_list;
662 break;
663#ifdef BB_FEATURE_TAR_GZIP
664 case 'z':
665 untar_funct |= untar_unzip;
666 break;
667#endif
668 default:
669 show_usage();
670 }
671 }
672
673 /* Make sure the valid arguments were passed */
674 if (untar_funct_required == 0) {
675 error_msg_and_die("You must specify one of the `-ctx' options");
676 }
677 if ((untar_funct_required != untar_create) &&
678 (untar_funct_required != untar_extract) &&
679 (untar_funct_required != untar_list)) {
680 error_msg_and_die("You may not specify more than one `ctx' option.");
681 }
682 untar_funct |= untar_funct_required;
683
684 /* Setup an array of filenames to work with */
685 while (optind < argc) {
686 append_file_to_list(argv[optind], &include_list, &include_list_count);
687 optind++;
688 }
689
690 if (extract_function & (extract_list | extract_all_to_fs)) {
691 if (dst_prefix == NULL) {
692 dst_prefix = xstrdup("./");
693 }
694
695 /* Setup the source of the tar data */
696 if (untar_funct & untar_from_file) {
697 src_stream = xfopen(src_filename, "r");
698 } else {
699 src_stream = stdin;
700 }
701#ifdef BB_FEATURE_TAR_GZIP
702 /* Get a binary tree of all the tar file headers */
703 if (untar_funct & untar_unzip) {
704 uncompressed_stream = gz_open(src_stream, &gunzip_pid);
705 } else
706#endif // BB_FEATURE_TAR_GZIP
707 uncompressed_stream = src_stream;
708
709 /* extract or list archive */
710 unarchive(uncompressed_stream, stdout, &get_header_tar, extract_function, dst_prefix, include_list, exclude_list);
711 fclose(uncompressed_stream);
712 }
713#ifdef BB_FEATURE_TAR_CREATE
714 /* create an archive */
715 else if (untar_funct & untar_create) {
716 int verboseFlag = FALSE;
717
718#ifdef BB_FEATURE_TAR_GZIP
719 if (untar_funct && untar_unzip) {
720 error_msg_and_die("Creation of compressed tarfile not internally support by tar, pipe to busybox gunzip");
721 }
722#endif // BB_FEATURE_TAR_GZIP
723 if (extract_function & extract_verbose_list) {
724 verboseFlag = TRUE;
725 }
726 writeTarFile(src_filename, verboseFlag, &argv[argc - 1], include_list);
727 }
728#endif // BB_FEATURE_TAR_CREATE
729
730 /* Cleanups */
731#ifdef BB_FEATURE_TAR_GZIP
732 if (untar_funct & untar_unzip) {
733 fclose(src_stream);
734 close(gz_fd);
735 gz_close(gunzip_pid);
736 }
737#endif // BB_FEATURE_TAR_GZIP
738 if (src_filename) {
739 free(src_filename);
740 }
741 if (file_list_name) {
742 free(file_list_name);
743 }
744 return(EXIT_SUCCESS);
745}
diff --git a/tee.c b/tee.c
deleted file mode 100644
index 64a0922b7..000000000
--- a/tee.c
+++ /dev/null
@@ -1,67 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini tee implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include "busybox.h"
25#include <getopt.h>
26#include <stdio.h>
27
28int
29tee_main(int argc, char **argv)
30{
31 char *mode = "w";
32 int c, i, status = 0, nfiles = 0;
33 FILE **files;
34
35 while ((c = getopt(argc, argv, "a")) != EOF) {
36 switch (c) {
37 case 'a':
38 mode = "a";
39 break;
40 default:
41 show_usage();
42 }
43 }
44
45 files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 1));
46 files[nfiles++] = stdout;
47 while (optind < argc) {
48 if ((files[nfiles++] = wfopen(argv[optind++], mode)) == NULL) {
49 nfiles--;
50 status = 1;
51 }
52 }
53
54 while ((c = getchar()) != EOF)
55 for (i = 0; i < nfiles; i++)
56 putc(c, files[i]);
57
58 return status;
59}
60
61/*
62Local Variables:
63c-file-style: "linux"
64c-basic-offset: 4
65tab-width: 4
66End:
67*/
diff --git a/telnet.c b/telnet.c
deleted file mode 100644
index ce82a0ee8..000000000
--- a/telnet.c
+++ /dev/null
@@ -1,711 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * telnet implementation for busybox
4 *
5 * Author: Tomi Ollila <too@iki.fi>
6 * Copyright (C) 1994-2000 by Tomi Ollila
7 *
8 * Created: Thu Apr 7 13:29:41 1994 too
9 * Last modified: Fri Jun 9 14:34:24 2000 too
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 * HISTORY
26 * Revision 3.1 1994/04/17 11:31:54 too
27 * initial revision
28 * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen
29 * <andersen@lineo.com>
30 * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan
31 * <jam@ltsp.org>
32 *
33 */
34
35#include <termios.h>
36#include <unistd.h>
37#include <errno.h>
38#include <stdlib.h>
39#include <stdarg.h>
40#include <string.h>
41#include <signal.h>
42#include <arpa/telnet.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/in.h>
46#include <netdb.h>
47#include "busybox.h"
48
49#if 0
50static const int DOTRACE = 1;
51#endif
52
53#ifdef DOTRACE
54#include <arpa/inet.h> /* for inet_ntoa()... */
55#define TRACE(x, y) do { if (x) printf y; } while (0)
56#else
57#define TRACE(x, y)
58#endif
59
60#if 0
61#define USE_POLL
62#include <sys/poll.h>
63#else
64#include <sys/time.h>
65#endif
66
67#define DATABUFSIZE 128
68#define IACBUFSIZE 128
69
70static const int CHM_TRY = 0;
71static const int CHM_ON = 1;
72static const int CHM_OFF = 2;
73
74static const int UF_ECHO = 0x01;
75static const int UF_SGA = 0x02;
76
77enum {
78 TS_0 = 1,
79 TS_IAC = 2,
80 TS_OPT = 3,
81 TS_SUB1 = 4,
82 TS_SUB2 = 5,
83};
84
85#define WriteCS(fd, str) write(fd, str, sizeof str -1)
86
87typedef unsigned char byte;
88
89/* use globals to reduce size ??? */ /* test this hypothesis later */
90static struct Globalvars {
91 int netfd; /* console fd:s are 0 and 1 (and 2) */
92 /* same buffer used both for network and console read/write */
93 char buf[DATABUFSIZE]; /* allocating so static size is smaller */
94 byte telstate; /* telnet negotiation state from network input */
95 byte telwish; /* DO, DONT, WILL, WONT */
96 byte charmode;
97 byte telflags;
98 byte gotsig;
99 /* buffer to handle telnet negotiations */
100 char iacbuf[IACBUFSIZE];
101 short iaclen; /* could even use byte */
102 struct termios termios_def;
103 struct termios termios_raw;
104} G;
105
106#define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */
107
108#ifdef USE_GLOBALVAR_PTR
109struct Globalvars * Gptr;
110#define G (*Gptr)
111#else
112static struct Globalvars G;
113#endif
114
115static inline void iacflush()
116{
117 write(G.netfd, G.iacbuf, G.iaclen);
118 G.iaclen = 0;
119}
120
121/* Function prototypes */
122static int getport(char * p);
123static struct in_addr getserver(char * p);
124static int create_socket();
125static void setup_sockaddr_in(struct sockaddr_in * addr, int port);
126static int remote_connect(struct in_addr addr, int port);
127static void rawmode();
128static void cookmode();
129static void do_linemode();
130static void will_charmode();
131static void telopt(byte c);
132static int subneg(byte c);
133#if 0
134static int local_bind(int port);
135#endif
136
137/* Some globals */
138static int one = 1;
139
140#ifdef BB_FEATURE_TELNET_TTYPE
141static char *ttype;
142#endif
143
144static void doexit(int ev)
145{
146 cookmode();
147 exit(ev);
148}
149
150static void conescape()
151{
152 char b;
153
154 if (G.gotsig) /* came from line mode... go raw */
155 rawmode();
156
157 WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"
158 " l go to line mode\r\n"
159 " c go to character mode\r\n"
160 " z suspend telnet\r\n"
161 " e exit telnet\r\n");
162
163 if (read(0, &b, 1) <= 0)
164 doexit(1);
165
166 switch (b)
167 {
168 case 'l':
169 if (!G.gotsig)
170 {
171 do_linemode();
172 goto rrturn;
173 }
174 break;
175 case 'c':
176 if (G.gotsig)
177 {
178 will_charmode();
179 goto rrturn;
180 }
181 break;
182 case 'z':
183 cookmode();
184 kill(0, SIGTSTP);
185 rawmode();
186 break;
187 case 'e':
188 doexit(0);
189 }
190
191 WriteCS(1, "continuing...\r\n");
192
193 if (G.gotsig)
194 cookmode();
195
196 rrturn:
197 G.gotsig = 0;
198
199}
200static void handlenetoutput(int len)
201{
202 /* here we could do smart tricks how to handle 0xFF:s in output
203 * stream like writing twice every sequence of FF:s (thus doing
204 * many write()s. But I think interactive telnet application does
205 * not need to be 100% 8-bit clean, so changing every 0xff:s to
206 * 0x7f:s */
207
208 int i;
209 byte * p = G.buf;
210
211 for (i = len; i > 0; i--, p++)
212 {
213 if (*p == 0x1d)
214 {
215 conescape();
216 return;
217 }
218 if (*p == 0xff)
219 *p = 0x7f;
220 }
221 write(G.netfd, G.buf, len);
222}
223
224
225static void handlenetinput(int len)
226{
227 int i;
228 int cstart = 0;
229
230 for (i = 0; i < len; i++)
231 {
232 byte c = G.buf[i];
233
234 if (G.telstate == 0) /* most of the time state == 0 */
235 {
236 if (c == IAC)
237 {
238 cstart = i;
239 G.telstate = TS_IAC;
240 }
241 }
242 else
243 switch (G.telstate)
244 {
245 case TS_0:
246 if (c == IAC)
247 G.telstate = TS_IAC;
248 else
249 G.buf[cstart++] = c;
250 break;
251
252 case TS_IAC:
253 if (c == IAC) /* IAC IAC -> 0xFF */
254 {
255 G.buf[cstart++] = c;
256 G.telstate = TS_0;
257 break;
258 }
259 /* else */
260 switch (c)
261 {
262 case SB:
263 G.telstate = TS_SUB1;
264 break;
265 case DO:
266 case DONT:
267 case WILL:
268 case WONT:
269 G.telwish = c;
270 G.telstate = TS_OPT;
271 break;
272 default:
273 G.telstate = TS_0; /* DATA MARK must be added later */
274 }
275 break;
276 case TS_OPT: /* WILL, WONT, DO, DONT */
277 telopt(c);
278 G.telstate = TS_0;
279 break;
280 case TS_SUB1: /* Subnegotiation */
281 case TS_SUB2: /* Subnegotiation */
282 if (subneg(c) == TRUE)
283 G.telstate = TS_0;
284 break;
285 }
286 }
287 if (G.telstate)
288 {
289 if (G.iaclen) iacflush();
290 if (G.telstate == TS_0) G.telstate = 0;
291
292 len = cstart;
293 }
294
295 if (len)
296 write(1, G.buf, len);
297}
298
299
300/* ******************************* */
301
302static inline void putiac(int c)
303{
304 G.iacbuf[G.iaclen++] = c;
305}
306
307
308static void putiac2(byte wwdd, byte c)
309{
310 if (G.iaclen + 3 > IACBUFSIZE)
311 iacflush();
312
313 putiac(IAC);
314 putiac(wwdd);
315 putiac(c);
316}
317
318#if 0
319static void putiac1(byte c)
320{
321 if (G.iaclen + 2 > IACBUFSIZE)
322 iacflush();
323
324 putiac(IAC);
325 putiac(c);
326}
327#endif
328
329#ifdef BB_FEATURE_TELNET_TTYPE
330static void putiac_subopt(byte c, char *str)
331{
332 int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 )
333
334 if (G.iaclen + len > IACBUFSIZE)
335 iacflush();
336
337 putiac(IAC);
338 putiac(SB);
339 putiac(c);
340 putiac(0);
341
342 while(*str)
343 putiac(*str++);
344
345 putiac(IAC);
346 putiac(SE);
347}
348#endif
349
350/* void putiacstring (subneg strings) */
351
352/* ******************************* */
353
354static char const escapecharis[] = "\r\nEscape character is ";
355
356static void setConMode()
357{
358 if (G.telflags & UF_ECHO)
359 {
360 if (G.charmode == CHM_TRY) {
361 G.charmode = CHM_ON;
362 printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis);
363 rawmode();
364 }
365 }
366 else
367 {
368 if (G.charmode != CHM_OFF) {
369 G.charmode = CHM_OFF;
370 printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis);
371 cookmode();
372 }
373 }
374}
375
376/* ******************************* */
377
378static void will_charmode()
379{
380 G.charmode = CHM_TRY;
381 G.telflags |= (UF_ECHO | UF_SGA);
382 setConMode();
383
384 putiac2(DO, TELOPT_ECHO);
385 putiac2(DO, TELOPT_SGA);
386 iacflush();
387}
388
389static void do_linemode()
390{
391 G.charmode = CHM_TRY;
392 G.telflags &= ~(UF_ECHO | UF_SGA);
393 setConMode();
394
395 putiac2(DONT, TELOPT_ECHO);
396 putiac2(DONT, TELOPT_SGA);
397 iacflush();
398}
399
400/* ******************************* */
401
402static inline void to_notsup(char c)
403{
404 if (G.telwish == WILL) putiac2(DONT, c);
405 else if (G.telwish == DO) putiac2(WONT, c);
406}
407
408static inline void to_echo()
409{
410 /* if server requests ECHO, don't agree */
411 if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; }
412 else if (G.telwish == DONT) return;
413
414 if (G.telflags & UF_ECHO)
415 {
416 if (G.telwish == WILL)
417 return;
418 }
419 else
420 if (G.telwish == WONT)
421 return;
422
423 if (G.charmode != CHM_OFF)
424 G.telflags ^= UF_ECHO;
425
426 if (G.telflags & UF_ECHO)
427 putiac2(DO, TELOPT_ECHO);
428 else
429 putiac2(DONT, TELOPT_ECHO);
430
431 setConMode();
432 WriteCS(1, "\r\n"); /* sudden modec */
433}
434
435static inline void to_sga()
436{
437 /* daemon always sends will/wont, client do/dont */
438
439 if (G.telflags & UF_SGA)
440 {
441 if (G.telwish == WILL)
442 return;
443 }
444 else
445 if (G.telwish == WONT)
446 return;
447
448 if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */
449 putiac2(DO, TELOPT_SGA);
450 else
451 putiac2(DONT, TELOPT_SGA);
452
453 return;
454}
455
456#ifdef BB_FEATURE_TELNET_TTYPE
457static inline void to_ttype()
458{
459 /* Tell server we will (or won't) do TTYPE */
460
461 if(ttype)
462 putiac2(WILL, TELOPT_TTYPE);
463 else
464 putiac2(WONT, TELOPT_TTYPE);
465
466 return;
467}
468#endif
469
470static void telopt(byte c)
471{
472 switch (c)
473 {
474 case TELOPT_ECHO: to_echo(c); break;
475 case TELOPT_SGA: to_sga(c); break;
476#ifdef BB_FEATURE_TELNET_TTYPE
477 case TELOPT_TTYPE: to_ttype(c); break;
478#endif
479 default: to_notsup(c); break;
480 }
481}
482
483
484/* ******************************* */
485
486/* subnegotiation -- ignore all (except TTYPE) */
487
488static int subneg(byte c)
489{
490 switch (G.telstate)
491 {
492 case TS_SUB1:
493 if (c == IAC)
494 G.telstate = TS_SUB2;
495#ifdef BB_FEATURE_TELNET_TTYPE
496 else
497 if (c == TELOPT_TTYPE)
498 putiac_subopt(TELOPT_TTYPE,ttype);
499#endif
500 break;
501 case TS_SUB2:
502 if (c == SE)
503 return TRUE;
504 G.telstate = TS_SUB1;
505 /* break; */
506 }
507 return FALSE;
508}
509
510/* ******************************* */
511
512static void fgotsig(int sig)
513{
514 G.gotsig = sig;
515}
516
517
518static void rawmode()
519{
520 tcsetattr(0, TCSADRAIN, &G.termios_raw);
521}
522
523static void cookmode()
524{
525 tcsetattr(0, TCSADRAIN, &G.termios_def);
526}
527
528extern int telnet_main(int argc, char** argv)
529{
530 struct in_addr host;
531 int port;
532 int len;
533#ifdef USE_POLL
534 struct pollfd ufds[2];
535#else
536 fd_set readfds;
537 int maxfd;
538#endif
539
540#ifdef BB_FEATURE_TELNET_TTYPE
541 ttype = getenv("TERM");
542#endif
543
544 memset(&G, 0, sizeof G);
545
546 if (tcgetattr(0, &G.termios_def) < 0)
547 exit(1);
548
549 G.termios_raw = G.termios_def;
550 cfmakeraw(&G.termios_raw);
551
552 if (argc < 2) show_usage();
553 port = (argc > 2)? getport(argv[2]): 23;
554
555 host = getserver(argv[1]);
556
557 G.netfd = remote_connect(host, port);
558
559 signal(SIGINT, fgotsig);
560
561#ifdef USE_POLL
562 ufds[0].fd = 0; ufds[1].fd = G.netfd;
563 ufds[0].events = ufds[1].events = POLLIN;
564#else
565 FD_ZERO(&readfds);
566 FD_SET(0, &readfds);
567 FD_SET(G.netfd, &readfds);
568 maxfd = G.netfd + 1;
569#endif
570
571 while (1)
572 {
573#ifndef USE_POLL
574 fd_set rfds = readfds;
575
576 switch (select(maxfd, &rfds, NULL, NULL, NULL))
577#else
578 switch (poll(ufds, 2, -1))
579#endif
580 {
581 case 0:
582 /* timeout */
583 case -1:
584 /* error, ignore and/or log something, bay go to loop */
585 if (G.gotsig)
586 conescape();
587 else
588 sleep(1);
589 break;
590 default:
591
592#ifdef USE_POLL
593 if (ufds[0].revents) /* well, should check POLLIN, but ... */
594#else
595 if (FD_ISSET(0, &rfds))
596#endif
597 {
598 len = read(0, G.buf, DATABUFSIZE);
599
600 if (len <= 0)
601 doexit(0);
602
603 TRACE(0, ("Read con: %d\n", len));
604
605 handlenetoutput(len);
606 }
607
608#ifdef USE_POLL
609 if (ufds[1].revents) /* well, should check POLLIN, but ... */
610#else
611 if (FD_ISSET(G.netfd, &rfds))
612#endif
613 {
614 len = read(G.netfd, G.buf, DATABUFSIZE);
615
616 if (len <= 0)
617 {
618 WriteCS(1, "Connection closed by foreign host.\r\n");
619 doexit(1);
620 }
621 TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
622
623 handlenetinput(len);
624 }
625 }
626 }
627}
628
629static int getport(char * p)
630{
631 unsigned int port = atoi(p);
632
633 if ((unsigned)(port - 1 ) > 65534)
634 {
635 error_msg_and_die("%s: bad port number", p);
636 }
637 return port;
638}
639
640static struct in_addr getserver(char * host)
641{
642 struct in_addr addr;
643
644 struct hostent * he;
645 he = xgethostbyname(host);
646 memcpy(&addr, he->h_addr, sizeof addr);
647
648 TRACE(1, ("addr: %s\n", inet_ntoa(addr)));
649
650 return addr;
651}
652
653static int create_socket()
654{
655 return socket(AF_INET, SOCK_STREAM, 0);
656}
657
658static void setup_sockaddr_in(struct sockaddr_in * addr, int port)
659{
660 memset(addr, 0, sizeof(struct sockaddr_in));
661 addr->sin_family = AF_INET;
662 addr->sin_port = htons(port);
663}
664
665#if 0
666static int local_bind(int port)
667{
668 struct sockaddr_in s_addr;
669 int s = create_socket();
670
671 setup_sockaddr_in(&s_addr, port);
672
673 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
674
675 if (bind(s, &s_addr, sizeof s_addr) < 0)
676 {
677 char * e = sys_errlist[errno];
678 syserrorexit("bind");
679 exit(1);
680 }
681 listen(s, 1);
682
683 return s;
684}
685#endif
686
687static int remote_connect(struct in_addr addr, int port)
688{
689 struct sockaddr_in s_addr;
690 int s = create_socket();
691
692 setup_sockaddr_in(&s_addr, port);
693 s_addr.sin_addr = addr;
694
695 setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
696
697 if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0)
698 {
699 perror_msg_and_die("Unable to connect to remote host");
700 }
701 return s;
702}
703
704/*
705Local Variables:
706c-file-style: "linux"
707c-basic-offset: 4
708tab-width: 4
709End:
710*/
711
diff --git a/test.c b/test.c
deleted file mode 100644
index 3404b02b4..000000000
--- a/test.c
+++ /dev/null
@@ -1,579 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * test implementation for busybox
4 *
5 * Copyright (c) by a whole pile of folks:
6 *
7 * test(1); version 7-like -- author Erik Baalbergen
8 * modified by Eric Gisin to be used as built-in.
9 * modified by Arnold Robbins to add SVR3 compatibility
10 * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
11 * modified by J.T. Conklin for NetBSD.
12 * modified by Herbert Xu to be used as built-in in ash.
13 * modified by Erik Andersen <andersee@debian.org> to be used
14 * in busybox.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 * Original copyright notice states:
31 * "This program is in the Public Domain."
32 */
33
34#include <sys/types.h>
35#include <unistd.h>
36#include <ctype.h>
37#include <errno.h>
38#include <stdlib.h>
39#include <string.h>
40#include "busybox.h"
41
42/* test(1) accepts the following grammar:
43 oexpr ::= aexpr | aexpr "-o" oexpr ;
44 aexpr ::= nexpr | nexpr "-a" aexpr ;
45 nexpr ::= primary | "!" primary
46 primary ::= unary-operator operand
47 | operand binary-operator operand
48 | operand
49 | "(" oexpr ")"
50 ;
51 unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
52 "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
53
54 binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
55 "-nt"|"-ot"|"-ef";
56 operand ::= <any legal UNIX file name>
57*/
58
59enum token {
60 EOI,
61 FILRD,
62 FILWR,
63 FILEX,
64 FILEXIST,
65 FILREG,
66 FILDIR,
67 FILCDEV,
68 FILBDEV,
69 FILFIFO,
70 FILSOCK,
71 FILSYM,
72 FILGZ,
73 FILTT,
74 FILSUID,
75 FILSGID,
76 FILSTCK,
77 FILNT,
78 FILOT,
79 FILEQ,
80 FILUID,
81 FILGID,
82 STREZ,
83 STRNZ,
84 STREQ,
85 STRNE,
86 STRLT,
87 STRGT,
88 INTEQ,
89 INTNE,
90 INTGE,
91 INTGT,
92 INTLE,
93 INTLT,
94 UNOT,
95 BAND,
96 BOR,
97 LPAREN,
98 RPAREN,
99 OPERAND
100};
101
102enum token_types {
103 UNOP,
104 BINOP,
105 BUNOP,
106 BBINOP,
107 PAREN
108};
109
110static const struct t_op {
111 const char *op_text;
112 short op_num, op_type;
113} ops [] = {
114 {"-r", FILRD, UNOP},
115 {"-w", FILWR, UNOP},
116 {"-x", FILEX, UNOP},
117 {"-e", FILEXIST,UNOP},
118 {"-f", FILREG, UNOP},
119 {"-d", FILDIR, UNOP},
120 {"-c", FILCDEV,UNOP},
121 {"-b", FILBDEV,UNOP},
122 {"-p", FILFIFO,UNOP},
123 {"-u", FILSUID,UNOP},
124 {"-g", FILSGID,UNOP},
125 {"-k", FILSTCK,UNOP},
126 {"-s", FILGZ, UNOP},
127 {"-t", FILTT, UNOP},
128 {"-z", STREZ, UNOP},
129 {"-n", STRNZ, UNOP},
130 {"-h", FILSYM, UNOP}, /* for backwards compat */
131 {"-O", FILUID, UNOP},
132 {"-G", FILGID, UNOP},
133 {"-L", FILSYM, UNOP},
134 {"-S", FILSOCK,UNOP},
135 {"=", STREQ, BINOP},
136 {"!=", STRNE, BINOP},
137 {"<", STRLT, BINOP},
138 {">", STRGT, BINOP},
139 {"-eq", INTEQ, BINOP},
140 {"-ne", INTNE, BINOP},
141 {"-ge", INTGE, BINOP},
142 {"-gt", INTGT, BINOP},
143 {"-le", INTLE, BINOP},
144 {"-lt", INTLT, BINOP},
145 {"-nt", FILNT, BINOP},
146 {"-ot", FILOT, BINOP},
147 {"-ef", FILEQ, BINOP},
148 {"!", UNOT, BUNOP},
149 {"-a", BAND, BBINOP},
150 {"-o", BOR, BBINOP},
151 {"(", LPAREN, PAREN},
152 {")", RPAREN, PAREN},
153 {0, 0, 0}
154};
155
156static char **t_wp;
157static struct t_op const *t_wp_op;
158static gid_t *group_array = NULL;
159static int ngroups;
160
161static enum token t_lex(char* s);
162static int oexpr(enum token n);
163static int aexpr(enum token n);
164static int nexpr(enum token n);
165static int binop(void);
166static int primary(enum token n);
167static int filstat(char *nm, enum token mode);
168static int getn(const char *s);
169static int newerf(const char *f1, const char *f2);
170static int olderf(const char *f1, const char *f2);
171static int equalf(const char *f1, const char *f2);
172static void syntax(const char *op, const char *msg);
173static int test_eaccess(char *path, int mode);
174static int is_a_group_member(gid_t gid);
175static void initialize_group_array(void);
176
177extern int
178test_main(int argc, char** argv)
179{
180 int res;
181
182 if (strcmp(applet_name, "[") == 0) {
183 if (strcmp(argv[--argc], "]"))
184 error_msg_and_die("missing ]");
185 argv[argc] = NULL;
186 }
187 /* Implement special cases from POSIX.2, section 4.62.4 */
188 switch (argc) {
189 case 1:
190 exit( 1);
191 case 2:
192 exit (*argv[1] == '\0');
193 case 3:
194 if (argv[1][0] == '!' && argv[1][1] == '\0') {
195 exit (!(*argv[2] == '\0'));
196 }
197 break;
198 case 4:
199 if (argv[1][0] != '!' || argv[1][1] != '\0') {
200 if (t_lex(argv[2]),
201 t_wp_op && t_wp_op->op_type == BINOP) {
202 t_wp = &argv[1];
203 exit (binop() == 0);
204 }
205 }
206 break;
207 case 5:
208 if (argv[1][0] == '!' && argv[1][1] == '\0') {
209 if (t_lex(argv[3]),
210 t_wp_op && t_wp_op->op_type == BINOP) {
211 t_wp = &argv[2];
212 exit (!(binop() == 0));
213 }
214 }
215 break;
216 }
217
218 t_wp = &argv[1];
219 res = !oexpr(t_lex(*t_wp));
220
221 if (*t_wp != NULL && *++t_wp != NULL)
222 syntax(*t_wp, "unknown operand");
223
224 return( res);
225}
226
227static void
228syntax(op, msg)
229 const char *op;
230 const char *msg;
231{
232 if (op && *op)
233 error_msg_and_die("%s: %s", op, msg);
234 else
235 error_msg_and_die("%s", msg);
236}
237
238static int
239oexpr(n)
240 enum token n;
241{
242 int res;
243
244 res = aexpr(n);
245 if (t_lex(*++t_wp) == BOR)
246 return oexpr(t_lex(*++t_wp)) || res;
247 t_wp--;
248 return res;
249}
250
251static int
252aexpr(n)
253 enum token n;
254{
255 int res;
256
257 res = nexpr(n);
258 if (t_lex(*++t_wp) == BAND)
259 return aexpr(t_lex(*++t_wp)) && res;
260 t_wp--;
261 return res;
262}
263
264static int
265nexpr(n)
266 enum token n; /* token */
267{
268 if (n == UNOT)
269 return !nexpr(t_lex(*++t_wp));
270 return primary(n);
271}
272
273static int
274primary(n)
275 enum token n;
276{
277 int res;
278
279 if (n == EOI)
280 syntax(NULL, "argument expected");
281 if (n == LPAREN) {
282 res = oexpr(t_lex(*++t_wp));
283 if (t_lex(*++t_wp) != RPAREN)
284 syntax(NULL, "closing paren expected");
285 return res;
286 }
287 if (t_wp_op && t_wp_op->op_type == UNOP) {
288 /* unary expression */
289 if (*++t_wp == NULL)
290 syntax(t_wp_op->op_text, "argument expected");
291 switch (n) {
292 case STREZ:
293 return strlen(*t_wp) == 0;
294 case STRNZ:
295 return strlen(*t_wp) != 0;
296 case FILTT:
297 return isatty(getn(*t_wp));
298 default:
299 return filstat(*t_wp, n);
300 }
301 }
302
303 if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
304 return binop();
305 }
306
307 return strlen(*t_wp) > 0;
308}
309
310static int
311binop()
312{
313 const char *opnd1, *opnd2;
314 struct t_op const *op;
315
316 opnd1 = *t_wp;
317 (void) t_lex(*++t_wp);
318 op = t_wp_op;
319
320 if ((opnd2 = *++t_wp) == (char *)0)
321 syntax(op->op_text, "argument expected");
322
323 switch (op->op_num) {
324 case STREQ:
325 return strcmp(opnd1, opnd2) == 0;
326 case STRNE:
327 return strcmp(opnd1, opnd2) != 0;
328 case STRLT:
329 return strcmp(opnd1, opnd2) < 0;
330 case STRGT:
331 return strcmp(opnd1, opnd2) > 0;
332 case INTEQ:
333 return getn(opnd1) == getn(opnd2);
334 case INTNE:
335 return getn(opnd1) != getn(opnd2);
336 case INTGE:
337 return getn(opnd1) >= getn(opnd2);
338 case INTGT:
339 return getn(opnd1) > getn(opnd2);
340 case INTLE:
341 return getn(opnd1) <= getn(opnd2);
342 case INTLT:
343 return getn(opnd1) < getn(opnd2);
344 case FILNT:
345 return newerf (opnd1, opnd2);
346 case FILOT:
347 return olderf (opnd1, opnd2);
348 case FILEQ:
349 return equalf (opnd1, opnd2);
350 }
351 /* NOTREACHED */
352 return 1;
353}
354
355static int
356filstat(nm, mode)
357 char *nm;
358 enum token mode;
359{
360 struct stat s;
361 unsigned int i;
362
363 if (mode == FILSYM) {
364#ifdef S_IFLNK
365 if (lstat(nm, &s) == 0) {
366 i = S_IFLNK;
367 goto filetype;
368 }
369#endif
370 return 0;
371 }
372
373 if (stat(nm, &s) != 0)
374 return 0;
375
376 switch (mode) {
377 case FILRD:
378 return test_eaccess(nm, R_OK) == 0;
379 case FILWR:
380 return test_eaccess(nm, W_OK) == 0;
381 case FILEX:
382 return test_eaccess(nm, X_OK) == 0;
383 case FILEXIST:
384 return 1;
385 case FILREG:
386 i = S_IFREG;
387 goto filetype;
388 case FILDIR:
389 i = S_IFDIR;
390 goto filetype;
391 case FILCDEV:
392 i = S_IFCHR;
393 goto filetype;
394 case FILBDEV:
395 i = S_IFBLK;
396 goto filetype;
397 case FILFIFO:
398#ifdef S_IFIFO
399 i = S_IFIFO;
400 goto filetype;
401#else
402 return 0;
403#endif
404 case FILSOCK:
405#ifdef S_IFSOCK
406 i = S_IFSOCK;
407 goto filetype;
408#else
409 return 0;
410#endif
411 case FILSUID:
412 i = S_ISUID;
413 goto filebit;
414 case FILSGID:
415 i = S_ISGID;
416 goto filebit;
417 case FILSTCK:
418 i = S_ISVTX;
419 goto filebit;
420 case FILGZ:
421 return s.st_size > 0L;
422 case FILUID:
423 return s.st_uid == geteuid();
424 case FILGID:
425 return s.st_gid == getegid();
426 default:
427 return 1;
428 }
429
430filetype:
431 return ((s.st_mode & S_IFMT) == i);
432
433filebit:
434 return ((s.st_mode & i) != 0);
435}
436
437static enum token
438t_lex(s)
439 char *s;
440{
441 struct t_op const *op = ops;
442
443 if (s == 0) {
444 t_wp_op = (struct t_op *)0;
445 return EOI;
446 }
447 while (op->op_text) {
448 if (strcmp(s, op->op_text) == 0) {
449 t_wp_op = op;
450 return op->op_num;
451 }
452 op++;
453 }
454 t_wp_op = (struct t_op *)0;
455 return OPERAND;
456}
457
458/* atoi with error detection */
459static int
460getn(s)
461 const char *s;
462{
463 char *p;
464 long r;
465
466 errno = 0;
467 r = strtol(s, &p, 10);
468
469 if (errno != 0)
470 error_msg_and_die("%s: out of range", s);
471
472 while (isspace(*p))
473 p++;
474
475 if (*p)
476 error_msg_and_die("%s: bad number", s);
477
478 return (int) r;
479}
480
481static int
482newerf (f1, f2)
483const char *f1, *f2;
484{
485 struct stat b1, b2;
486
487 return (stat (f1, &b1) == 0 &&
488 stat (f2, &b2) == 0 &&
489 b1.st_mtime > b2.st_mtime);
490}
491
492static int
493olderf (f1, f2)
494const char *f1, *f2;
495{
496 struct stat b1, b2;
497
498 return (stat (f1, &b1) == 0 &&
499 stat (f2, &b2) == 0 &&
500 b1.st_mtime < b2.st_mtime);
501}
502
503static int
504equalf (f1, f2)
505const char *f1, *f2;
506{
507 struct stat b1, b2;
508
509 return (stat (f1, &b1) == 0 &&
510 stat (f2, &b2) == 0 &&
511 b1.st_dev == b2.st_dev &&
512 b1.st_ino == b2.st_ino);
513}
514
515/* Do the same thing access(2) does, but use the effective uid and gid,
516 and don't make the mistake of telling root that any file is
517 executable. */
518static int
519test_eaccess (path, mode)
520char *path;
521int mode;
522{
523 struct stat st;
524 unsigned int euid = geteuid();
525
526 if (stat (path, &st) < 0)
527 return (-1);
528
529 if (euid == 0) {
530 /* Root can read or write any file. */
531 if (mode != X_OK)
532 return (0);
533
534 /* Root can execute any file that has any one of the execute
535 bits set. */
536 if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
537 return (0);
538 }
539
540 if (st.st_uid == euid) /* owner */
541 mode <<= 6;
542 else if (is_a_group_member (st.st_gid))
543 mode <<= 3;
544
545 if (st.st_mode & mode)
546 return (0);
547
548 return (-1);
549}
550
551static void
552initialize_group_array ()
553{
554 ngroups = getgroups(0, NULL);
555 group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
556 getgroups(ngroups, group_array);
557}
558
559/* Return non-zero if GID is one that we have in our groups list. */
560static int
561is_a_group_member (gid)
562gid_t gid;
563{
564 register int i;
565
566 /* Short-circuit if possible, maybe saving a call to getgroups(). */
567 if (gid == getgid() || gid == getegid())
568 return (1);
569
570 if (ngroups == 0)
571 initialize_group_array ();
572
573 /* Search through the list looking for GID. */
574 for (i = 0; i < ngroups; i++)
575 if (gid == group_array[i])
576 return (1);
577
578 return (0);
579}
diff --git a/tests/multibuild.pl b/tests/multibuild.pl
index 94930bd95..a3e49a625 100755
--- a/tests/multibuild.pl
+++ b/tests/multibuild.pl
@@ -12,13 +12,13 @@
12 12
13$logfile = "multibuild.log"; 13$logfile = "multibuild.log";
14 14
15# How to handle all the BB_FEATURE_FOO lines 15# How to handle all the CONFIG_FEATURE_FOO lines
16if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; } 16if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; }
17if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; } 17if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; }
18# neither means, leave that part of Config.h alone 18# neither means, leave that part of Config.h alone
19 19
20# Support building from pristine source 20# Support building from pristine source
21$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne ""); 21$make_opt = "-f $ARGV[0]/Makefile CONFIG_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne "");
22 22
23# Move the config file to a safe place 23# Move the config file to a safe place
24-e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die; 24-e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die;
@@ -38,7 +38,7 @@ while (<C>) {
38 $trailer .= $_; 38 $trailer .= $_;
39 } else { 39 } else {
40 $in_trailer=1 if /End of Applications List/; 40 $in_trailer=1 if /End of Applications List/;
41 if (/^\/*#define BB_([A-Z0-9_]*)/) { 41 if (/^\/*#define CONFIG_([A-Z0-9_]*)/) {
42 push @apps, $1; 42 push @apps, $1;
43 } 43 }
44 } 44 }
@@ -50,7 +50,7 @@ $failed_tests=0;
50for $a (@apps) { 50for $a (@apps) {
51 # print "Testing build of applet $a ...\n"; 51 # print "Testing build of applet $a ...\n";
52 open (O, ">Config.h") || die; 52 open (O, ">Config.h") || die;
53 print O "#define BB_$a\n", $trailer; 53 print O "#define CONFIG_$a\n", $trailer;
54 close O; 54 close O;
55 system("echo -e '\n***\n$a\n***' >>$logfile"); 55 system("echo -e '\n***\n$a\n***' >>$logfile");
56 # With a fast computer and 1-second resolution on file timestamps, this 56 # With a fast computer and 1-second resolution on file timestamps, this
diff --git a/tests/multifeat.pl b/tests/multifeat.pl
index adcb30bbd..875b4a277 100755
--- a/tests/multifeat.pl
+++ b/tests/multifeat.pl
@@ -11,14 +11,14 @@
11 11
12$logfile = "multifeat.log"; 12$logfile = "multifeat.log";
13 13
14# How to handle all the BB_APPLET lines 14# How to handle all the CONFIG_APPLET lines
15# (most thorough testing occurs when you call it with the -all switch) 15# (most thorough testing occurs when you call it with the -all switch)
16if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; } 16if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; }
17if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; } 17if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; }
18# neither means, leave that part of Config.h alone 18# neither means, leave that part of Config.h alone
19 19
20# Support building from pristine source 20# Support building from pristine source
21$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne ""); 21$make_opt = "-f $ARGV[0]/Makefile CONFIG_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne "");
22 22
23# Move the config file to a safe place 23# Move the config file to a safe place
24-e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die; 24-e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die;
@@ -42,7 +42,7 @@ while (<C>) {
42 } 42 }
43 } 43 }
44 elsif ($in_features) { 44 elsif ($in_features) {
45 if (/^\/*#define BB_FEATURE_([A-Z0-9_]*)/) { 45 if (/^\/*#define CONFIG_FEATURE_([A-Z0-9_]*)/) {
46 push @features, $1; 46 push @features, $1;
47 } 47 }
48 if (/End of Features List/) { 48 if (/End of Features List/) {
@@ -60,7 +60,7 @@ $failed_tests=0;
60for $f (@features) { 60for $f (@features) {
61 # print "Testing build with feature $f ...\n"; 61 # print "Testing build with feature $f ...\n";
62 open (O, ">Config.h") || die; 62 open (O, ">Config.h") || die;
63 print O $header, "#define BB_FEATURE_$f\n", $trailer; 63 print O $header, "#define CONFIG_FEATURE_$f\n", $trailer;
64 close O; 64 close O;
65 system("echo -e '\n***\n$f\n***' >>$logfile"); 65 system("echo -e '\n***\n$f\n***' >>$logfile");
66 # With a fast computer and 1-second resolution on file timestamps, this 66 # With a fast computer and 1-second resolution on file timestamps, this
diff --git a/tests/testcases b/tests/testcases
index 2aad9b651..2c28bf389 100644
--- a/tests/testcases
+++ b/tests/testcases
@@ -199,7 +199,7 @@ id -un
199 199
200 200
201# ifconfig 201# ifconfig
202# requires BB_FEATURE_IFCONFIG_STATUS 202# requires CONFIG_FEATURE_IFCONFIG_STATUS
203ifconfig 203ifconfig
204#ifconfig -a 204#ifconfig -a
205#ifconfig eth0 205#ifconfig eth0
diff --git a/tests/tester.sh b/tests/tester.sh
index a767c6c7f..09ba750ec 100755
--- a/tests/tester.sh
+++ b/tests/tester.sh
@@ -10,7 +10,7 @@
10BUSYBOX=../busybox 10BUSYBOX=../busybox
11TESTCASES=testcases 11TESTCASES=testcases
12LOGFILE=tester.log 12LOGFILE=tester.log
13BB_OUT=bb.out 13CONFIG_OUT=bb.out
14GNU_OUT=gnu.out 14GNU_OUT=gnu.out
15SETUP="" 15SETUP=""
16CLEANUP="" 16CLEANUP=""
@@ -25,7 +25,7 @@ do
25 p) BUSYBOX=$OPTARG; ;; 25 p) BUSYBOX=$OPTARG; ;;
26 t) TESTCASES=$OPTARG; ;; 26 t) TESTCASES=$OPTARG; ;;
27 l) LOGFILE=$OPTARG; ;; 27 l) LOGFILE=$OPTARG; ;;
28# b) BB_OUT=$OPTARG; ;; 28# b) CONFIG_OUT=$OPTARG; ;;
29# g) GNU_OUT=$OPTARG; ;; 29# g) GNU_OUT=$OPTARG; ;;
30 s) SETUP=$OPTARG; ;; 30 s) SETUP=$OPTARG; ;;
31 c) CLEANUP=$OPTARG; ;; 31 c) CLEANUP=$OPTARG; ;;
@@ -59,7 +59,7 @@ then
59 echo "BUSYBOX=$BUSYBOX" 59 echo "BUSYBOX=$BUSYBOX"
60 echo "TESTCASES=$TESTCASES" 60 echo "TESTCASES=$TESTCASES"
61 echo "LOGFILE=$LOGFILE" 61 echo "LOGFILE=$LOGFILE"
62 echo "BB_OUT=$BB_OUT" 62 echo "CONFIG_OUT=$CONFIG_OUT"
63 echo "GNU_OUT=$GNU_OUT" 63 echo "GNU_OUT=$GNU_OUT"
64 echo "SETUP=$SETUP" 64 echo "SETUP=$SETUP"
65 echo "CLEANUP=$CLEANUP" 65 echo "CLEANUP=$CLEANUP"
@@ -129,14 +129,14 @@ do
129 129
130 # execute line using busybox programs 130 # execute line using busybox programs
131 [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE 131 [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE
132 sh -c "$line" > $BB_OUT 132 sh -c "$line" > $CONFIG_OUT
133 133
134 # see if they match 134 # see if they match
135 diff -q $BB_OUT $GNU_OUT > /dev/null 135 diff -q $CONFIG_OUT $GNU_OUT > /dev/null
136 if [ $? -eq 1 ] 136 if [ $? -eq 1 ]
137 then 137 then
138 [ $DEBUG -ge 1 ] && echo "FAILED: $line" | tee -a $LOGFILE 138 [ $DEBUG -ge 1 ] && echo "FAILED: $line" | tee -a $LOGFILE
139 diff -u $BB_OUT $GNU_OUT >> $LOGFILE 139 diff -u $CONFIG_OUT $GNU_OUT >> $LOGFILE
140 fi 140 fi
141 fi 141 fi
142 fi 142 fi
@@ -147,7 +147,7 @@ done
147 147
148 148
149# do normal cleanup 149# do normal cleanup
150[ "$KEEPTMPFILES" = "no" ] && rm -f $BB_OUT $GNU_OUT 150[ "$KEEPTMPFILES" = "no" ] && rm -f $CONFIG_OUT $GNU_OUT
151 151
152 152
153# do extra cleanup (if any) 153# do extra cleanup (if any)
diff --git a/tftp.c b/tftp.c
deleted file mode 100644
index 530b3d134..000000000
--- a/tftp.c
+++ /dev/null
@@ -1,574 +0,0 @@
1/* ------------------------------------------------------------------------- */
2/* tftp.c */
3/* */
4/* A simple tftp client for busybox. */
5/* Tries to follow RFC1350. */
6/* Only "octet" mode supported. */
7/* Optional blocksize negotiation (RFC2347 + RFC2348) */
8/* */
9/* Copyright (C) 2001 Magnus Damm <damm@opensource.se> */
10/* */
11/* Parts of the code based on: */
12/* */
13/* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca> */
14/* and Remi Lefebvre <remi@debian.org> */
15/* */
16/* utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de> */
17/* */
18/* This program is free software; you can redistribute it and/or modify */
19/* it under the terms of the GNU General Public License as published by */
20/* the Free Software Foundation; either version 2 of the License, or */
21/* (at your option) any later version. */
22/* */
23/* This program is distributed in the hope that it will be useful, */
24/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
25/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
26/* General Public License for more details. */
27/* */
28/* You should have received a copy of the GNU General Public License */
29/* along with this program; if not, write to the Free Software */
30/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
31/* */
32/* ------------------------------------------------------------------------- */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <sys/time.h>
40#include <sys/stat.h>
41#include <netdb.h>
42#include <netinet/in.h>
43#include <arpa/inet.h>
44#include <unistd.h>
45#include <fcntl.h>
46
47#include "busybox.h"
48
49//#define BB_FEATURE_TFTP_DEBUG
50
51#define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
52#define TFTP_TIMEOUT 5 /* seconds */
53
54/* opcodes we support */
55
56#define TFTP_RRQ 1
57#define TFTP_WRQ 2
58#define TFTP_DATA 3
59#define TFTP_ACK 4
60#define TFTP_ERROR 5
61#define TFTP_OACK 6
62
63static const char *tftp_error_msg[] = {
64 "Undefined error",
65 "File not found",
66 "Access violation",
67 "Disk full or allocation error",
68 "Illegal TFTP operation",
69 "Unknown transfer ID",
70 "File already exists",
71 "No such user"
72};
73
74const int tftp_cmd_get = 1;
75const int tftp_cmd_put = 2;
76
77#ifdef BB_FEATURE_TFTP_BLOCKSIZE
78
79static int tftp_blocksize_check(int blocksize, int bufsize)
80{
81 /* Check if the blocksize is valid:
82 * RFC2348 says between 8 and 65464,
83 * but our implementation makes it impossible
84 * to use blocksizes smaller than 22 octets.
85 */
86
87 if ((bufsize && (blocksize > bufsize)) ||
88 (blocksize < 8) || (blocksize > 65464)) {
89 error_msg("bad blocksize");
90 return 0;
91 }
92
93 return blocksize;
94}
95
96static char *tftp_option_get(char *buf, int len, char *option)
97{
98 int opt_val = 0;
99 int opt_found = 0;
100 int k;
101
102 while (len > 0) {
103
104 /* Make sure the options are terminated correctly */
105
106 for (k = 0; k < len; k++) {
107 if (buf[k] == '\0') {
108 break;
109 }
110 }
111
112 if (k >= len) {
113 break;
114 }
115
116 if (opt_val == 0) {
117 if (strcasecmp(buf, option) == 0) {
118 opt_found = 1;
119 }
120 }
121 else {
122 if (opt_found) {
123 return buf;
124 }
125 }
126
127 k++;
128
129 buf += k;
130 len -= k;
131
132 opt_val ^= 1;
133 }
134
135 return NULL;
136}
137
138#endif
139
140static inline int tftp(const int cmd, const struct hostent *host,
141 const char *remotefile, int localfd, const int port, int tftp_bufsize)
142{
143 const int cmd_get = cmd & tftp_cmd_get;
144 const int cmd_put = cmd & tftp_cmd_put;
145 const int bb_tftp_num_retries = 5;
146
147 struct sockaddr_in sa;
148 struct sockaddr_in from;
149 struct timeval tv;
150 socklen_t fromlen;
151 fd_set rfds;
152 char *cp;
153 unsigned short tmp;
154 int socketfd;
155 int len;
156 int opcode = 0;
157 int finished = 0;
158 int timeout = bb_tftp_num_retries;
159 int block_nr = 1;
160
161#ifdef BB_FEATURE_TFTP_BLOCKSIZE
162 int want_option_ack = 0;
163#endif
164
165 RESERVE_BB_BUFFER(buf, tftp_bufsize + 4); /* Opcode + Block # + Data */
166
167 tftp_bufsize += 4;
168
169 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
170 perror_msg("socket");
171 return EXIT_FAILURE;
172 }
173
174 len = sizeof(sa);
175
176 memset(&sa, 0, len);
177 bind(socketfd, (struct sockaddr *)&sa, len);
178
179 sa.sin_family = host->h_addrtype;
180 sa.sin_port = htons(port);
181 memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
182 sizeof(sa.sin_addr));
183
184 /* build opcode */
185
186 if (cmd_get) {
187 opcode = TFTP_RRQ;
188 }
189
190 if (cmd_put) {
191 opcode = TFTP_WRQ;
192 }
193
194 while (1) {
195
196 cp = buf;
197
198 /* first create the opcode part */
199
200 *((unsigned short *) cp) = htons(opcode);
201
202 cp += 2;
203
204 /* add filename and mode */
205
206 if ((cmd_get && (opcode == TFTP_RRQ)) ||
207 (cmd_put && (opcode == TFTP_WRQ))) {
208 int too_long = 0;
209
210 /* see if the filename fits into buf */
211 /* and fill in packet */
212
213 len = strlen(remotefile) + 1;
214
215 if ((cp + len) >= &buf[tftp_bufsize - 1]) {
216 too_long = 1;
217 }
218 else {
219 safe_strncpy(cp, remotefile, len);
220 cp += len;
221 }
222
223 if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) {
224 error_msg("too long remote-filename");
225 break;
226 }
227
228 /* add "mode" part of the package */
229
230 memcpy(cp, "octet", 6);
231 cp += 6;
232
233#ifdef BB_FEATURE_TFTP_BLOCKSIZE
234
235 len = tftp_bufsize - 4; /* data block size */
236
237 if (len != TFTP_BLOCKSIZE_DEFAULT) {
238
239 if ((&buf[tftp_bufsize - 1] - cp) < 15) {
240 error_msg("too long remote-filename");
241 break;
242 }
243
244 /* add "blksize" + number of blocks */
245
246 memcpy(cp, "blksize", 8);
247 cp += 8;
248
249 cp += snprintf(cp, 6, "%d", len) + 1;
250
251 want_option_ack = 1;
252 }
253#endif
254 }
255
256 /* add ack and data */
257
258 if ((cmd_get && (opcode == TFTP_ACK)) ||
259 (cmd_put && (opcode == TFTP_DATA))) {
260
261 *((unsigned short *) cp) = htons(block_nr);
262
263 cp += 2;
264
265 block_nr++;
266
267 if (cmd_put && (opcode == TFTP_DATA)) {
268 len = read(localfd, cp, tftp_bufsize - 4);
269
270 if (len < 0) {
271 perror_msg("read");
272 break;
273 }
274
275 if (len != (tftp_bufsize - 4)) {
276 finished++;
277 }
278
279 cp += len;
280 } else if (finished) {
281 break;
282 }
283 }
284
285
286 /* send packet */
287
288
289 do {
290
291 len = cp - buf;
292
293#ifdef BB_FEATURE_TFTP_DEBUG
294 printf("sending %u bytes\n", len);
295 for (cp = buf; cp < &buf[len]; cp++)
296 printf("%02x ", *cp);
297 printf("\n");
298#endif
299 if (sendto(socketfd, buf, len, 0,
300 (struct sockaddr *) &sa, sizeof(sa)) < 0) {
301 perror_msg("send");
302 len = -1;
303 break;
304 }
305
306
307 /* receive packet */
308
309
310 memset(&from, 0, sizeof(from));
311 fromlen = sizeof(from);
312
313 tv.tv_sec = TFTP_TIMEOUT;
314 tv.tv_usec = 0;
315
316 FD_ZERO(&rfds);
317 FD_SET(socketfd, &rfds);
318
319 switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
320 case 1:
321 len = recvfrom(socketfd, buf, tftp_bufsize, 0,
322 (struct sockaddr *) &from, &fromlen);
323
324 if (len < 0) {
325 perror_msg("recvfrom");
326 break;
327 }
328
329 timeout = 0;
330
331 if (sa.sin_port == htons(port)) {
332 sa.sin_port = from.sin_port;
333 }
334 if (sa.sin_port == from.sin_port) {
335 break;
336 }
337
338 /* fall-through for bad packets! */
339 /* discard the packet - treat as timeout */
340 timeout = bb_tftp_num_retries;
341
342 case 0:
343 error_msg("timeout");
344
345 if (timeout == 0) {
346 len = -1;
347 error_msg("last timeout");
348 } else {
349 timeout--;
350 }
351 break;
352
353 default:
354 perror_msg("select");
355 len = -1;
356 }
357
358 } while (timeout && (len >= 0));
359
360 if (len < 0) {
361 break;
362 }
363
364 /* process received packet */
365
366
367 opcode = ntohs(*((unsigned short *) buf));
368 tmp = ntohs(*((unsigned short *) &buf[2]));
369
370#ifdef BB_FEATURE_TFTP_DEBUG
371 printf("received %d bytes: %04x %04x\n", len, opcode, tmp);
372#endif
373
374 if (opcode == TFTP_ERROR) {
375 char *msg = NULL;
376
377 if (buf[4] != '\0') {
378 msg = &buf[4];
379 buf[tftp_bufsize - 1] = '\0';
380 } else if (tmp < (sizeof(tftp_error_msg)
381 / sizeof(char *))) {
382
383 msg = (char *) tftp_error_msg[tmp];
384 }
385
386 if (msg) {
387 error_msg("server says: %s", msg);
388 }
389
390 break;
391 }
392
393#ifdef BB_FEATURE_TFTP_BLOCKSIZE
394 if (want_option_ack) {
395
396 want_option_ack = 0;
397
398 if (opcode == TFTP_OACK) {
399
400 /* server seems to support options */
401
402 char *res;
403
404 res = tftp_option_get(&buf[2], len-2,
405 "blksize");
406
407 if (res) {
408 int foo = atoi(res);
409
410 if (tftp_blocksize_check(foo,
411 tftp_bufsize - 4)) {
412
413 if (cmd_put) {
414 opcode = TFTP_DATA;
415 }
416 else {
417 opcode = TFTP_ACK;
418 }
419#ifdef BB_FEATURE_TFTP_DEBUG
420 printf("using blksize %u\n");
421#endif
422 tftp_bufsize = foo + 4;
423 block_nr = 0;
424 continue;
425 }
426 }
427 /* FIXME:
428 * we should send ERROR 8 */
429 error_msg("bad server option");
430 break;
431 }
432
433 error_msg("warning: blksize not supported by server"
434 " - reverting to 512");
435
436 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
437 }
438#endif
439
440 if (cmd_get && (opcode == TFTP_DATA)) {
441
442 if (tmp == block_nr) {
443
444 len = write(localfd, &buf[4], len - 4);
445
446 if (len < 0) {
447 perror_msg("write");
448 break;
449 }
450
451 if (len != (tftp_bufsize - 4)) {
452 finished++;
453 }
454
455 opcode = TFTP_ACK;
456 continue;
457 }
458 }
459
460 if (cmd_put && (opcode == TFTP_ACK)) {
461
462 if (tmp == (block_nr - 1)) {
463 if (finished) {
464 break;
465 }
466
467 opcode = TFTP_DATA;
468 continue;
469 }
470 }
471 }
472
473#ifdef BB_FEATURE_CLEAN_UP
474 close(socketfd);
475
476 RELEASE_BB_BUFFER(buf);
477#endif
478
479 return finished ? EXIT_SUCCESS : EXIT_FAILURE;
480}
481
482int tftp_main(int argc, char **argv)
483{
484 struct hostent *host = NULL;
485 char *localfile = NULL;
486 char *remotefile = NULL;
487 int port = 69;
488 int cmd = 0;
489 int fd = -1;
490 int flags = 0;
491 int opt;
492 int result;
493 int blocksize = TFTP_BLOCKSIZE_DEFAULT;
494
495 /* figure out what to pass to getopt */
496
497#ifdef BB_FEATURE_TFTP_BLOCKSIZE
498#define BS "b:"
499#else
500#define BS
501#endif
502
503#ifdef BB_FEATURE_TFTP_GET
504#define GET "g"
505#else
506#define GET
507#endif
508
509#ifdef BB_FEATURE_TFTP_PUT
510#define PUT "p"
511#else
512#define PUT
513#endif
514
515 while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) {
516 switch (opt) {
517#ifdef BB_FEATURE_TFTP_BLOCKSIZE
518 case 'b':
519 blocksize = atoi(optarg);
520 if (!tftp_blocksize_check(blocksize, 0)) {
521 return EXIT_FAILURE;
522 }
523 break;
524#endif
525#ifdef BB_FEATURE_TFTP_GET
526 case 'g':
527 cmd = tftp_cmd_get;
528 flags = O_WRONLY | O_CREAT;
529 break;
530#endif
531#ifdef BB_FEATURE_TFTP_PUT
532 case 'p':
533 cmd = tftp_cmd_put;
534 flags = O_RDONLY;
535 break;
536#endif
537 case 'l':
538 localfile = xstrdup(optarg);
539 break;
540 case 'r':
541 remotefile = xstrdup(optarg);
542 break;
543 }
544 }
545
546 if ((cmd == 0) || (optind == argc)) {
547 show_usage();
548 }
549
550 fd = open(localfile, flags, 0644);
551 if (fd < 0) {
552 perror_msg_and_die("local file");
553 }
554
555 host = xgethostbyname(argv[optind]);
556
557 if (optind + 2 == argc) {
558 port = atoi(argv[optind + 1]);
559 }
560
561#ifdef BB_FEATURE_TFTP_DEBUG
562 printf("using server \"%s\", remotefile \"%s\", "
563 "localfile \"%s\".\n",
564 inet_ntoa(*((struct in_addr *) host->h_addr)),
565 remotefile, localfile);
566#endif
567
568 result = tftp(cmd, host, remotefile, fd, port, blocksize);
569
570#ifdef BB_FEATURE_CLEAN_UP
571 close(fd);
572#endif
573 return(result);
574}
diff --git a/touch.c b/touch.c
deleted file mode 100644
index 1718da71e..000000000
--- a/touch.c
+++ /dev/null
@@ -1,75 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini touch implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <stdio.h>
26#include <sys/types.h>
27#include <fcntl.h>
28#include <utime.h>
29#include <errno.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include "busybox.h"
33
34extern int touch_main(int argc, char **argv)
35{
36 int fd;
37 int create = TRUE;
38
39 /* Parse options */
40 while (--argc > 0 && **(++argv) == '-') {
41 while (*(++(*argv))) {
42 switch (**argv) {
43 case 'c':
44 create = FALSE;
45 break;
46 default:
47 show_usage();
48 }
49 }
50 }
51
52 if (argc < 1) {
53 show_usage();
54 }
55
56 while (argc > 0) {
57 fd = open(*argv, (create == FALSE) ? O_RDWR : O_RDWR | O_CREAT,
58 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
59 if (fd < 0) {
60 if (create == FALSE && errno == ENOENT)
61 return EXIT_SUCCESS;
62 else {
63 perror_msg_and_die("%s", *argv);
64 }
65 }
66 close(fd);
67 if (utime(*argv, NULL)) {
68 perror_msg_and_die("%s", *argv);
69 }
70 argc--;
71 argv++;
72 }
73
74 return EXIT_SUCCESS;
75}
diff --git a/tr.c b/tr.c
deleted file mode 100644
index 5b7b8d091..000000000
--- a/tr.c
+++ /dev/null
@@ -1,248 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini tr implementation for busybox
4 *
5 * Copyright (c) Michiel Huisjes
6 *
7 * This version of tr is adapted from Minix tr and was modified
8 * by Erik Andersen <andersee@debian.org> to be used in busybox.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Original copyright notice is retained at the end of this file.
25 */
26
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <sys/types.h>
32#include "busybox.h"
33
34/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
35 * enabled, we otherwise get a "storage size isn't constant error. */
36#define ASCII 0377
37
38/* some "globals" shared across this file */
39static char com_fl, del_fl, sq_fl;
40static short in_index, out_index;
41/* these last are pointers to static buffers declared in tr_main */
42static unsigned char *poutput, *pinput;
43static unsigned char *pvector;
44static char *pinvec, *poutvec;
45
46
47static void convert()
48{
49 short read_chars = 0;
50 short c, coded;
51 short last = -1;
52
53 for (;;) {
54 if (in_index == read_chars) {
55 if ((read_chars = read(0, (char *) pinput, BUFSIZ)) <= 0) {
56 if (write(1, (char *) poutput, out_index) != out_index)
57 error_msg("%s", write_error);
58 exit(0);
59 }
60 in_index = 0;
61 }
62 c = pinput[in_index++];
63 coded = pvector[c];
64 if (del_fl && pinvec[c])
65 continue;
66 if (sq_fl && last == coded && (pinvec[c] || poutvec[coded]))
67 continue;
68 poutput[out_index++] = last = coded;
69 if (out_index == BUFSIZ) {
70 if (write(1, (char *) poutput, out_index) != out_index)
71 error_msg_and_die("%s", write_error);
72 out_index = 0;
73 }
74 }
75
76 /* NOTREACHED */
77}
78
79static void map(register unsigned char *string1, unsigned int string1_len,
80 register unsigned char *string2, unsigned int string2_len)
81{
82 unsigned char last = '0';
83 unsigned int i, j;
84
85 for (j = 0, i = 0; i < string1_len; i++) {
86 if (string2_len <= j)
87 pvector[string1[i]] = last;
88 else
89 pvector[string1[i]] = last = string2[j++];
90 }
91}
92
93/* supported constructs:
94 * Ranges, e.g., [0-9] ==> 0123456789
95 * Escapes, e.g., \a ==> Control-G
96 */
97static unsigned int expand(const char *arg, register unsigned char *buffer)
98{
99 unsigned char *buffer_start = buffer;
100 int i, ac;
101
102 while (*arg) {
103 if (*arg == '\\') {
104 arg++;
105 *buffer++ = process_escape_sequence(&arg);
106 } else if (*(arg+1) == '-') {
107 ac = *(arg+2);
108 if(ac == 0) {
109 *buffer++ = *arg++;
110 continue;
111 }
112 i = *arg;
113 while (i <= ac)
114 *buffer++ = i++;
115 arg += 3; /* Skip the assumed a-z */
116 } else if (*arg == '[') {
117 arg++;
118 i = *arg++;
119 if (*arg++ != '-') {
120 *buffer++ = '[';
121 arg -= 2;
122 continue;
123 }
124 ac = *arg++;
125 while (i <= ac)
126 *buffer++ = i++;
127 arg++; /* Skip the assumed ']' */
128 } else
129 *buffer++ = *arg++;
130 }
131
132 return (buffer - buffer_start);
133}
134
135static int complement(unsigned char *buffer, int buffer_len)
136{
137 register short i, j, ix;
138 char conv[ASCII + 2];
139
140 ix = 0;
141 for (i = 0; i <= ASCII; i++) {
142 for (j = 0; j < buffer_len; j++)
143 if (buffer[j] == i)
144 break;
145 if (j == buffer_len)
146 conv[ix++] = i & ASCII;
147 }
148 memcpy(buffer, conv, ix);
149 return ix;
150}
151
152extern int tr_main(int argc, char **argv)
153{
154 register unsigned char *ptr;
155 int output_length=0, input_length;
156 int idx = 1;
157 int i;
158 RESERVE_BB_BUFFER(output, BUFSIZ);
159 RESERVE_BB_BUFFER(input, BUFSIZ);
160 RESERVE_BB_UBUFFER(vector, ASCII+1);
161 RESERVE_BB_BUFFER(invec, ASCII+1);
162 RESERVE_BB_BUFFER(outvec, ASCII+1);
163
164 /* ... but make them available globally */
165 poutput = output;
166 pinput = input;
167 pvector = vector;
168 pinvec = invec;
169 poutvec = outvec;
170
171 if (argc > 1 && argv[idx][0] == '-') {
172 for (ptr = (unsigned char *) &argv[idx][1]; *ptr; ptr++) {
173 switch (*ptr) {
174 case 'c':
175 com_fl = TRUE;
176 break;
177 case 'd':
178 del_fl = TRUE;
179 break;
180 case 's':
181 sq_fl = TRUE;
182 break;
183 default:
184 show_usage();
185 }
186 }
187 idx++;
188 }
189 for (i = 0; i <= ASCII; i++) {
190 vector[i] = i;
191 invec[i] = outvec[i] = FALSE;
192 }
193
194 if (argv[idx] != NULL) {
195 input_length = expand(argv[idx++], input);
196 if (com_fl)
197 input_length = complement(input, input_length);
198 if (argv[idx] != NULL) {
199 if (*argv[idx] == '\0')
200 error_msg_and_die("STRING2 cannot be empty");
201 output_length = expand(argv[idx], output);
202 map(input, input_length, output, output_length);
203 }
204 for (i = 0; i < input_length; i++)
205 invec[(int)input[i]] = TRUE;
206 for (i = 0; i < output_length; i++)
207 outvec[(int)output[i]] = TRUE;
208 }
209 convert();
210 return (0);
211}
212
213/*
214 * Copyright (c) 1987,1997, Prentice Hall
215 * All rights reserved.
216 *
217 * Redistribution and use of the MINIX operating system in source and
218 * binary forms, with or without modification, are permitted provided
219 * that the following conditions are met:
220 *
221 * Redistributions of source code must retain the above copyright
222 * notice, this list of conditions and the following disclaimer.
223 *
224 * Redistributions in binary form must reproduce the above
225 * copyright notice, this list of conditions and the following
226 * disclaimer in the documentation and/or other materials provided
227 * with the distribution.
228 *
229 * Neither the name of Prentice Hall nor the names of the software
230 * authors or contributors may be used to endorse or promote
231 * products derived from this software without specific prior
232 * written permission.
233 *
234 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
235 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
236 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
237 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
238 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
239 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
240 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
241 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
242 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
243 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
244 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
245 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
246 *
247 */
248
diff --git a/traceroute.c b/traceroute.c
deleted file mode 100644
index a3abd0a00..000000000
--- a/traceroute.c
+++ /dev/null
@@ -1,652 +0,0 @@
1/*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Van Jacobson.
7 *
8 * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38/*
39 * traceroute host - trace the route ip packets follow going to "host".
40 * Notes
41 * -----
42 * This program must be run by root or be setuid. (I suggest that
43 * you *don't* make it setuid -- casual use could result in a lot
44 * of unnecessary traffic on our poor, congested nets.)
45 *
46 * I stole the idea for this program from Steve Deering. Since
47 * the first release, I've learned that had I attended the right
48 * IETF working group meetings, I also could have stolen it from Guy
49 * Almes or Matt Mathis. I don't know (or care) who came up with
50 * the idea first. I envy the originators' perspicacity and I'm
51 * glad they didn't keep the idea a secret.
52 *
53 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
54 * enhancements to the original distribution.
55 *
56 * I've hacked up a round-trip-route version of this that works by
57 * sending a loose-source-routed udp datagram through the destination
58 * back to yourself. Unfortunately, SO many gateways botch source
59 * routing, the thing is almost worthless. Maybe one day...
60 *
61 * -- Van Jacobson (van@helios.ee.lbl.gov)
62 * Tue Dec 20 03:50:13 PST 1988
63 */
64
65#undef BB_FEATURE_TRACEROUTE_VERBOSE
66//#define BB_FEATURE_TRACEROUTE_VERBOSE
67#undef BB_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
68
69#include <stdio.h>
70#include <errno.h>
71#include <stdlib.h>
72#include <string.h>
73#include <unistd.h>
74#include <sys/time.h>
75#include <sys/types.h>
76#include <sys/socket.h>
77#include <netdb.h>
78#include <endian.h>
79#include <arpa/inet.h>
80#include <netinet/udp.h>
81#include <netinet/ip.h>
82#include <netinet/ip_icmp.h>
83
84
85 /* It turns out that libc5 doesn't have proper icmp support
86 * built into it header files, so we have to supplement it */
87#if __GNU_LIBRARY__ < 5
88static const int ICMP_MINLEN = 8; /* abs minimum */
89
90struct icmp_ra_addr
91{
92 u_int32_t ira_addr;
93 u_int32_t ira_preference;
94};
95
96
97struct icmp
98{
99 u_int8_t icmp_type; /* type of message, see below */
100 u_int8_t icmp_code; /* type sub code */
101 u_int16_t icmp_cksum; /* ones complement checksum of struct */
102 union
103 {
104 u_char ih_pptr; /* ICMP_PARAMPROB */
105 struct in_addr ih_gwaddr; /* gateway address */
106 struct ih_idseq /* echo datagram */
107 {
108 u_int16_t icd_id;
109 u_int16_t icd_seq;
110 } ih_idseq;
111 u_int32_t ih_void;
112
113 /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
114 struct ih_pmtu
115 {
116 u_int16_t ipm_void;
117 u_int16_t ipm_nextmtu;
118 } ih_pmtu;
119
120 struct ih_rtradv
121 {
122 u_int8_t irt_num_addrs;
123 u_int8_t irt_wpa;
124 u_int16_t irt_lifetime;
125 } ih_rtradv;
126 } icmp_hun;
127#define icmp_pptr icmp_hun.ih_pptr
128#define icmp_gwaddr icmp_hun.ih_gwaddr
129#define icmp_id icmp_hun.ih_idseq.icd_id
130#define icmp_seq icmp_hun.ih_idseq.icd_seq
131#define icmp_void icmp_hun.ih_void
132#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
133#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
134#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
135#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
136#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
137 union
138 {
139 struct
140 {
141 u_int32_t its_otime;
142 u_int32_t its_rtime;
143 u_int32_t its_ttime;
144 } id_ts;
145 struct
146 {
147 struct ip idi_ip;
148 /* options and then 64 bits of data */
149 } id_ip;
150 struct icmp_ra_addr id_radv;
151 u_int32_t id_mask;
152 u_int8_t id_data[1];
153 } icmp_dun;
154#define icmp_otime icmp_dun.id_ts.its_otime
155#define icmp_rtime icmp_dun.id_ts.its_rtime
156#define icmp_ttime icmp_dun.id_ts.its_ttime
157#define icmp_ip icmp_dun.id_ip.idi_ip
158#define icmp_radv icmp_dun.id_radv
159#define icmp_mask icmp_dun.id_mask
160#define icmp_data icmp_dun.id_data
161};
162
163#define ICMP_MINLEN 8 /* abs minimum */
164#define ICMP_UNREACH 3 /* dest unreachable, codes: */
165#define ICMP_TIMXCEED 11 /* time exceeded, code: */
166#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
167#define ICMP_UNREACH_NET 0 /* bad net */
168#define ICMP_UNREACH_HOST 1 /* bad host */
169#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
170#define ICMP_UNREACH_PORT 3 /* bad port */
171#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
172#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
173#endif
174
175
176#define MAXPACKET 65535 /* max ip packet size */
177#ifndef MAXHOSTNAMELEN
178#define MAXHOSTNAMELEN 64
179#endif
180
181/*
182 * format of a (udp) probe packet.
183 */
184struct opacket {
185 struct ip ip;
186 struct udphdr udp;
187 u_char seq; /* sequence number of this packet */
188 u_char ttl; /* ttl packet left with */
189 struct timeval tv; /* time packet left */
190};
191
192/*
193 * Definitions for internet protocol version 4.
194 * Per RFC 791, September 1981.
195 */
196#define IPVERSION 4
197
198
199#include "busybox.h"
200
201static u_char packet[512]; /* last inbound (icmp) packet */
202static struct opacket *outpacket; /* last output (udp) packet */
203
204static int s; /* receive (icmp) socket file descriptor */
205static int sndsock; /* send (udp) socket file descriptor */
206
207static struct sockaddr whereto; /* Who to try to reach */
208static int datalen; /* How much data */
209
210static char *hostname;
211
212static int max_ttl = 30;
213static u_short ident;
214static u_short port = 32768+666; /* start udp dest port # for probe packets */
215
216#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
217static int verbose;
218#endif
219static int waittime = 5; /* time to wait for response (in seconds) */
220static int nflag; /* print addresses numerically */
221
222/*
223 * Construct an Internet address representation.
224 * If the nflag has been supplied, give
225 * numeric value, otherwise try for symbolic name.
226 */
227static inline void
228inetname(struct sockaddr_in *from)
229{
230 char *cp;
231 struct hostent *hp;
232 static char domain[MAXHOSTNAMELEN + 1];
233 static int first = 1;
234 const char *ina;
235
236 if (first && !nflag) {
237 first = 0;
238 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
239 (cp = strchr(domain, '.')))
240 (void) strcpy(domain, cp + 1);
241 else
242 domain[0] = 0;
243 }
244 cp = 0;
245 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
246 hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET);
247 if (hp) {
248 if ((cp = strchr(hp->h_name, '.')) &&
249 !strcmp(cp + 1, domain))
250 *cp = 0;
251 cp = (char *)hp->h_name;
252 }
253 }
254 ina = inet_ntoa(from->sin_addr);
255 if (nflag)
256 printf(" %s", ina);
257 else
258 printf(" %s (%s)", (cp ? cp : ina), ina);
259}
260
261static inline void
262print(u_char *buf, int cc, struct sockaddr_in *from)
263{
264 struct ip *ip;
265 int hlen;
266
267 ip = (struct ip *) buf;
268 hlen = ip->ip_hl << 2;
269 cc -= hlen;
270
271 inetname(from);
272#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
273 if (verbose)
274 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
275#endif
276}
277
278static inline double
279deltaT(struct timeval *t1p, struct timeval *t2p)
280{
281 double dt;
282
283 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
284 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
285 return (dt);
286}
287
288static inline int
289wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
290{
291 fd_set fds;
292 static struct timeval wait;
293 int cc = 0;
294 int fromlen = sizeof (*from);
295
296 FD_ZERO(&fds);
297 FD_SET(sock, &fds);
298 if (reset_timer) {
299 /*
300 * traceroute could hang if someone else has a ping
301 * running and our ICMP reply gets dropped but we don't
302 * realize it because we keep waking up to handle those
303 * other ICMP packets that keep coming in. To fix this,
304 * "reset_timer" will only be true if the last packet that
305 * came in was for us or if this is the first time we're
306 * waiting for a reply since sending out a probe. Note
307 * that this takes advantage of the select() feature on
308 * Linux where the remaining timeout is written to the
309 * struct timeval area.
310 */
311 wait.tv_sec = waittime;
312 wait.tv_usec = 0;
313 }
314
315 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
316 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
317 (struct sockaddr *)from, &fromlen);
318
319 return(cc);
320}
321
322#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
323/*
324 * Convert an ICMP "type" field to a printable string.
325 */
326static inline const char *
327pr_type(t)
328 u_char t;
329{
330 static const char * const ttab[] = {
331 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
332 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
333 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
334 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
335 "Info Reply"
336 };
337
338 if(t > 16)
339 return("OUT-OF-RANGE");
340
341 return(ttab[t]);
342}
343#endif
344
345static inline int
346packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
347{
348 struct icmp *icp;
349 u_char type, code;
350 int hlen;
351 struct ip *ip;
352
353 ip = (struct ip *) buf;
354 hlen = ip->ip_hl << 2;
355 if (cc < hlen + ICMP_MINLEN) {
356#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
357 if (verbose)
358 printf("packet too short (%d bytes) from %s\n", cc,
359 inet_ntoa(from->sin_addr));
360#endif
361 return (0);
362 }
363 cc -= hlen;
364 icp = (struct icmp *)(buf + hlen);
365 type = icp->icmp_type; code = icp->icmp_code;
366 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
367 type == ICMP_UNREACH) {
368 struct ip *hip;
369 struct udphdr *up;
370
371 hip = &icp->icmp_ip;
372 hlen = hip->ip_hl << 2;
373 up = (struct udphdr *)((u_char *)hip + hlen);
374 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
375 up->source == htons(ident) &&
376 up->dest == htons(port+seq))
377 return (type == ICMP_TIMXCEED? -1 : code+1);
378 }
379#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
380 if (verbose) {
381 int i;
382 u_long *lp = (u_long *)&icp->icmp_ip;
383
384 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
385 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
386 type, pr_type(type), icp->icmp_code);
387 for (i = 4; i < cc ; i += sizeof(long))
388 printf("%2d: x%8.8lx\n", i, *lp++);
389 }
390#endif
391 return(0);
392}
393
394static void /* not inline */
395send_probe(int seq, int ttl)
396{
397 struct opacket *op = outpacket;
398 struct ip *ip = &op->ip;
399 struct udphdr *up = &op->udp;
400 int i;
401 struct timezone tz;
402
403 ip->ip_off = 0;
404 ip->ip_hl = sizeof(*ip) >> 2;
405 ip->ip_p = IPPROTO_UDP;
406 ip->ip_len = datalen;
407 ip->ip_ttl = ttl;
408 ip->ip_v = IPVERSION;
409 ip->ip_id = htons(ident+seq);
410
411 up->source = htons(ident);
412 up->dest = htons(port+seq);
413 up->len = htons((u_short)(datalen - sizeof(struct ip)));
414 up->check = 0;
415
416 op->seq = seq;
417 op->ttl = ttl;
418 (void) gettimeofday(&op->tv, &tz);
419
420 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
421 sizeof(struct sockaddr));
422 if (i < 0 || i != datalen) {
423 if (i<0)
424 perror("sendto");
425 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
426 datalen, i);
427 (void) fflush(stdout);
428 }
429}
430
431
432int
433#ifndef BB_TRACEROUTE
434main(argc, argv)
435#else
436traceroute_main(argc, argv)
437#endif
438 int argc;
439 char *argv[];
440{
441 extern char *optarg;
442 extern int optind;
443 struct hostent *hp;
444 struct sockaddr_in from, *to;
445 int ch, i, on, probe, seq, tos, ttl;
446
447 int options = 0; /* socket options */
448 char *source = 0;
449 int nprobes = 3;
450
451 on = 1;
452 seq = tos = 0;
453 to = (struct sockaddr_in *)&whereto;
454 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
455 switch(ch) {
456 case 'd':
457#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
458 options |= SO_DEBUG;
459#endif
460 break;
461 case 'm':
462 max_ttl = atoi(optarg);
463 if (max_ttl <= 1)
464 error_msg_and_die("max ttl must be >1.");
465 break;
466 case 'n':
467 nflag++;
468 break;
469 case 'p':
470 port = atoi(optarg);
471 if (port < 1)
472 error_msg_and_die("port must be >0.");
473 break;
474 case 'q':
475 nprobes = atoi(optarg);
476 if (nprobes < 1)
477 error_msg_and_die("nprobes must be >0.");
478 break;
479 case 'r':
480 options |= SO_DONTROUTE;
481 break;
482 case 's':
483 /*
484 * set the ip source address of the outbound
485 * probe (e.g., on a multi-homed host).
486 */
487 source = optarg;
488 break;
489 case 't':
490 tos = atoi(optarg);
491 if (tos < 0 || tos > 255)
492 error_msg_and_die("tos must be 0 to 255.");
493 break;
494 case 'v':
495#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
496 verbose++;
497#endif
498 break;
499 case 'w':
500 waittime = atoi(optarg);
501 if (waittime <= 1)
502 error_msg_and_die("wait must be >1 sec.");
503 break;
504 default:
505 show_usage();
506 }
507 argc -= optind;
508 argv += optind;
509
510 if (argc < 1)
511 show_usage();
512
513 setlinebuf (stdout);
514
515 memset(&whereto, 0, sizeof(struct sockaddr));
516 hp = xgethostbyname(*argv);
517 to->sin_family = hp->h_addrtype;
518 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
519 hostname = (char *)hp->h_name;
520 if (*++argv)
521 datalen = atoi(*argv);
522 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
523 error_msg_and_die("packet size must be 0 <= s < %d.",
524 MAXPACKET - sizeof(struct opacket));
525 datalen += sizeof(struct opacket);
526 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
527 memset(outpacket, 0, datalen);
528 outpacket->ip.ip_dst = to->sin_addr;
529 outpacket->ip.ip_tos = tos;
530 outpacket->ip.ip_v = IPVERSION;
531 outpacket->ip.ip_id = 0;
532
533 ident = (getpid() & 0xffff) | 0x8000;
534
535 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
536 perror_msg_and_die(can_not_create_raw_socket);
537
538 s = create_icmp_socket();
539
540#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
541 if (options & SO_DEBUG)
542 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
543 (char *)&on, sizeof(on));
544#endif
545 if (options & SO_DONTROUTE)
546 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
547 (char *)&on, sizeof(on));
548#ifdef SO_SNDBUF
549 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
550 sizeof(datalen)) < 0)
551 perror_msg_and_die("SO_SNDBUF");
552#endif SO_SNDBUF
553#ifdef IP_HDRINCL
554 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
555 sizeof(on)) < 0)
556 perror_msg_and_die("IP_HDRINCL");
557#endif IP_HDRINCL
558#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
559 if (options & SO_DEBUG)
560 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
561 (char *)&on, sizeof(on));
562#endif
563 if (options & SO_DONTROUTE)
564 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
565 (char *)&on, sizeof(on));
566
567 if (source) {
568 memset(&from, 0, sizeof(struct sockaddr));
569 from.sin_family = AF_INET;
570 from.sin_addr.s_addr = inet_addr(source);
571 if (from.sin_addr.s_addr == -1)
572 error_msg_and_die("unknown host %s", source);
573 outpacket->ip.ip_src = from.sin_addr;
574#ifndef IP_HDRINCL
575 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
576 perror_msg_and_die("bind");
577#endif IP_HDRINCL
578 }
579
580 fprintf(stderr, "traceroute to %s (%s)", hostname,
581 inet_ntoa(to->sin_addr));
582 if (source)
583 fprintf(stderr, " from %s", source);
584 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
585
586 for (ttl = 1; ttl <= max_ttl; ++ttl) {
587 u_long lastaddr = 0;
588 int got_there = 0;
589 int unreachable = 0;
590
591 printf("%2d ", ttl);
592 for (probe = 0; probe < nprobes; ++probe) {
593 int cc, reset_timer;
594 struct timeval t1, t2;
595 struct timezone tz;
596 struct ip *ip;
597
598 (void) gettimeofday(&t1, &tz);
599 send_probe(++seq, ttl);
600 reset_timer = 1;
601 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
602 (void) gettimeofday(&t2, &tz);
603 if ((i = packet_ok(packet, cc, &from, seq))) {
604 reset_timer = 1;
605 if (from.sin_addr.s_addr != lastaddr) {
606 print(packet, cc, &from);
607 lastaddr = from.sin_addr.s_addr;
608 }
609 printf(" %g ms", deltaT(&t1, &t2));
610 switch(i - 1) {
611 case ICMP_UNREACH_PORT:
612 ip = (struct ip *)packet;
613 if (ip->ip_ttl <= 1)
614 printf(" !");
615 ++got_there;
616 break;
617 case ICMP_UNREACH_NET:
618 ++unreachable;
619 printf(" !N");
620 break;
621 case ICMP_UNREACH_HOST:
622 ++unreachable;
623 printf(" !H");
624 break;
625 case ICMP_UNREACH_PROTOCOL:
626 ++got_there;
627 printf(" !P");
628 break;
629 case ICMP_UNREACH_NEEDFRAG:
630 ++unreachable;
631 printf(" !F");
632 break;
633 case ICMP_UNREACH_SRCFAIL:
634 ++unreachable;
635 printf(" !S");
636 break;
637 }
638 break;
639 } else
640 reset_timer = 0;
641 }
642 if (cc == 0)
643 printf(" *");
644 (void) fflush(stdout);
645 }
646 putchar('\n');
647 if (got_there || unreachable >= nprobes-1)
648 exit(0);
649 }
650
651 return 0;
652}
diff --git a/true_false.c b/true_false.c
deleted file mode 100644
index 76183431c..000000000
--- a/true_false.c
+++ /dev/null
@@ -1,39 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini true/false implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25/* getopt not needed */
26
27#include <stdlib.h>
28#include "busybox.h"
29
30
31extern int true_main(int argc, char **argv)
32{
33 return EXIT_SUCCESS;
34}
35
36extern int false_main(int argc, char **argv)
37{
38 return EXIT_FAILURE;
39}
diff --git a/tty.c b/tty.c
deleted file mode 100644
index 4510c2996..000000000
--- a/tty.c
+++ /dev/null
@@ -1,44 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini tty implementation for busybox
4 *
5 * Copyright (C) 2000 Edward Betts <edward@debian.org>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <sys/types.h>
27#include "busybox.h"
28
29extern int tty_main(int argc, char **argv)
30{
31 char *tty;
32
33 if (argc > 1) {
34 if (argv[1][0] != '-' || argv[1][1] != 's')
35 show_usage();
36 } else {
37 tty = ttyname(0);
38 if (tty)
39 puts(tty);
40 else
41 puts("not a tty");
42 }
43 return(isatty(0) ? EXIT_SUCCESS : EXIT_FAILURE);
44}
diff --git a/umount.c b/umount.c
deleted file mode 100644
index 74638d21c..000000000
--- a/umount.c
+++ /dev/null
@@ -1,298 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini umount implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <limits.h>
26#include <stdio.h>
27#include <mntent.h>
28#include <errno.h>
29#include <string.h>
30#include <stdlib.h>
31#include "busybox.h"
32
33/* Teach libc5 about realpath -- it includes it but the
34 * prototype is missing... */
35#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
36extern char *realpath(const char *path, char *resolved_path);
37#endif
38
39static const int MNT_FORCE = 1;
40static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
41static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS. */
42static const int MS_RDONLY = 1; /* Mount read-only. */
43
44extern int mount (__const char *__special_file, __const char *__dir,
45 __const char *__fstype, unsigned long int __rwflag,
46 __const void *__data);
47extern int umount (__const char *__special_file);
48extern int umount2 (__const char *__special_file, int __flags);
49
50struct _mtab_entry_t {
51 char *device;
52 char *mountpt;
53 struct _mtab_entry_t *next;
54};
55
56static struct _mtab_entry_t *mtab_cache = NULL;
57
58
59
60#if defined BB_FEATURE_MOUNT_FORCE
61static int doForce = FALSE;
62#endif
63#if defined BB_FEATURE_MOUNT_LOOP
64static int freeLoop = TRUE;
65#endif
66#if defined BB_FEATURE_MTAB_SUPPORT
67static int useMtab = TRUE;
68#endif
69static int umountAll = FALSE;
70static int doRemount = FALSE;
71extern const char mtab_file[]; /* Defined in utility.c */
72
73
74
75/* These functions are here because the getmntent functions do not appear
76 * to be re-entrant, which leads to all sorts of problems when we try to
77 * use them recursively - randolph
78 *
79 * TODO: Perhaps switch to using Glibc's getmntent_r
80 * -Erik
81 */
82static void mtab_read(void)
83{
84 struct _mtab_entry_t *entry = NULL;
85 struct mntent *e;
86 FILE *fp;
87
88 if (mtab_cache != NULL)
89 return;
90
91 if ((fp = setmntent(mtab_file, "r")) == NULL) {
92 error_msg("Cannot open %s", mtab_file);
93 return;
94 }
95 while ((e = getmntent(fp))) {
96 entry = xmalloc(sizeof(struct _mtab_entry_t));
97 entry->device = strdup(e->mnt_fsname);
98 entry->mountpt = strdup(e->mnt_dir);
99 entry->next = mtab_cache;
100 mtab_cache = entry;
101 }
102 endmntent(fp);
103}
104
105static char *mtab_getinfo(const char *match, const char which)
106{
107 struct _mtab_entry_t *cur = mtab_cache;
108
109 while (cur) {
110 if (strcmp(cur->mountpt, match) == 0 ||
111 strcmp(cur->device, match) == 0) {
112 if (which == MTAB_GETMOUNTPT) {
113 return cur->mountpt;
114 } else {
115#if !defined BB_FEATURE_MTAB_SUPPORT
116 if (strcmp(cur->device, "/dev/root") == 0) {
117 /* Adjusts device to be the real root device,
118 * or leaves device alone if it can't find it */
119 cur->device = find_real_root_device_name(cur->device);
120 }
121#endif
122 return cur->device;
123 }
124 }
125 cur = cur->next;
126 }
127 return NULL;
128}
129
130static char *mtab_next(void **iter)
131{
132 char *mp;
133
134 if (iter == NULL || *iter == NULL)
135 return NULL;
136 mp = ((struct _mtab_entry_t *) (*iter))->mountpt;
137 *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next;
138 return mp;
139}
140
141static char *mtab_first(void **iter)
142{
143 struct _mtab_entry_t *mtab_iter;
144
145 if (!iter)
146 return NULL;
147 mtab_iter = mtab_cache;
148 *iter = (void *) mtab_iter;
149 return mtab_next(iter);
150}
151
152/* Don't bother to clean up, since exit() does that
153 * automagically, so we can save a few bytes */
154#ifdef BB_FEATURE_CLEAN_UP
155static void mtab_free(void)
156{
157 struct _mtab_entry_t *this, *next;
158
159 this = mtab_cache;
160 while (this) {
161 next = this->next;
162 if (this->device)
163 free(this->device);
164 if (this->mountpt)
165 free(this->mountpt);
166 free(this);
167 this = next;
168 }
169}
170#endif
171
172static int do_umount(const char *name)
173{
174 int status;
175 char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
176
177 if (blockDevice && strcmp(blockDevice, name) == 0)
178 name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
179
180 status = umount(name);
181
182#if defined BB_FEATURE_MOUNT_LOOP
183 if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
184 /* this was a loop device, delete it */
185 del_loop(blockDevice);
186#endif
187#if defined BB_FEATURE_MOUNT_FORCE
188 if (status != 0 && doForce == TRUE) {
189 status = umount2(blockDevice, MNT_FORCE);
190 if (status != 0) {
191 error_msg_and_die("forced umount of %s failed!", blockDevice);
192 }
193 }
194#endif
195 if (status != 0 && doRemount == TRUE && errno == EBUSY) {
196 status = mount(blockDevice, name, NULL,
197 MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
198 if (status == 0) {
199 error_msg("%s busy - remounted read-only", blockDevice);
200 } else {
201 error_msg("Cannot remount %s read-only", blockDevice);
202 }
203 }
204 if (status == 0) {
205#if defined BB_FEATURE_MTAB_SUPPORT
206 if (useMtab == TRUE)
207 erase_mtab(name);
208#endif
209 return (TRUE);
210 }
211 return (FALSE);
212}
213
214static int umount_all(void)
215{
216 int status = TRUE;
217 char *mountpt;
218 void *iter;
219
220 for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
221 /* Never umount /proc on a umount -a */
222 if (strstr(mountpt, "proc")!= NULL)
223 continue;
224 if (!do_umount(mountpt)) {
225 /* Don't bother retrying the umount on busy devices */
226 if (errno == EBUSY) {
227 perror_msg("%s", mountpt);
228 status = FALSE;
229 continue;
230 }
231 if (!do_umount(mountpt)) {
232 printf("Couldn't umount %s on %s: %s\n",
233 mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE),
234 strerror(errno));
235 status = FALSE;
236 }
237 }
238 }
239 return (status);
240}
241
242extern int umount_main(int argc, char **argv)
243{
244 char path[PATH_MAX];
245
246 if (argc < 2) {
247 show_usage();
248 }
249#ifdef BB_FEATURE_CLEAN_UP
250 atexit(mtab_free);
251#endif
252
253 /* Parse any options */
254 while (--argc > 0 && **(++argv) == '-') {
255 while (*++(*argv))
256 switch (**argv) {
257 case 'a':
258 umountAll = TRUE;
259 break;
260#if defined BB_FEATURE_MOUNT_LOOP
261 case 'l':
262 freeLoop = FALSE;
263 break;
264#endif
265#ifdef BB_FEATURE_MTAB_SUPPORT
266 case 'n':
267 useMtab = FALSE;
268 break;
269#endif
270#ifdef BB_FEATURE_MOUNT_FORCE
271 case 'f':
272 doForce = TRUE;
273 break;
274#endif
275 case 'r':
276 doRemount = TRUE;
277 break;
278 case 'v':
279 break; /* ignore -v */
280 default:
281 show_usage();
282 }
283 }
284
285 mtab_read();
286 if (umountAll == TRUE) {
287 if (umount_all() == TRUE)
288 return EXIT_SUCCESS;
289 else
290 return EXIT_FAILURE;
291 }
292 if (realpath(*argv, path) == NULL)
293 perror_msg_and_die("%s", path);
294 if (do_umount(path) == TRUE)
295 return EXIT_SUCCESS;
296 perror_msg_and_die("%s", *argv);
297}
298
diff --git a/uname.c b/uname.c
deleted file mode 100644
index f7e2291a8..000000000
--- a/uname.c
+++ /dev/null
@@ -1,156 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/* uname -- print system information
3 Copyright (C) 1989-1999 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18
19/* Option Example
20
21 -s, --sysname SunOS
22 -n, --nodename rocky8
23 -r, --release 4.0
24 -v, --version
25 -m, --machine sun
26 -a, --all SunOS rocky8 4.0 sun
27
28 The default behavior is equivalent to `-s'.
29
30 David MacKenzie <djm@gnu.ai.mit.edu> */
31
32/* Busyboxed by Erik Andersen */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sys/types.h>
38#include <sys/utsname.h>
39
40#if defined (HAVE_SYSINFO) && defined (HAVE_SYS_SYSTEMINFO_H)
41# include <sys/systeminfo.h>
42#endif
43#include "busybox.h"
44
45static void print_element(unsigned int mask, char *element);
46
47/* Values that are bitwise or'd into `toprint'. */
48/* Operating system name. */
49static const int PRINT_SYSNAME = 1;
50
51/* Node name on a communications network. */
52static const int PRINT_NODENAME = 2;
53
54/* Operating system release. */
55static const int PRINT_RELEASE = 4;
56
57/* Operating system version. */
58static const int PRINT_VERSION = 8;
59
60/* Machine hardware name. */
61static const int PRINT_MACHINE = 16;
62
63 /* Host processor type. */
64static const int PRINT_PROCESSOR = 32;
65
66/* Mask indicating which elements of the name to print. */
67static unsigned char toprint;
68
69
70int uname_main(int argc, char **argv)
71{
72 struct utsname name;
73 char processor[256];
74
75#if defined(__sparc__) && defined(__linux__)
76 char *fake_sparc = getenv("FAKE_SPARC");
77#endif
78
79 toprint = 0;
80
81 /* Parse any options */
82 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
83 while (--argc > 0 && **(++argv) == '-') {
84 while (*(++(*argv))) {
85 switch (**argv) {
86 case 's':
87 toprint |= PRINT_SYSNAME;
88 break;
89 case 'n':
90 toprint |= PRINT_NODENAME;
91 break;
92 case 'r':
93 toprint |= PRINT_RELEASE;
94 break;
95 case 'v':
96 toprint |= PRINT_VERSION;
97 break;
98 case 'm':
99 toprint |= PRINT_MACHINE;
100 break;
101 case 'p':
102 toprint |= PRINT_PROCESSOR;
103 break;
104 case 'a':
105 toprint = (PRINT_SYSNAME | PRINT_NODENAME | PRINT_RELEASE |
106 PRINT_PROCESSOR | PRINT_VERSION |
107 PRINT_MACHINE);
108 break;
109 default:
110 show_usage();
111 }
112 }
113 }
114
115 if (toprint == 0)
116 toprint = PRINT_SYSNAME;
117
118 if (uname(&name) == -1)
119 perror_msg("cannot get system name");
120
121#if defined (HAVE_SYSINFO) && defined (SI_ARCHITECTURE)
122 if (sysinfo(SI_ARCHITECTURE, processor, sizeof(processor)) == -1)
123 perror_msg("cannot get processor type");
124}
125
126#else
127 strcpy(processor, "unknown");
128#endif
129
130#if defined(__sparc__) && defined(__linux__)
131 if (fake_sparc != NULL
132 && (fake_sparc[0] == 'y'
133 || fake_sparc[0] == 'Y')) strcpy(name.machine, "sparc");
134#endif
135
136 print_element(PRINT_SYSNAME, name.sysname);
137 print_element(PRINT_NODENAME, name.nodename);
138 print_element(PRINT_RELEASE, name.release);
139 print_element(PRINT_VERSION, name.version);
140 print_element(PRINT_MACHINE, name.machine);
141 print_element(PRINT_PROCESSOR, processor);
142
143 return EXIT_SUCCESS;
144}
145
146/* If the name element set in MASK is selected for printing in `toprint',
147 print ELEMENT; then print a space unless it is the last element to
148 be printed, in which case print a newline. */
149
150static void print_element(unsigned int mask, char *element)
151{
152 if (toprint & mask) {
153 toprint &= ~mask;
154 printf("%s%c", element, toprint ? ' ' : '\n');
155 }
156}
diff --git a/uniq.c b/uniq.c
deleted file mode 100644
index 53e3c64f2..000000000
--- a/uniq.c
+++ /dev/null
@@ -1,89 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini uniq implementation for busybox
4 *
5 *
6 * Copyright (C) 1999,2000,2001 by Lineo, inc.
7 * Written by John Beppu <beppu@lineo.com>
8 * Rewritten by Matt Kraai <kraai@alumni.carnegiemellon.edu>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26#include <stdio.h>
27#include <string.h>
28#include <getopt.h>
29#include <errno.h>
30#include <stdlib.h>
31#include "busybox.h"
32
33static int print_count;
34static int print_uniq = 1;
35static int print_duplicates = 1;
36
37static void print_line(char *line, int count, FILE *fp)
38{
39 if ((print_duplicates && count > 1) || (print_uniq && count == 1)) {
40 if (print_count)
41 fprintf(fp, "%7d\t%s", count, line);
42 else
43 fputs(line, fp);
44 }
45}
46
47int uniq_main(int argc, char **argv)
48{
49 FILE *in = stdin, *out = stdout;
50 char *lastline = NULL, *input;
51 int opt, count = 0;
52
53 /* parse argv[] */
54 while ((opt = getopt(argc, argv, "cdu")) > 0) {
55 switch (opt) {
56 case 'c':
57 print_count = 1;
58 break;
59 case 'd':
60 print_duplicates = 1;
61 print_uniq = 0;
62 break;
63 case 'u':
64 print_duplicates = 0;
65 print_uniq = 1;
66 break;
67 }
68 }
69
70 if (argv[optind] != NULL) {
71 in = xfopen(argv[optind], "r");
72 if (argv[optind+1] != NULL)
73 out = xfopen(argv[optind+1], "w");
74 }
75
76 while ((input = get_line_from_file(in)) != NULL) {
77 if (lastline == NULL || strcmp(input, lastline) != 0) {
78 print_line(lastline, count, out);
79 free(lastline);
80 lastline = input;
81 count = 0;
82 }
83 count++;
84 }
85 print_line(lastline, count, out);
86 free(lastline);
87
88 return EXIT_SUCCESS;
89}
diff --git a/update.c b/update.c
deleted file mode 100644
index 27a04ddee..000000000
--- a/update.c
+++ /dev/null
@@ -1,112 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini update implementation for busybox; much pasted from update-2.11
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 * Copyright (c) 1996, 1997, 1999 Torsten Poulin.
8 * Copyright (c) 2000 by Karl M. Hegbloom <karlheg@debian.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26/*
27 * Note: This program is only necessary if you are running a 2.0.x (or
28 * earlier) kernel. 2.2.x and higher flush filesystem buffers automatically.
29 */
30
31#include <sys/param.h>
32#include <sys/syslog.h>
33#include <unistd.h> /* for getopt() */
34#include <stdlib.h>
35
36#if __GNU_LIBRARY__ > 5
37 #include <sys/kdaemon.h>
38#else
39 extern int bdflush (int func, long int data);
40#endif
41
42#include "busybox.h"
43
44static unsigned int sync_duration = 30;
45static unsigned int flush_duration = 5;
46static int use_sync = 0;
47
48extern int update_main(int argc, char **argv)
49{
50 int pid;
51 int opt;
52
53 while ((opt = getopt(argc, argv, "Ss:f:")) > 0) {
54 switch (opt) {
55 case 'S':
56 use_sync = 1;
57 break;
58 case 's':
59 sync_duration = atoi(optarg);
60 break;
61 case 'f':
62 flush_duration = atoi(optarg);
63 break;
64 default:
65 show_usage();
66 }
67 }
68
69 if (daemon(0, 1) < 0)
70 perror_msg_and_die("daemon");
71
72#ifdef OPEN_MAX
73 for (pid = 0; pid < OPEN_MAX; pid++) close(pid);
74#else
75 /* glibc 2.1.92 requires using sysconf(_SC_OPEN_MAX) */
76 for (pid = 0; pid < sysconf(_SC_OPEN_MAX); pid++) close(pid);
77#endif
78
79 /* This is no longer necessary since 1.3.5x, but it will harmlessly
80 * exit if that is the case.
81 */
82
83 /* set the program name that will show up in a 'ps' listing */
84 argv[0] = "bdflush (update)";
85 argv[1] = NULL;
86 argv[2] = NULL;
87 for (;;) {
88 if (use_sync) {
89 sleep(sync_duration);
90 sync();
91 } else {
92 sleep(flush_duration);
93 if (bdflush(1, 0) < 0) {
94 openlog("update", LOG_CONS, LOG_DAEMON);
95 syslog(LOG_INFO,
96 "This kernel does not need update(8). Exiting.");
97 closelog();
98 return EXIT_SUCCESS;
99 }
100 }
101 }
102
103 return EXIT_SUCCESS;
104}
105
106/*
107Local Variables:
108c-file-style: "linux"
109c-basic-offset: 4
110tab-width: 4
111End:
112*/
diff --git a/uptime.c b/uptime.c
deleted file mode 100644
index 6758d959e..000000000
--- a/uptime.c
+++ /dev/null
@@ -1,77 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini uptime implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24/* This version of uptime doesn't display the number of users on the system,
25 * since busybox init doesn't mess with utmp. For folks using utmp that are
26 * just dying to have # of users reported, feel free to write it as some type
27 * of BB_FEATURE_UTMP_SUPPORT #define
28 */
29
30/* getopt not needed */
31
32
33#include <stdio.h>
34#include <time.h>
35#include <errno.h>
36#include <stdlib.h>
37#include "busybox.h"
38
39static const int FSHIFT = 16; /* nr of bits of precision */
40#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */
41#define LOAD_INT(x) ((x) >> FSHIFT)
42#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
43
44
45extern int uptime_main(int argc, char **argv)
46{
47 int updays, uphours, upminutes;
48 struct sysinfo info;
49 struct tm *current_time;
50 time_t current_secs;
51
52 time(&current_secs);
53 current_time = localtime(&current_secs);
54
55 sysinfo(&info);
56
57 printf(" %2d:%02d%s up ",
58 current_time->tm_hour%12 ? current_time->tm_hour%12 : 12,
59 current_time->tm_min, current_time->tm_hour > 11 ? "pm" : "am");
60 updays = (int) info.uptime / (60*60*24);
61 if (updays)
62 printf("%d day%s, ", updays, (updays != 1) ? "s" : "");
63 upminutes = (int) info.uptime / 60;
64 uphours = (upminutes / 60) % 24;
65 upminutes %= 60;
66 if(uphours)
67 printf("%2d:%02d, ", uphours, upminutes);
68 else
69 printf("%d min, ", upminutes);
70
71 printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n",
72 LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]),
73 LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]),
74 LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2]));
75
76 return EXIT_SUCCESS;
77}
diff --git a/usage.c b/usage.c
deleted file mode 100644
index dfea1f96b..000000000
--- a/usage.c
+++ /dev/null
@@ -1,10 +0,0 @@
1#include "busybox.h"
2
3const char usage_messages[] =
4
5#define MAKE_USAGE
6#include "usage.h"
7
8#include "applets.h"
9
10;
diff --git a/usage.h b/usage.h
deleted file mode 100644
index 5e514274a..000000000
--- a/usage.h
+++ /dev/null
@@ -1,1894 +0,0 @@
1#define addgroup_trivial_usage \
2 "[OPTIONS] <group_name>"
3#define addgroup_full_usage \
4 "Adds a group to the system" \
5 "Options:\n" \
6 "\t-g\t\tspecify gid\n"
7
8#define adduser_trivial_usage \
9 "[OPTIONS] <user_name>"
10#define adduser_full_usage \
11 "Adds a user to the system" \
12 "Options:\n" \
13 "\t-h\t\thome directory\n" \
14 "\t-s\t\tshell\n" \
15 "\t-g\t\tGECOS string\n"
16
17#define adjtimex_trivial_usage \
18 "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]"
19#define adjtimex_full_usage \
20 "Reads and optionally sets system timebase parameters.\n" \
21 "See adjtimex(2).\n\n" \
22 "Options:\n" \
23 "\t-q\t\tquiet mode - do not print\n" \
24 "\t-o offset\ttime offset, microseconds\n" \
25 "\t-f frequency\tfrequency adjust, integer kernel units (65536 is 1ppm)\n" \
26 "\t\t\t(positive values make the system clock run fast)\n" \
27 "\t-t tick\t\tmicroseconds per tick, usually 10000\n" \
28 "\t-p timeconstant\n"
29
30#define ar_trivial_usage \
31 "-[ov][ptx] ARCHIVE FILES"
32#define ar_full_usage \
33 "Extract or list FILES from an ar archive.\n\n" \
34 "Options:\n" \
35 "\t-o\t\tpreserve original dates\n" \
36 "\t-p\t\textract to stdout\n" \
37 "\t-t\t\tlist\n" \
38 "\t-x\t\textract\n" \
39 "\t-v\t\tverbosely list files processed\n"
40
41#define basename_trivial_usage \
42 "FILE [SUFFIX]"
43#define basename_full_usage \
44 "Strips directory path and suffixes from FILE.\n" \
45 "If specified, also removes any trailing SUFFIX."
46#define basename_example_usage \
47 "$ basename /usr/local/bin/foo\n" \
48 "foo\n" \
49 "$ basename /usr/local/bin/\n" \
50 "bin\n" \
51 "$ basename /foo/bar.txt .txt\n" \
52 "bar"
53
54#define bunzip2_trivial_usage \
55 "FILE"
56#define bunzip2_full_usage \
57 "Uncompress FILE to current directory, stripping its .bz2 extension.\n"\
58 " -k is assumed"
59
60#define cat_trivial_usage \
61 "[FILE]..."
62#define cat_full_usage \
63 "Concatenates FILE(s) and prints them to stdout."
64#define cat_example_usage \
65 "$ cat /proc/uptime\n" \
66 "110716.72 17.67"
67
68#define chgrp_trivial_usage \
69 "[OPTION]... GROUP FILE..."
70#define chgrp_full_usage \
71 "Change the group membership of each FILE to GROUP.\n" \
72 "\nOptions:\n" \
73 "\t-R\tChanges files and directories recursively."
74#define chgrp_example_usage \
75 "$ ls -l /tmp/foo\n" \
76 "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \
77 "$ chgrp root /tmp/foo\n" \
78 "$ ls -l /tmp/foo\n" \
79 "-r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo\n"
80
81#define chmod_trivial_usage \
82 "[-R] MODE[,MODE]... FILE..."
83#define chmod_full_usage \
84 "Each MODE is one or more of the letters ugoa, one of the\n" \
85 "symbols +-= and one or more of the letters rwxst.\n\n" \
86 "Options:\n" \
87 "\t-R\tChanges files and directories recursively."
88#define chmod_example_usage \
89 "$ ls -l /tmp/foo\n" \
90 "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" \
91 "$ chmod u+x /tmp/foo\n" \
92 "$ ls -l /tmp/foo\n" \
93 "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n" \
94 "$ chmod 444 /tmp/foo\n" \
95 "$ ls -l /tmp/foo\n" \
96 "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n"
97
98#define chown_trivial_usage \
99 "[ -Rh ]... OWNER[<.|:>[GROUP]] FILE..."
100#define chown_full_usage \
101 "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \
102 "\nOptions:\n" \
103 "\t-R\tChanges files and directories recursively.\n" \
104 "\t-h\tDo not dereference symbolic links."
105#define chown_example_usage \
106 "$ ls -l /tmp/foo\n" \
107 "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \
108 "$ chown root /tmp/foo\n" \
109 "$ ls -l /tmp/foo\n" \
110 "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n" \
111 "$ chown root.root /tmp/foo\n" \
112 "ls -l /tmp/foo\n" \
113 "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n"
114
115#define chroot_trivial_usage \
116 "NEWROOT [COMMAND...]"
117#define chroot_full_usage \
118 "Run COMMAND with root directory set to NEWROOT."
119#define chroot_example_usage \
120 "$ ls -l /bin/ls\n" \
121 "lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \
122 "$ mount /dev/hdc1 /mnt -t minix\n" \
123 "$ chroot /mnt\n" \
124 "$ ls -l /bin/ls\n" \
125 "-rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls*\n"
126
127#define chvt_trivial_usage \
128 "N"
129#define chvt_full_usage \
130 "Changes the foreground virtual terminal to /dev/ttyN"
131
132#define clear_trivial_usage \
133 ""
134#define clear_full_usage \
135 "Clear screen."
136
137#define cmp_trivial_usage \
138 "FILE1 [FILE2]"
139#define cmp_full_usage \
140 "\t-s\tquiet mode - do not print\n" \
141 "Compare files."
142
143#define cp_trivial_usage \
144 "[OPTION]... SOURCE DEST"
145#define cp_full_usage \
146 "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \
147 "\n" \
148 "\t-a\tSame as -dpR\n" \
149 "\t-d\tPreserves links\n" \
150 "\t-p\tPreserves file attributes if possible\n" \
151 "\t-f\tforce (implied; ignored) - always set\n" \
152 "\t-R\tCopies directories recursively"
153
154#define cpio_trivial_usage \
155 "-[dimtuv][F cpiofile]"
156#define cpio_full_usage \
157 "Extract or list files from a cpio archive\n" \
158 "Main operation mode:\n" \
159 "\td\t\tmake leading directories\n" \
160 "\ti\t\textract\n" \
161 "\tm\t\tpreserve mtime\n" \
162 "\tt\t\tlist\n" \
163 "\tu\t\tunconditional overwrite\t" \
164 "\tF\t\tinput from file\t"
165
166#define cut_trivial_usage \
167 "[OPTION]... [FILE]..."
168#define cut_full_usage \
169 "Prints selected fields from each input FILE to standard output.\n\n" \
170 "Options:\n" \
171 "\t-b LIST\t\tOutput only bytes from LIST\n" \
172 "\t-c LIST\t\tOutput only characters from LIST\n" \
173 "\t-d CHAR\t\tUse CHAR instead of tab as the field delimiter\n" \
174 "\t-s\t\tOutput only the lines containing delimiter\n" \
175 "\t-f N\t\tPrint only these fields\n" \
176 "\t-n\t\tIgnored"
177#define cut_example_usage \
178 "$ echo "Hello world" | cut -f 1 -d ' '\n" \
179 "Hello\n" \
180 "$ echo "Hello world" | cut -f 2 -d ' '\n" \
181 "world\n"
182
183#define date_trivial_usage \
184 "[OPTION]... [+FORMAT]"
185#define date_full_usage \
186 "Displays the current time in the given FORMAT, or sets the system date.\n" \
187 "\nOptions:\n" \
188 "\t-R\t\tOutputs RFC-822 compliant date string\n" \
189 "\t-d STRING\tdisplay time described by STRING, not `now'\n" \
190 "\t-s\t\tSets time described by STRING\n" \
191 "\t-u\t\tPrints or sets Coordinated Universal Time"
192#define date_example_usage \
193 "$ date\n" \
194 "Wed Apr 12 18:52:41 MDT 2000\n"
195
196#define dc_trivial_usage \
197 "expression ..."
198#define dc_full_usage \
199 "This is a Tiny RPN calculator that understands the\n" \
200 "following operations: +, -, /, *, and, or, not, eor.\n" \
201 "i.e., 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16"
202#define dc_example_usage \
203 "$ dc 2 2 +\n" \
204 "4\n" \
205 "$ dc 8 8 \* 2 2 + /\n" \
206 "16\n" \
207 "$ dc 0 1 and\n" \
208 "0\n" \
209 "$ dc 0 1 or\n" \
210 "1\n" \
211 "$ echo 72 9 div 8 mul | dc\n" \
212 "64\n"
213
214#define dd_trivial_usage \
215 "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \
216 "\t [seek=N] [conv=notrunc|sync]"
217#define dd_full_usage \
218 "Copy a file, converting and formatting according to options\n\n" \
219 "\tif=FILE\t\tread from FILE instead of stdin\n" \
220 "\tof=FILE\t\twrite to FILE instead of stdout\n" \
221 "\tbs=N\t\tread and write N bytes at a time\n" \
222 "\tcount=N\t\tcopy only N input blocks\n" \
223 "\tskip=N\t\tskip N input blocks\n" \
224 "\tseek=N\t\tskip N output blocks\n" \
225 "\tconv=notrunc\tdon't truncate output file\n" \
226 "\tconv=sync\tpad blocks with zeros\n" \
227 "\n" \
228 "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \
229 "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)."
230#define dd_example_usage \
231 "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \
232 "4+0 records in\n" \
233 "4+0 records out\n"
234
235#define deallocvt_trivial_usage \
236 "N"
237#define deallocvt_full_usage \
238 "Deallocate unused virtual terminal /dev/ttyN"
239
240#define delgroup_trivial_usage \
241 "GROUP"
242#define delgroup_full_usage \
243 "Deletes group GROUP from the system"
244
245#define deluser_trivial_usage \
246 "USER"
247#define deluser_full_usage \
248 "Deletes user USER from the system"
249
250#ifdef BB_FEATURE_HUMAN_READABLE
251 #define USAGE_HUMAN_READABLE(a) a
252 #define USAGE_NOT_HUMAN_READABLE(a)
253#else
254 #define USAGE_HUMAN_READABLE(a)
255 #define USAGE_NOT_HUMAN_READABLE(a) a
256#endif
257#define df_trivial_usage \
258 "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]"
259#define df_full_usage \
260 "Print the filesystem space used and space available.\n\n" \
261 "Options:\n" \
262 USAGE_HUMAN_READABLE( \
263 "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
264 "\t-m\tprint sizes in megabytes\n" \
265 "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
266 "\n\t-k\tprint sizes in kilobytes(compatibility)")
267#define df_example_usage \
268 "$ df\n" \
269 "Filesystem 1k-blocks Used Available Use% Mounted on\n" \
270 "/dev/sda3 8690864 8553540 137324 98% /\n" \
271 "/dev/sda1 64216 36364 27852 57% /boot\n" \
272 "$ df /dev/sda3\n" \
273 "Filesystem 1k-blocks Used Available Use% Mounted on\n" \
274 "/dev/sda3 8690864 8553540 137324 98% /\n"
275
276#define dirname_trivial_usage \
277 "[FILENAME ...]"
278#define dirname_full_usage \
279 "Strips non-directory suffix from FILENAME"
280#define dirname_example_usage \
281 "$ dirname /tmp/foo\n" \
282 "/tmp\n" \
283 "$ dirname /tmp/foo/\n" \
284 "/tmp\n"
285
286#define dmesg_trivial_usage \
287 "[-c] [-n LEVEL] [-s SIZE]"
288#define dmesg_full_usage \
289 "Prints or controls the kernel ring buffer\n\n" \
290 "Options:\n" \
291 "\t-c\t\tClears the ring buffer's contents after printing\n" \
292 "\t-n LEVEL\tSets console logging level\n" \
293 "\t-s SIZE\t\tUse a buffer of size SIZE"
294
295#define dos2unix_trivial_usage \
296 "[option] [FILE]"
297#define dos2unix_full_usage \
298 "Converts FILE from dos format to unix format. When no option\n" \
299 "is given, the input is converted to the opposite output format.\n" \
300 "When no file is given, uses stdin for input and stdout for output.\n\n" \
301 "Options:\n" \
302 "\t-u\toutput will be in UNIX format\n" \
303 "\t-d\toutput will be in DOS format"
304
305#define dpkg_trivial_usage \
306 "-i package_file\n"
307 "[-CPru] package_name"
308#define dpkg_full_usage \
309 "\t-i\tInstall the package\n" \
310 "\t-C\tConfigure an unpackaged package\n" \
311 "\t-P\tPurge all files of a package\n" \
312 "\t-r\tRemove all but the configuration files for a package\n" \
313 "\t-u\tUnpack a package, but dont configure it\n"
314
315#define dpkg_deb_trivial_usage \
316 "[-cefItxX] FILE [argument]"
317#define dpkg_deb_full_usage \
318 "Perform actions on debian packages (.debs)\n\n" \
319 "Options:\n" \
320 "\t-c\tList contents of filesystem tree\n" \
321 "\t-e\tExtract control files to [argument] directory\n" \
322 "\t-f\tDisplay control field name starting with [argument]\n" \
323 "\t-I\tDisplay the control filenamed [argument]\n" \
324 "\t-t\tExtract filesystem tree to stdout in tar format\n" \
325 "\t-x\tExtract packages filesystem tree to directory\n" \
326 "\t-X\tVerbose extract"
327#define dpkg_deb_example_usage \
328 "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
329
330#define du_trivial_usage \
331 "[-ls" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILE]..."
332#define du_full_usage \
333 "Summarizes disk space used for each FILE and/or directory.\n" \
334 "Disk space is printed in units of 1024 bytes.\n\n" \
335 "Options:\n" \
336 "\t-l\tcount sizes many times if hard linked\n" \
337 "\t-s\tdisplay only a total for each argument" \
338 USAGE_HUMAN_READABLE( \
339 "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
340 "\t-m\tprint sizes in megabytes\n" \
341 "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
342 "\n\t-k\tprint sizes in kilobytes(compatibility)")
343#define du_example_usage \
344 "$ du\n" \
345 "16 ./CVS\n" \
346 "12 ./kernel-patches/CVS\n" \
347 "80 ./kernel-patches\n" \
348 "12 ./tests/CVS\n" \
349 "36 ./tests\n" \
350 "12 ./scripts/CVS\n" \
351 "16 ./scripts\n" \
352 "12 ./docs/CVS\n" \
353 "104 ./docs\n" \
354 "2417 .\n"
355
356#define dumpkmap_trivial_usage \
357 "> keymap"
358#define dumpkmap_full_usage \
359 "Prints out a binary keyboard translation table to standard output."
360#define dumpkmap_example_usage \
361 "$ dumpkmap > keymap\n"
362
363#define dutmp_trivial_usage \
364 "[FILE]"
365#define dutmp_full_usage \
366 "Dump utmp file format (pipe delimited) from FILE\n" \
367 "or stdin to stdout. (i.e., 'dutmp /var/run/utmp')"
368#define dutmp_example_usage \
369 "$ dutmp /var/run/utmp\n" \
370 "8|7||si|||0|0|0|955637625|760097|0\n" \
371 "2|0|~|~~|reboot||0|0|0|955637625|782235|0\n" \
372 "1|20020|~|~~|runlevel||0|0|0|955637625|800089|0\n" \
373 "8|125||l4|||0|0|0|955637629|998367|0\n" \
374 "6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0\n" \
375 "6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0\n" \
376 "7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0\n"
377
378#define echo_trivial_usage \
379 "[-neE] [ARG ...]"
380#define echo_full_usage \
381 "Prints the specified ARGs to stdout\n\n" \
382 "Options:\n" \
383 "\t-n\tsuppress trailing newline\n" \
384 "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \
385 "\t-E\tdisable interpretation of backslash-escaped characters"
386#define echo_example_usage \
387 "$ echo "Erik is cool"\n" \
388 "Erik is cool\n" \
389 "$ echo -e "Erik\\nis\\ncool"\n" \
390 "Erik\n" \
391 "is\n" \
392 "cool\n" \
393 "$ echo "Erik\\nis\\ncool"\n" \
394 "Erik\\nis\\ncool\n"
395
396#define env_trivial_usage \
397 "[-iu] [-] [name=value]... [command]"
398#define env_full_usage \
399 "Prints the current environment or runs a program after setting\n" \
400 "up the specified environment.\n\n" \
401 "Options:\n" \
402 "\t-, -i\tstart with an empty environment\n" \
403 "\t-u\tremove variable from the environment\n"
404
405#define expr_trivial_usage \
406 "EXPRESSION"
407#define expr_full_usage \
408 "Prints the value of EXPRESSION to standard output.\n\n" \
409 "EXPRESSION may be:\n" \
410 "\tARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \
411 "\tARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \
412 "\tARG1 < ARG2 ARG1 is less than ARG2\n" \
413 "\tARG1 <= ARG2 ARG1 is less than or equal to ARG2\n" \
414 "\tARG1 = ARG2 ARG1 is equal to ARG2\n" \
415 "\tARG1 != ARG2 ARG1 is unequal to ARG2\n" \
416 "\tARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n" \
417 "\tARG1 > ARG2 ARG1 is greater than ARG2\n" \
418 "\tARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n" \
419 "\tARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n" \
420 "\tARG1 * ARG2 arithmetic product of ARG1 and ARG2\n" \
421 "\tARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n" \
422 "\tARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n" \
423 "\tSTRING : REGEXP anchored pattern match of REGEXP in STRING\n" \
424 "\tmatch STRING REGEXP same as STRING : REGEXP\n" \
425 "\tsubstr STRING POS LENGTH substring of STRING, POS counted from 1\n" \
426 "\tindex STRING CHARS index in STRING where any CHARS is found,\n" \
427 "\t or 0\n" \
428 "\tlength STRING length of STRING\n" \
429 "\tquote TOKEN interpret TOKEN as a string, even if\n" \
430 "\t it is a keyword like `match' or an\n" \
431 "\t operator like `/'\n" \
432 "\t( EXPRESSION ) value of EXPRESSION\n\n" \
433 "Beware that many operators need to be escaped or quoted for shells.\n" \
434 "Comparisons are arithmetic if both ARGs are numbers, else\n" \
435 "lexicographical. Pattern matches return the string matched between \n" \
436 "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \
437 "of characters matched or 0."
438
439#define false_trivial_usage \
440 ""
441#define false_full_usage \
442 "Return an exit code of FALSE (1)."
443#define false_example_usage \
444 "$ false\n" \
445 "$ echo $?\n" \
446 "1\n"
447
448#define fbset_trivial_usage \
449 "[options] [mode]"
450#define fbset_full_usage \
451 "Show and modify frame buffer settings"
452#define fbset_example_usage \
453 "$ fbset\n" \
454 "mode "1024x768-76"\n" \
455 "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \
456 "\tgeometry 1024 768 1024 768 16\n" \
457 "\ttimings 12714 128 32 16 4 128 4\n" \
458 "\taccel false\n" \
459 "\trgba 5/11,6/5,5/0,0/0\n" \
460 "endmode\n"
461
462#define fdflush_trivial_usage \
463 "DEVICE"
464#define fdflush_full_usage \
465 "Forces floppy disk drive to detect disk change"
466
467#ifdef BB_FEATURE_FIND_TYPE
468 #define USAGE_FIND_TYPE(a) a
469#else
470 #define USAGE_FIND_TYPE(a)
471#endif
472#ifdef BB_FEATURE_FIND_PERM
473 #define USAGE_FIND_PERM(a) a
474#else
475 #define USAGE_FIND_PERM(a)
476#endif
477#ifdef BB_FEATURE_FIND_MTIME
478 #define USAGE_FIND_MTIME(a) a
479#else
480 #define USAGE_FIND_MTIME(a)
481#endif
482
483#define find_trivial_usage \
484 "[PATH...] [EXPRESSION]"
485#define find_full_usage \
486 "Search for files in a directory hierarchy. The default PATH is\n" \
487 "the current directory; default EXPRESSION is '-print'\n" \
488 "\nEXPRESSION may consist of:\n" \
489 "\t-follow\t\tDereference symbolic links.\n" \
490 "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \
491 "\t-print\t\tPrint (default and assumed).\n" \
492 USAGE_FIND_TYPE( \
493 "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \
494) USAGE_FIND_PERM( \
495 "\n\t-perm PERMS\tPermissions match any of (+NNN); all of (-NNN);\n\t\t\tor exactly (NNN)" \
496) USAGE_FIND_MTIME( \
497 "\n\t-mtime TIME\tModified time is greater than (+N); less than (-N);\n\t\t\tor exactly (N) days")
498#define find_example_usage \
499 "$ find / -name /etc/passwd\n" \
500 "/etc/passwd\n"
501
502#define free_trivial_usage \
503 ""
504#define free_full_usage \
505 "Displays the amount of free and used system memory"
506#define free_example_usage \
507 "$ free\n" \
508 " total used free shared buffers\n" \
509 " Mem: 257628 248724 8904 59644 93124\n" \
510 " Swap: 128516 8404 120112\n" \
511 "Total: 386144 257128 129016\n" \
512
513#define freeramdisk_trivial_usage \
514 "DEVICE"
515#define freeramdisk_full_usage \
516 "Frees all memory used by the specified ramdisk."
517#define freeramdisk_example_usage \
518 "$ freeramdisk /dev/ram2\n"
519
520#define fsck_minix_trivial_usage \
521 "[-larvsmf] /dev/name"
522#define fsck_minix_full_usage \
523 "Performs a consistency check for MINIX filesystems.\n\n" \
524 "Options:\n" \
525 "\t-l\tLists all filenames\n" \
526 "\t-r\tPerform interactive repairs\n" \
527 "\t-a\tPerform automatic repairs\n" \
528 "\t-v\tverbose\n" \
529 "\t-s\tOutputs super-block information\n" \
530 "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \
531 "\t-f\tForce file system check."
532
533#define getopt_trivial_usage \
534 "[OPTIONS]..."
535#define getopt_full_usage \
536 "Parse command options\n" \
537 "\t-a, --alternative Allow long options starting with single -\n" \
538 "\t-l, --longoptions=longopts Long options to be recognized\n" \
539 "\t-n, --name=progname The name under which errors are reported\n" \
540 "\t-o, --options=optstring Short options to be recognized\n" \
541 "\t-q, --quiet Disable error reporting by getopt(3)\n" \
542 "\t-Q, --quiet-output No normal output\n" \
543 "\t-s, --shell=shell Set shell quoting conventions\n" \
544 "\t-T, --test Test for getopt(1) version\n" \
545 "\t-u, --unqote Do not quote the output"
546#define getopt_example_usage \
547 "$ cat getopt.test\n" \
548 "#!/bin/sh\n" \
549 "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \
550 " -n 'example.busybox' -- "$@"`\n" \
551 "if [ $? != 0 ] ; then exit 1 ; fi\n" \
552 "eval set -- "$GETOPT"\n" \
553 "while true ; do\n" \
554 " case $1 in\n" \
555 " -a|--a-long) echo \"Option a\" ; shift ;;\n" \
556 " -b|--b-long) echo \"Option b, argument \`$2'\" ; shift 2 ;;\n" \
557 " -c|--c-long)\n" \
558 " case "$2" in\n" \
559 " \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \
560 " *) echo \"Option c, argument \`$2'\" ; shift 2 ;;\n" \
561 " esac ;;\n" \
562 " --) shift ; break ;;\n" \
563 " *) echo \"Internal error!\" ; exit 1 ;;\n" \
564 " esac\n" \
565 "done\n"
566
567#define getty_trivial_usage \
568 "getty [OPTIONS]... baud_rate,... line [termtype]"
569#define getty_full_usage \
570 "\nOpens a tty, prompts for a login name, then invokes /bin/login\n\n" \
571 "Options:\n" \
572 "\t-h\t\tEnable hardware (RTS/CTS) flow control.\n" \
573 "\t-i\t\tDo not display /etc/issue before running login.\n" \
574 "\t-L\t\tLocal line, so do not do carrier detect.\n" \
575 "\t-m\t\tGet baud rate from modem's CONNECT status message.\n" \
576 "\t-w\t\tWait for a CR or LF before sending /etc/issue.\n" \
577 "\t-l login_app\tInvoke login_app instead of /bin/login.\n" \
578 "\t-t timeout\tTerminate after timeout if no username is read.\n" \
579 "\t-I initstring\tSets the init string to send before anything else.\n" \
580 "\t-H login_host\tLog login_host into the utmp file as the hostname."
581
582
583#define grep_trivial_usage \
584 "[-ihHnqvs] PATTERN [FILEs...]"
585#define grep_full_usage \
586 "Search for PATTERN in each FILE or standard input.\n\n" \
587 "Options:\n" \
588 "\t-H\tprefix output lines with filename where match was found\n" \
589 "\t-h\tsuppress the prefixing filename on output\n" \
590 "\t-i\tignore case distinctions\n" \
591 "\t-l\tlist names of files that match\n" \
592 "\t-n\tprint line number with output lines\n" \
593 "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" \
594 "\t-v\tselect non-matching lines\n" \
595 "\t-s\tsuppress file open/read error messages"
596#define grep_example_usage \
597 "$ grep root /etc/passwd\n" \
598 "root:x:0:0:root:/root:/bin/bash\n" \
599 "$ grep ^[rR]oo. /etc/passwd\n" \
600 "root:x:0:0:root:/root:/bin/bash\n"
601
602#define gunzip_trivial_usage \
603 "[OPTION]... FILE"
604#define gunzip_full_usage \
605 "Uncompress FILE (or standard input if FILE is '-').\n\n" \
606 "Options:\n" \
607 "\t-c\tWrite output to standard output\n" \
608 "\t-t\tTest compressed file integrity"
609#define gunzip_example_usage \
610 "$ ls -la /tmp/BusyBox*\n" \
611 "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \
612 "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \
613 "$ ls -la /tmp/BusyBox*\n" \
614 "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
615
616#define gzip_trivial_usage \
617 "[OPTION]... FILE"
618#define gzip_full_usage \
619 "Compress FILE with maximum compression.\n" \
620 "When FILE is '-', reads standard input. Implies -c.\n\n" \
621 "Options:\n" \
622 "\t-c\tWrite output to standard output instead of FILE.gz\n" \
623 "\t-d\tdecompress"
624#define gzip_example_usage \
625 "$ ls -la /tmp/busybox*\n" \
626 "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/busybox.tar\n" \
627 "$ gzip /tmp/busybox.tar\n" \
628 "$ ls -la /tmp/busybox*\n" \
629 "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
630
631#define halt_trivial_usage \
632 ""
633#define halt_full_usage \
634 "Halt the system."
635
636#define head_trivial_usage \
637 "[OPTION] [FILE]..."
638#define head_full_usage \
639 "Print first 10 lines of each FILE to standard output.\n" \
640 "With more than one FILE, precede each with a header giving the\n" \
641 "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
642 "Options:\n" \
643 "\t-n NUM\t\tPrint first NUM lines instead of first 10"
644#define head_example_usage \
645 "$ head -n 2 /etc/passwd\n" \
646 "root:x:0:0:root:/root:/bin/bash\n" \
647 "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n"
648
649#define hostid_trivial_usage \
650 ""
651#define hostid_full_usage \
652 "Print out a unique 32-bit identifier for the machine."
653
654#define hostname_trivial_usage \
655 "[OPTION] {hostname | -F FILE}"
656#define hostname_full_usage \
657 "Get or set the hostname or DNS domain name. If a hostname is given\n" \
658 "(or FILE with the -F parameter), the host name will be set.\n\n" \
659 "Options:\n" \
660 "\t-s\t\tShort\n" \
661 "\t-i\t\tAddresses for the hostname\n" \
662 "\t-d\t\tDNS domain name\n" \
663 "\t-F, --file FILE\tUse the contents of FILE to specify the hostname"
664#define hostname_example_usage \
665 "$ hostname\n" \
666 "sage \n"
667
668#define id_trivial_usage \
669 "[OPTIONS]... [USERNAME]"
670#define id_full_usage \
671 "Print information for USERNAME or the current user\n\n" \
672 "Options:\n" \
673 "\t-g\tprints only the group ID\n" \
674 "\t-u\tprints only the user ID\n" \
675 "\t-n\tprint a name instead of a number (with for -ug)\n" \
676 "\t-r\tprints the real user ID instead of the effective ID (with -ug)"
677#define id_example_usage \
678 "$ id\n" \
679 "uid=1000(andersen) gid=1000(andersen)\n"
680
681#ifdef BB_FEATURE_IFCONFIG_SLIP
682 #define USAGE_SIOCSKEEPALIVE(a) a
683#else
684 #define USAGE_SIOCSKEEPALIVE(a)
685#endif
686#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
687 #define USAGE_IFCONFIG_MII(a) a
688#else
689 #define USAGE_IFCONFIG_MII(a)
690#endif
691#ifdef BB_FEATURE_IFCONFIG_HW
692 #define USAGE_IFCONFIG_HW(a) a
693#else
694 #define USAGE_IFCONFIG_HW(a)
695#endif
696#ifdef BB_FEATURE_IFCONFIG_STATUS
697 #define USAGE_IFCONFIG_OPT_A(a) a
698#else
699 #define USAGE_IFCONFIG_OPT_A(a)
700#endif
701
702#define ifconfig_trivial_usage \
703 USAGE_IFCONFIG_OPT_A("[-a]") " <interface> [<address>]"
704#define ifconfig_full_usage \
705 "configure a network interface\n\n" \
706 "Options:\n" \
707 "\t[[-]broadcast [<address>]] [[-]pointopoint [<address>]]\n" \
708 "\t[netmask <address>] [dstaddr <address>]\n" \
709 USAGE_SIOCSKEEPALIVE("\t[outfill <NN>] [keepalive <NN>]\n") \
710 "\t" USAGE_IFCONFIG_HW("[hw ether <address>] ") \
711 "[metric <NN>] [mtu <NN>]\n" \
712 "\t[[-]trailers] [[-]arp] [[-]allmulti]\n" \
713 "\t[multicast] [[-]promisc] [txqueuelen <NN>] [[-]dynamic]\n" \
714 USAGE_IFCONFIG_MII("\t[mem_start <NN>] [io_addr <NN>] [irq <NN>]\n") \
715 "\t[up|down] ..."
716
717#define init_trivial_usage \
718 ""
719#define init_full_usage \
720 "Init is the parent of all processes."
721#define init_notes_usage \
722"This version of init is designed to be run only by the kernel.\n" \
723"\n" \
724"BusyBox init doesn't support multiple runlevels. The runlevels field of\n" \
725"the /etc/inittab file is completely ignored by BusyBox init. If you want \n" \
726"runlevels, use sysvinit.\n" \
727"\n" \
728"BusyBox init works just fine without an inittab. If no inittab is found, \n" \
729"it has the following default behavior:\n" \
730"\n" \
731" ::sysinit:/etc/init.d/rcS\n" \
732" ::askfirst:/bin/sh\n" \
733" ::ctrlaltdel:/sbin/reboot\n" \
734" ::shutdown:/sbin/swapoff -a\n" \
735" ::shutdown:/bin/umount -a -r\n" \
736"\n" \
737"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \
738"\n" \
739" tty2::askfirst:/bin/sh\n" \
740" tty3::askfirst:/bin/sh\n" \
741" tty4::askfirst:/bin/sh\n" \
742"\n" \
743"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \
744"\n" \
745" <id>:<runlevels>:<action>:<process>\n" \
746"\n" \
747" <id>: \n" \
748"\n" \
749" WARNING: This field has a non-traditional meaning for BusyBox init!\n" \
750" The id field is used by BusyBox init to specify the controlling tty for\n" \
751" the specified process to run on. The contents of this field are\n" \
752" appended to "/dev/" and used as-is. There is no need for this field to\n" \
753" be unique, although if it isn't you may have strange results. If this\n" \
754" field is left blank, the controlling tty is set to the console. Also\n" \
755" note that if BusyBox detects that a serial console is in use, then only\n" \
756" entries whose controlling tty is either the serial console or /dev/null\n" \
757" will be run. BusyBox init does nothing with utmp. We don't need no\n" \
758" stinkin' utmp.\n" \
759"\n" \
760" <runlevels>: \n" \
761"\n" \
762" The runlevels field is completely ignored.\n" \
763"\n" \
764" <action>: \n" \
765"\n" \
766" Valid actions include: sysinit, respawn, askfirst, wait, \n" \
767" once, ctrlaltdel, and shutdown.\n" \
768"\n" \
769" The available actions can be classified into two groups: actions\n" \
770" that are run only once, and actions that are re-run when the specified\n" \
771" process exits.\n" \
772"\n" \
773" Run only-once actions:\n" \
774"\n" \
775" 'sysinit' is the first item run on boot. init waits until all\n" \
776" sysinit actions are completed before continuing. Following the\n" \
777" completion of all sysinit actions, all 'wait' actions are run.\n" \
778" 'wait' actions, like 'sysinit' actions, cause init to wait until\n" \
779" the specified task completes. 'once' actions are asynchronous,\n" \
780" therefore, init does not wait for them to complete. 'ctrlaltdel'\n" \
781" actions are run when the system detects that someone on the system\n" \
782" console has pressed the CTRL-ALT-DEL key combination. Typically one\n" \
783" wants to run 'reboot' at this point to cause the system to reboot.\n" \
784" Finally the 'shutdown' action specifies the actions to taken when\n" \
785" init is told to reboot. Unmounting filesystems and disabling swap\n" \
786" is a very good here\n" \
787"\n" \
788" Run repeatedly actions:\n" \
789"\n" \
790" 'respawn' actions are run after the 'once' actions. When a process\n" \
791" started with a 'respawn' action exits, init automatically restarts\n" \
792" it. Unlike sysvinit, BusyBox init does not stop processes from\n" \
793" respawning out of control. The 'askfirst' actions acts just like\n" \
794" respawn, except that before running the specified process it\n" \
795" displays the line "Please press Enter to activate this console."\n" \
796" and then waits for the user to press enter before starting the\n" \
797" specified process. \n" \
798"\n" \
799" Unrecognized actions (like initdefault) will cause init to emit an\n" \
800" error message, and then go along with its business. All actions are\n" \
801" run in the reverse order from how they appear in /etc/inittab.\n" \
802"\n" \
803" <process>: \n" \
804"\n" \
805" Specifies the process to be executed and it's command line.\n" \
806"\n" \
807"Example /etc/inittab file:\n" \
808"\n" \
809" # This is run first except when booting in single-user mode.\n" \
810" #\n" \
811" ::sysinit:/etc/init.d/rcS\n" \
812" \n" \
813" # /bin/sh invocations on selected ttys\n" \
814" #\n" \
815" # Start an "askfirst" shell on the console (whatever that may be)\n" \
816" ::askfirst:-/bin/sh\n" \
817" # Start an "askfirst" shell on /dev/tty2-4\n" \
818" tty2::askfirst:-/bin/sh\n" \
819" tty3::askfirst:-/bin/sh\n" \
820" tty4::askfirst:-/bin/sh\n" \
821" \n" \
822" # /sbin/getty invocations for selected ttys\n" \
823" #\n" \
824" tty4::respawn:/sbin/getty 38400 tty5\n" \
825" tty5::respawn:/sbin/getty 38400 tty6\n" \
826" \n" \
827" \n" \
828" # Example of how to put a getty on a serial line (for a terminal)\n" \
829" #\n" \
830" #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \
831" #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \
832" #\n" \
833" # Example how to put a getty on a modem line.\n" \
834" #::respawn:/sbin/getty 57600 ttyS2\n" \
835" \n" \
836" # Stuff to do before rebooting\n" \
837" ::ctrlaltdel:/sbin/reboot\n" \
838" ::shutdown:/bin/umount -a -r\n" \
839" ::shutdown:/sbin/swapoff -a\n"
840
841#define insmod_trivial_usage \
842 "[OPTION]... MODULE [symbol=value]..."
843#define insmod_full_usage \
844 "Loads the specified kernel modules into the kernel.\n\n" \
845 "Options:\n" \
846 "\t-f\tForce module to load into the wrong kernel version.\n" \
847 "\t-k\tMake module autoclean-able.\n" \
848 "\t-v\tverbose output\n" \
849 "\t-L\tLock to prevent simultaneous loads of a module\n" \
850 "\t-x\tdo not export externs"
851
852#define kill_trivial_usage \
853 "[-signal] process-id [process-id ...]"
854#define kill_full_usage \
855 "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
856 "Options:\n" \
857 "\t-l\tList all signal names and numbers."
858#define kill_example_usage \
859 "$ ps | grep apache\n" \
860 "252 root root S [apache]\n" \
861 "263 www-data www-data S [apache]\n" \
862 "264 www-data www-data S [apache]\n" \
863 "265 www-data www-data S [apache]\n" \
864 "266 www-data www-data S [apache]\n" \
865 "267 www-data www-data S [apache]\n" \
866 "$ kill 252\n"
867
868#define killall_trivial_usage \
869 "[-signal] process-name [process-name ...]"
870#define killall_full_usage \
871 "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
872 "Options:\n" \
873 "\t-l\tList all signal names and numbers."
874#define killall_example_usage \
875 "$ killall apache\n"
876
877#define klogd_trivial_usage \
878 "-n"
879#define klogd_full_usage \
880 "Kernel logger.\n"\
881 "Options:\n"\
882 "\t-n\tRun as a foreground process."
883
884#define length_trivial_usage \
885 "STRING"
886#define length_full_usage \
887 "Prints out the length of the specified STRING."
888#define length_example_usage \
889 "$ length Hello\n" \
890 "5\n"
891
892#define ln_trivial_usage \
893 "[OPTION] TARGET... LINK_NAME|DIRECTORY"
894#define ln_full_usage \
895 "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\
896 "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \
897 "Options:\n" \
898 "\t-s\tmake symbolic links instead of hard links\n" \
899 "\t-f\tremove existing destination files\n" \
900 "\t-n\tno dereference symlinks - treat like normal file"
901#define ln_example_usage \
902 "$ ln -s BusyBox /tmp/ls\n" \
903 "$ ls -l /tmp/ls\n" \
904 "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n"
905
906#define loadacm_trivial_usage \
907 "< mapfile"
908#define loadacm_full_usage \
909 "Loads an acm from standard input."
910#define loadacm_example_usage \
911 "$ loadacm < /etc/i18n/acmname\n"
912
913#define loadfont_trivial_usage \
914 "< font"
915#define loadfont_full_usage \
916 "Loads a console font from standard input."
917#define loadfont_example_usage \
918 "$ loadfont < /etc/i18n/fontname\n"
919
920#define loadkmap_trivial_usage \
921 "< keymap"
922#define loadkmap_full_usage \
923 "Loads a binary keyboard translation table from standard input."
924#define loadkmap_example_usage \
925 "$ loadkmap < /etc/i18n/lang-keymap\n"
926
927#define logger_trivial_usage \
928 "[OPTION]... [MESSAGE]"
929#define logger_full_usage \
930 "Write MESSAGE to the system log. If MESSAGE is omitted, log stdin.\n\n" \
931 "Options:\n" \
932 "\t-s\tLog to stderr as well as the system log.\n" \
933 "\t-t\tLog using the specified tag (defaults to user name).\n" \
934 "\t-p\tEnter the message with the specified priority.\n" \
935 "\t\tThis may be numerical or a ``facility.level'' pair."
936#define logger_example_usage \
937 "$ logger "hello"\n"
938
939#define logname_trivial_usage \
940 ""
941#define logname_full_usage \
942 "Print the name of the current user."
943#define logname_example_usage \
944 "$ logname\n" \
945 "root\n"
946
947#define logread_trivial_usage \
948 ""
949
950#define logread_full_usage \
951 "Shows the messages from syslogd (using circular buffer)."
952
953#ifdef BB_FEATURE_LS_TIMESTAMPS
954 #define USAGE_LS_TIMESTAMPS(a) a
955#else
956 #define USAGE_LS_TIMESTAMPS(a)
957#endif
958#ifdef BB_FEATURE_LS_FILETYPES
959 #define USAGE_LS_FILETYPES(a) a
960#else
961 #define USAGE_LS_FILETYPES(a)
962#endif
963#ifdef BB_FEATURE_LS_FOLLOWLINKS
964 #define USAGE_LS_FOLLOWLINKS(a) a
965#else
966 #define USAGE_LS_FOLLOWLINKS(a)
967#endif
968#ifdef BB_FEATURE_LS_RECURSIVE
969 #define USAGE_LS_RECURSIVE(a) a
970#else
971 #define USAGE_LS_RECURSIVE(a)
972#endif
973#ifdef BB_FEATURE_LS_SORTFILES
974 #define USAGE_LS_SORTFILES(a) a
975#else
976 #define USAGE_LS_SORTFILES(a)
977#endif
978#ifdef BB_FEATURE_AUTOWIDTH
979 #define USAGE_AUTOWIDTH(a) a
980#else
981 #define USAGE_AUTOWIDTH(a)
982#endif
983#define ls_trivial_usage \
984 "[-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...]"
985#define ls_full_usage \
986 "List directory contents\n\n" \
987 "Options:\n" \
988 "\t-1\tlist files in a single column\n" \
989 "\t-A\tdo not list implied . and ..\n" \
990 "\t-a\tdo not hide entries starting with .\n" \
991 "\t-C\tlist entries by columns\n" \
992 USAGE_LS_TIMESTAMPS("\t-c\twith -l: show ctime\n") \
993 "\t-d\tlist directory entries instead of contents\n" \
994 USAGE_LS_TIMESTAMPS("\t-e\tlist both full date and full time\n") \
995 USAGE_LS_FILETYPES("\t-F\tappend indicator (one of */=@|) to entries\n") \
996 "\t-i\tlist the i-node for each file\n" \
997 "\t-l\tuse a long listing format\n" \
998 "\t-n\tlist numeric UIDs and GIDs instead of names\n" \
999 USAGE_LS_FILETYPES("\t-p\tappend indicator (one of /=@|) to entries\n") \
1000 USAGE_LS_FOLLOWLINKS("\t-L\tlist entries pointed to by symbolic links\n") \
1001 USAGE_LS_RECURSIVE("\t-R\tlist subdirectories recursively\n") \
1002 USAGE_LS_SORTFILES("\t-r\tsort the listing in reverse order\n") \
1003 USAGE_LS_SORTFILES("\t-S\tsort the listing by file size\n") \
1004 "\t-s\tlist the size of each file, in blocks\n" \
1005 USAGE_AUTOWIDTH("\t-T NUM\tassume Tabstop every NUM columns\n") \
1006 USAGE_LS_TIMESTAMPS("\t-t\twith -l: show modification time\n") \
1007 USAGE_LS_TIMESTAMPS("\t-u\twith -l: show access time\n") \
1008 USAGE_LS_SORTFILES("\t-v\tsort the listing by version\n") \
1009 USAGE_AUTOWIDTH("\t-w NUM\tassume the terminal is NUM columns wide\n") \
1010 "\t-x\tlist entries by lines instead of by columns\n" \
1011 USAGE_LS_SORTFILES("\t-X\tsort the listing by extension\n") \
1012 USAGE_HUMAN_READABLE( \
1013 "\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
1014 "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
1015 "\t-k\tprint sizes in kilobytes(compatibility)")
1016
1017#define lsmod_trivial_usage \
1018 ""
1019#define lsmod_full_usage \
1020 "List the currently loaded kernel modules."
1021
1022#define makedevs_trivial_usage \
1023 "NAME TYPE MAJOR MINOR FIRST LAST [s]"
1024#define makedevs_full_usage \
1025 "Creates a range of block or character special files\n\n" \
1026 "TYPEs include:\n" \
1027 "\tb:\tMake a block (buffered) device.\n" \
1028 "\tc or u:\tMake a character (un-buffered) device.\n" \
1029 "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \
1030 "FIRST specifies the number appended to NAME to create the first device.\n" \
1031 "LAST specifies the number of the last item that should be created.\n" \
1032 "If 's' is the last argument, the base device is created as well.\n\n" \
1033 "For example:\n" \
1034 "\tmakedevs /dev/ttyS c 4 66 2 63 -> ttyS2-ttyS63\n" \
1035 "\tmakedevs /dev/hda b 3 0 0 8 s -> hda,hda1-hda8"
1036#define makedevs_example_usage \
1037 "$ makedevs /dev/ttyS c 4 66 2 63\n" \
1038 "[creates ttyS2-ttyS63]\n" \
1039 "$ makedevs /dev/hda b 3 0 0 8 s\n" \
1040 "[creates hda,hda1-hda8]\n"
1041
1042#define md5sum_trivial_usage \
1043 "[OPTION] [FILE]...\n" \
1044 "or: md5sum [OPTION] -c [FILE]"
1045#define md5sum_full_usage \
1046 "Print or check MD5 checksums.\n\n" \
1047 "Options:\n" \
1048 "With no FILE, or when FILE is -, read standard input.\n\n" \
1049 "\t-b\tread files in binary mode\n" \
1050 "\t-c\tcheck MD5 sums against given list\n" \
1051 "\t-t\tread files in text mode (default)\n" \
1052 "\t-g\tread a string\n" \
1053 "\nThe following two options are useful only when verifying checksums:\n" \
1054 "\t-s\tdon't output anything, status code shows success\n" \
1055 "\t-w\twarn about improperly formated MD5 checksum lines"
1056#define md5sum_example_usage \
1057 "$ md5sum < busybox\n" \
1058 "6fd11e98b98a58f64ff3398d7b324003\n" \
1059 "$ md5sum busybox\n" \
1060 "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \
1061 "$ md5sum -c -\n" \
1062 "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \
1063 "busybox: OK\n" \
1064 "^D\n"
1065
1066#define mkdir_trivial_usage \
1067 "[OPTION] DIRECTORY..."
1068#define mkdir_full_usage \
1069 "Create the DIRECTORY(ies) if they do not already exist\n\n" \
1070 "Options:\n" \
1071 "\t-m\tset permission mode (as in chmod), not rwxrwxrwx - umask\n" \
1072 "\t-p\tno error if existing, make parent directories as needed"
1073#define mkdir_example_usage \
1074 "$ mkdir /tmp/foo\n" \
1075 "$ mkdir /tmp/foo\n" \
1076 "/tmp/foo: File exists\n" \
1077 "$ mkdir /tmp/foo/bar/baz\n" \
1078 "/tmp/foo/bar/baz: No such file or directory\n" \
1079 "$ mkdir -p /tmp/foo/bar/baz\n"
1080
1081#define mkfifo_trivial_usage \
1082 "[OPTIONS] name"
1083#define mkfifo_full_usage \
1084 "Creates a named pipe (identical to 'mknod name p')\n\n" \
1085 "Options:\n" \
1086 "\t-m\tcreate the pipe using the specified mode (default a=rw)"
1087
1088#define mkfs_minix_trivial_usage \
1089 "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]"
1090#define mkfs_minix_full_usage \
1091 "Make a MINIX filesystem.\n\n" \
1092 "Options:\n" \
1093 "\t-c\t\tCheck the device for bad blocks\n" \
1094 "\t-n [14|30]\tSpecify the maximum length of filenames\n" \
1095 "\t-i INODES\tSpecify the number of inodes for the filesystem\n" \
1096 "\t-l FILENAME\tRead the bad blocks list from FILENAME\n" \
1097 "\t-v\t\tMake a Minix version 2 filesystem"
1098
1099#define mknod_trivial_usage \
1100 "[OPTIONS] NAME TYPE MAJOR MINOR"
1101#define mknod_full_usage \
1102 "Create a special file (block, character, or pipe).\n\n" \
1103 "Options:\n" \
1104 "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \
1105 "TYPEs include:\n" \
1106 "\tb:\tMake a block (buffered) device.\n" \
1107 "\tc or u:\tMake a character (un-buffered) device.\n" \
1108 "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes."
1109#define mknod_example_usage \
1110 "$ mknod /dev/fd0 b 2 0 \n" \
1111 "$ mknod -m 644 /tmp/pipe p\n"
1112
1113#define mkswap_trivial_usage \
1114 "[-c] [-v0|-v1] device [block-count]"
1115#define mkswap_full_usage \
1116 "Prepare a disk partition to be used as a swap partition.\n\n" \
1117 "Options:\n" \
1118 "\t-c\t\tCheck for read-ability.\n" \
1119 "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \
1120 "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \
1121 "\tblock-count\tNumber of block to use (default is entire partition)."
1122
1123#define mktemp_trivial_usage \
1124 "[-q] TEMPLATE"
1125#define mktemp_full_usage \
1126 "Creates a temporary file with its name based on TEMPLATE.\n" \
1127 "TEMPLATE is any name with six `Xs' (i.e., /tmp/temp.XXXXXX)."
1128#define mktemp_example_usage \
1129 "$ mktemp /tmp/temp.XXXXXX\n" \
1130 "/tmp/temp.mWiLjM\n" \
1131 "$ ls -la /tmp/temp.mWiLjM\n" \
1132 "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n"
1133
1134#define modprobe_trivial_usage \
1135 "[FILE ...]"
1136#define modprobe_full_usage \
1137 "Used for hight level module loading and unloading."
1138#define modprobe_example_usage \
1139 "$ modprobe cdrom\n"
1140
1141#define more_trivial_usage \
1142 "[FILE ...]"
1143#define more_full_usage \
1144 "More is a filter for viewing FILE one screenful at a time."
1145#define more_example_usage \
1146 "$ dmesg | more\n"
1147
1148#ifdef BB_FEATURE_MOUNT_LOOP
1149 #define USAGE_MOUNT_LOOP(a) a
1150#else
1151 #define USAGE_MOUNT_LOOP(a)
1152#endif
1153#ifdef BB_FEATURE_MTAB_SUPPORT
1154 #define USAGE_MTAB(a) a
1155#else
1156 #define USAGE_MTAB(a)
1157#endif
1158#define mount_trivial_usage \
1159 "[flags] DEVICE NODE [-o options,more-options]"
1160#define mount_full_usage \
1161 "Mount a filesystem\n\n" \
1162 "Flags:\n" \
1163 "\t-a:\t\tMount all filesystems in fstab.\n" \
1164 USAGE_MTAB( \
1165 "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \
1166 "\t-n:\t\tDon't write a mount table entry.\n" \
1167 ) \
1168 "\t-o option:\tOne of many filesystem options, listed below.\n" \
1169 "\t-r:\t\tMount the filesystem read-only.\n" \
1170 "\t-t fs-type:\tSpecify the filesystem type.\n" \
1171 "\t-w:\t\tMount for reading and writing (default).\n" \
1172 "\n" \
1173 "Options for use with the \"-o\" flag:\n" \
1174 "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \
1175 "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \
1176 "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \
1177 "\texec/noexec:\tAllow use of executable files / disallow them.\n" \
1178 USAGE_MOUNT_LOOP( \
1179 "\tloop:\t\tMounts a file via loop device.\n" \
1180 ) \
1181 "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \
1182 "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \
1183 "\tro/rw:\t\tMount for read-only / read-write.\n" \
1184 "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \
1185 "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \
1186 "You'll have to see the written documentation for those filesystems."
1187#define mount_example_usage \
1188 "$ mount\n" \
1189 "/dev/hda3 on / type minix (rw)\n" \
1190 "proc on /proc type proc (rw)\n" \
1191 "devpts on /dev/pts type devpts (rw)\n" \
1192 "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \
1193 "$ mount /tmp/diskimage /opt -t ext2 -o loop\n"
1194
1195#define mt_trivial_usage \
1196 "[-f device] opcode value"
1197#define mt_full_usage \
1198 "Control magnetic tape drive operation\n" \
1199 "\nAvailable Opcodes:\n\n" \
1200 "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \
1201 "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \
1202 "ras3 reset retension rew rewoffline seek setblk setdensity\n" \
1203 "setpart tell unload unlock weof wset"
1204
1205#define mv_trivial_usage \
1206 "SOURCE DEST\n" \
1207 "or: mv SOURCE... DIRECTORY"
1208#define mv_full_usage \
1209 "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY."
1210#define mv_example_usage \
1211 "$ mv /tmp/foo /bin/bar\n"
1212
1213#define nc_trivial_usage \
1214 "[IP] [port]"
1215#define nc_full_usage \
1216 "Netcat opens a pipe to IP:port"
1217#define nc_example_usage \
1218 "$ nc foobar.somedomain.com 25\n" \
1219 "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \
1220 "help\n" \
1221 "214-Commands supported:\n" \
1222 "214- HELO EHLO MAIL RCPT DATA AUTH\n" \
1223 "214 NOOP QUIT RSET HELP\n" \
1224 "quit\n" \
1225 "221 foobar closing connection\n"
1226
1227#define nslookup_trivial_usage \
1228 "[HOST] [SERVER]"
1229#define nslookup_full_usage \
1230 "Queries the nameserver for the IP address of the given HOST\n" \
1231 "optionally using a specified DNS server"
1232#define nslookup_example_usage \
1233 "$ nslookup localhost\n" \
1234 "Server: default\n" \
1235 "Address: default\n" \
1236 "\n" \
1237 "Name: debian\n" \
1238 "Address: 127.0.0.1\n"
1239
1240#define pidof_trivial_usage \
1241 "process-name [process-name ...]"
1242#define pidof_full_usage \
1243 "Lists the PIDs of all processes with names that match the names on the command line"
1244#define pidof_example_usage \
1245 "$ pidof init\n" \
1246 "1\n"
1247
1248#ifndef BB_FEATURE_FANCY_PING
1249#define ping_trivial_usage "host"
1250#define ping_full_usage "Send ICMP ECHO_REQUEST packets to network hosts"
1251#else
1252#define ping_trivial_usage \
1253 "[OPTION]... host"
1254#define ping_full_usage \
1255 "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \
1256 "Options:\n" \
1257 "\t-c COUNT\tSend only COUNT pings.\n" \
1258 "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \
1259 "\t-q\t\tQuiet mode, only displays output at start\n" \
1260 "\t\t\tand when finished."
1261#endif
1262#define ping_example_usage \
1263 "$ ping localhost\n" \
1264 "PING slag (127.0.0.1): 56 data bytes\n" \
1265 "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \
1266 "\n" \
1267 "--- debian ping statistics ---\n" \
1268 "1 packets transmitted, 1 packets received, 0% packet loss\n" \
1269 "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
1270
1271#define pivot_root_trivial_usage \
1272 "NEW_ROOT PUT_OLD"
1273#define pivot_root_full_usage \
1274 "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \
1275 "the new root file system."
1276
1277#define poweroff_trivial_usage \
1278 ""
1279#define poweroff_full_usage \
1280 "Halt the system and request that the kernel shut off the power."
1281
1282#define printf_trivial_usage \
1283 "FORMAT [ARGUMENT...]"
1284#define printf_full_usage \
1285 "Formats and prints ARGUMENT(s) according to FORMAT,\n" \
1286 "Where FORMAT controls the output exactly as in C printf."
1287#define printf_example_usage \
1288 "$ printf "Val=%d\\n" 5\n" \
1289 "Val=5\n"
1290
1291#define ps_trivial_usage \
1292 ""
1293#define ps_full_usage \
1294 "Report process status\n" \
1295 "\nThis version of ps accepts no options."
1296#define ps_example_usage \
1297 "$ ps\n" \
1298 " PID Uid Gid State Command\n" \
1299 " 1 root root S init\n" \
1300 " 2 root root S [kflushd]\n" \
1301 " 3 root root S [kupdate]\n" \
1302 " 4 root root S [kpiod]\n" \
1303 " 5 root root S [kswapd]\n" \
1304 " 742 andersen andersen S [bash]\n" \
1305 " 743 andersen andersen S -bash\n" \
1306 " 745 root root S [getty]\n" \
1307 " 2990 andersen andersen R ps\n"
1308
1309#define pwd_trivial_usage \
1310 ""
1311#define pwd_full_usage \
1312 "Print the full filename of the current working directory."
1313#define pwd_example_usage \
1314 "$ pwd\n" \
1315 "/root\n"
1316
1317#define rdate_trivial_usage \
1318 "[OPTION] HOST"
1319#define rdate_full_usage \
1320 "Get and possibly set the system date and time from a remote HOST.\n\n" \
1321 "Options:\n" \
1322 "\t-s\tSet the system date and time (default).\n" \
1323 "\t-p\tPrint the date and time."
1324
1325#define readlink_trivial_usage \
1326 ""
1327#define readlink_full_usage \
1328 "Read a symbolic link."
1329
1330#define reboot_trivial_usage \
1331 ""
1332#define reboot_full_usage \
1333 "Reboot the system."
1334
1335#define renice_trivial_usage \
1336 "priority pid [pid ...]"
1337#define renice_full_usage \
1338 "Changes priority of running processes. Allowed priorities range\n" \
1339 "from 20 (the process runs only when nothing else is running) to 0\n" \
1340 "(default priority) to -20 (almost nothing else ever gets to run)."
1341
1342#define reset_trivial_usage \
1343 ""
1344#define reset_full_usage \
1345 "Resets the screen."
1346
1347#define rm_trivial_usage \
1348 "[OPTION]... FILE..."
1349#define rm_full_usage \
1350 "Remove (unlink) the FILE(s). You may use '--' to\n" \
1351 "indicate that all following arguments are non-options.\n\n" \
1352 "Options:\n" \
1353 "\t-i\t\talways prompt before removing each destination" \
1354 "\t-f\t\tremove existing destinations, never prompt\n" \
1355 "\t-r or -R\tremove the contents of directories recursively"
1356#define rm_example_usage \
1357 "$ rm -rf /tmp/foo\n"
1358
1359#define rmdir_trivial_usage \
1360 "[OPTION]... DIRECTORY..."
1361#define rmdir_full_usage \
1362 "Remove the DIRECTORY(ies), if they are empty."
1363#define rmdir_example_usage \
1364 "# rmdir /tmp/foo\n"
1365
1366#define rmmod_trivial_usage \
1367 "[OPTION]... [MODULE]..."
1368#define rmmod_full_usage \
1369 "Unloads the specified kernel modules from the kernel.\n\n" \
1370 "Options:\n" \
1371 "\t-a\tTry to remove all unused kernel modules."
1372#define rmmod_example_usage \
1373 "$ rmmod tulip\n"
1374
1375#define route_trivial_usage \
1376 "[{add|del|flush}]"
1377#define route_full_usage \
1378 "Edit the kernel's routing tables"
1379
1380#define rpm2cpio_trivial_usage \
1381 "package.rpm"
1382#define rpm2cpio_full_usage \
1383 "Outputs a cpio archive of the rpm file."
1384
1385#define sed_trivial_usage \
1386 "[-nef] pattern [files...]"
1387#define sed_full_usage \
1388 "Options:\n" \
1389 "\t-n\t\tsuppress automatic printing of pattern space\n" \
1390 "\t-e script\tadd the script to the commands to be executed\n" \
1391 "\t-f scriptfile\tadd the contents of script-file to the commands to be executed\n" \
1392 "\n" \
1393 "If no -e or -f is given, the first non-option argument is taken as the\n" \
1394 "sed script to interpret. All remaining arguments are names of input\n" \
1395 "files; if no input files are specified, then the standard input is read."
1396#define sed_example_usage \
1397 "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \
1398 "bar\n"
1399
1400#define setkeycodes_trivial_usage \
1401 "SCANCODE KEYCODE ..."
1402#define setkeycodes_full_usage \
1403 "Set entries into the kernel's scancode-to-keycode map,\n" \
1404 "allowing unusual keyboards to generate usable keycodes.\n\n" \
1405 "SCANCODE may be either xx or e0xx (hexadecimal),\n" \
1406 "and KEYCODE is given in decimal"
1407#define setkeycodes_example_usage \
1408 "$ setkeycodes e030 127\n"
1409
1410#define lash_trivial_usage \
1411 "[FILE]...\n" \
1412 "or: sh -c command [args]..."
1413#define lash_full_usage \
1414 "lash: The BusyBox LAme SHell (command interpreter)"
1415#define lash_notes_usage \
1416"This command does not yet have proper documentation.\n" \
1417"\n" \
1418"Use lash just as you would use any other shell. It properly handles pipes,\n" \
1419"redirects, job control, can be used as the shell for scripts, and has a\n" \
1420"sufficient set of builtins to do what is needed. It does not (yet) support\n" \
1421"Bourne Shell syntax. If you need things like "if-then-else", "while", and such\n" \
1422"use ash or bash. If you just need a very simple and extremely small shell,\n" \
1423"this will do the job."
1424
1425#define sleep_trivial_usage \
1426 "N"
1427#define sleep_full_usage \
1428 "Pause for N seconds."
1429#define sleep_example_usage \
1430 "$ sleep 2\n" \
1431 "[2 second delay results]\n"
1432
1433
1434#ifdef BB_FEATURE_SORT_UNIQUE
1435 #define USAGE_SORT_UNIQUE(a) a
1436#else
1437 #define USAGE_SORT_UNIQUE(a)
1438#endif
1439#ifdef BB_FEATURE_SORT_REVERSE
1440 #define USAGE_SORT_REVERSE(a) a
1441#else
1442 #define USAGE_SORT_REVERSE(a)
1443#endif
1444#define sort_trivial_usage \
1445 "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..."
1446#define sort_full_usage \
1447 "Sorts lines of text in the specified files\n\n"\
1448 "Options:\n" \
1449 USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \
1450 USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \
1451 "\t-n\tsort numerics"
1452#define sort_example_usage \
1453 "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \
1454 "a\n" \
1455 "b\n" \
1456 "c\n" \
1457 "d\n" \
1458 "e\n" \
1459 "f\n"
1460
1461#define start_stop_daemon_trivial_usage \
1462 "[OPTIONS]"
1463#define start_stop_daemon_full_usage \
1464 "Program to start and stop services.\n"\
1465 "Options:\n" \
1466 "-S\t\t\tstart\n"\
1467 "-K\t\t\tstop\n"\
1468 "-x <executable>\t\tprogram to start/check if it is running\n"\
1469 "-p <pid-file>\t\tpid file to check\n"\
1470 "-u <username>|<uid>\tstop this user's processes\n"\
1471 "-n <process-name>\tstop processes with this name\n"\
1472 "-s <signal>\t\tsignal to send (default 15)\n"\
1473 "-a <pathname>\t\tprogram to start (default <executable>)\n"
1474
1475#define stty_trivial_usage \
1476 "[-a|g] [-F DEVICE] [SETTING]..."
1477#define stty_full_usage \
1478 "Without arguments, prints baud rate, line discipline," \
1479 "\nand deviations from stty sane." \
1480 "\n\nOptions:" \
1481 "\n\t-F DEVICE\topen device instead of stdin" \
1482 "\n\t-a\t\tprint all current settings in human-readable form" \
1483 "\n\t-g\t\tprint in stty-readable form" \
1484 "\n\t[SETTING]\tsee manpage"
1485
1486#define swapoff_trivial_usage \
1487 "[OPTION] [DEVICE]"
1488#define swapoff_full_usage \
1489 "Stop swapping virtual memory pages on DEVICE.\n\n" \
1490 "Options:\n" \
1491 "\t-a\tStop swapping on all swap devices"
1492
1493#define swapon_trivial_usage \
1494 "[OPTION] [DEVICE]"
1495#define swapon_full_usage \
1496 "Start swapping virtual memory pages on DEVICE.\n\n" \
1497 "Options:\n" \
1498 "\t-a\tStart swapping on all swap devices"
1499
1500#define sync_trivial_usage \
1501 ""
1502#define sync_full_usage \
1503 "Write all buffered filesystem blocks to disk."
1504
1505
1506#ifdef BB_FEATURE_REMOTE_LOG
1507 #define USAGE_REMOTE_LOG(a) a
1508#else
1509 #define USAGE_REMOTE_LOG(a)
1510#endif
1511#define syslogd_trivial_usage \
1512 "[OPTION]..."
1513#define syslogd_full_usage \
1514 "Linux system and kernel logging utility.\n" \
1515 "Note that this version of syslogd ignores /etc/syslog.conf.\n\n" \
1516 "Options:\n" \
1517 "\t-m NUM\t\tInterval between MARK lines (default=20min, 0=off)\n" \
1518 "\t-n\t\tRun as a foreground process\n" \
1519 "\t-O FILE\t\tUse an alternate log file (default=/var/log/messages)" \
1520 USAGE_REMOTE_LOG( \
1521 "\n\t-R HOST[:PORT]\tLog to IP or hostname on PORT (default PORT=514/UDP)\n" \
1522 "\t-L\t\tLog locally and via network logging (default is network only)")
1523#define syslogd_example_usage \
1524 "$ syslogd -R masterlog:514\n" \
1525 "$ syslogd -R 192.168.1.1:601\n"
1526
1527
1528#ifndef BB_FEATURE_FANCY_TAIL
1529 #define USAGE_UNSIMPLE_TAIL(a)
1530#else
1531 #define USAGE_UNSIMPLE_TAIL(a) a
1532#endif
1533#define tail_trivial_usage \
1534 "[OPTION]... [FILE]..."
1535#define tail_full_usage \
1536 "Print last 10 lines of each FILE to standard output.\n" \
1537 "With more than one FILE, precede each with a header giving the\n" \
1538 "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
1539 "Options:\n" \
1540 USAGE_UNSIMPLE_TAIL("\t-c N[kbm]\toutput the last N bytes\n") \
1541 "\t-n N[kbm]\tprint last N lines instead of last 10\n" \
1542 "\t-f\t\toutput data as the file grows" \
1543 USAGE_UNSIMPLE_TAIL( "\n\t-q\t\tnever output headers giving file names\n" \
1544 "\t-s SEC\t\twait SEC seconds between reads with -f\n" \
1545 "\t-v\t\talways output headers giving file names\n\n" \
1546 "If the first character of N (bytes or lines) is a '+', output begins with \n" \
1547 "the Nth item from the start of each file, otherwise, print the last N items\n" \
1548 "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." )
1549#define tail_example_usage \
1550 "$ tail -n 1 /etc/resolv.conf\n" \
1551 "nameserver 10.0.0.1\n"
1552
1553#ifdef BB_FEATURE_TAR_CREATE
1554 #define USAGE_TAR_CREATE(a) a
1555#else
1556 #define USAGE_TAR_CREATE(a)
1557#endif
1558#ifdef BB_FEATURE_TAR_EXCLUDE
1559 #define USAGE_TAR_EXCLUDE(a) a
1560#else
1561 #define USAGE_TAR_EXCLUDE(a)
1562#endif
1563#define tar_trivial_usage \
1564 "-[" USAGE_TAR_CREATE("c") "xtvO] " \
1565 USAGE_TAR_EXCLUDE("[--exclude FILE] [-X FILE]") \
1566 "[-f TARFILE] [-C DIR] [FILE(s)] ..."
1567#define tar_full_usage \
1568 "Create, extract, or list files from a tar file.\n\n" \
1569 "Options:\n" \
1570 USAGE_TAR_CREATE("\tc\t\tcreate\n") \
1571 "\tx\t\textract\n" \
1572 "\tt\t\tlist\n" \
1573 "\nFile selection:\n" \
1574 "\tf\t\tname of TARFILE or \"-\" for stdin\n" \
1575 "\tO\t\textract to stdout\n" \
1576 USAGE_TAR_EXCLUDE( \
1577 "\texclude\t\tfile to exclude\n" \
1578 "\tX\t\tfile with names to exclude\n" \
1579 ) \
1580 "\tC\t\tchange to directory DIR before operation\n" \
1581 "\tv\t\tverbosely list files processed"
1582#define tar_example_usage \
1583 "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \
1584 "$ tar -cf /tmp/tarball.tar /usr/local\n"
1585
1586#define tee_trivial_usage \
1587 "[OPTION]... [FILE]..."
1588#define tee_full_usage \
1589 "Copy standard input to each FILE, and also to standard output.\n\n" \
1590 "Options:\n" \
1591 "\t-a\tappend to the given FILEs, do not overwrite"
1592#define tee_example_usage \
1593 "$ echo "Hello" | tee /tmp/foo\n" \
1594 "$ cat /tmp/foo\n" \
1595 "Hello\n"
1596
1597#define telnet_trivial_usage \
1598 "HOST [PORT]"
1599#define telnet_full_usage \
1600 "Telnet is used to establish interactive communication with another\n"\
1601 "computer over a network using the TELNET protocol."
1602
1603#define test_trivial_usage \
1604 "EXPRESSION\n or [ EXPRESSION ]"
1605#define test_full_usage \
1606 "Checks file types and compares values returning an exit\n" \
1607 "code determined by the value of EXPRESSION."
1608#define test_example_usage \
1609 "$ test 1 -eq 2\n" \
1610 "$ echo $?\n" \
1611 "1\n" \
1612 "$ test 1 -eq 1\n" \
1613 "$ echo $? \n" \
1614 "0\n" \
1615 "$ [ -d /etc ]\n" \
1616 "$ echo $?\n" \
1617 "0\n" \
1618 "$ [ -d /junk ]\n" \
1619 "$ echo $?\n" \
1620 "1\n"
1621
1622#ifdef BB_FEATURE_TFTP_GET
1623 #define USAGE_TFTP_GET(a) a
1624#else
1625 #define USAGE_TFTP_GET(a)
1626#endif
1627#ifdef BB_FEATURE_TFTP_PUT
1628 #define USAGE_TFTP_PUT(a) a
1629#else
1630 #define USAGE_TFTP_PUT(a)
1631#endif
1632#ifdef BB_FEATURE_TFTP_BLOCKSIZE
1633 #define USAGE_TFTP_BS(a) a
1634#else
1635 #define USAGE_TFTP_BS(a)
1636#endif
1637
1638#define tftp_trivial_usage \
1639 "[OPTION]... HOST [PORT]"
1640#define tftp_full_usage \
1641 "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \
1642 "Options:\n" \
1643 "\t-l FILE\tLocal FILE.\n" \
1644 "\t-r FILE\tRemote FILE.\n" \
1645 USAGE_TFTP_GET( \
1646 "\t-g\tGet file.\n" \
1647 ) \
1648 USAGE_TFTP_PUT( \
1649 "\t-p\tPut file.\n" \
1650 ) \
1651 USAGE_TFTP_BS( \
1652 "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \
1653 )
1654
1655#define touch_trivial_usage \
1656 "[-c] FILE [FILE ...]"
1657#define touch_full_usage \
1658 "Update the last-modified date on the given FILE[s].\n\n" \
1659 "Options:\n" \
1660 "\t-c\tDo not create any files"
1661#define touch_example_usage \
1662 "$ ls -l /tmp/foo\n" \
1663 "/bin/ls: /tmp/foo: No such file or directory\n" \
1664 "$ touch /tmp/foo\n" \
1665 "$ ls -l /tmp/foo\n" \
1666 "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n"
1667
1668#define tr_trivial_usage \
1669 "[-cds] STRING1 [STRING2]"
1670#define tr_full_usage \
1671 "Translate, squeeze, and/or delete characters from\n" \
1672 "standard input, writing to standard output.\n\n" \
1673 "Options:\n" \
1674 "\t-c\ttake complement of STRING1\n" \
1675 "\t-d\tdelete input characters coded STRING1\n" \
1676 "\t-s\tsqueeze multiple output characters of STRING2 into one character"
1677#define tr_example_usage \
1678 "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \
1679 "hello world\n"
1680
1681#define traceroute_trivial_usage \
1682 "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\
1683 [-s src_addr] [-t tos] [-w wait] host [data size]"
1684#define traceroute_full_usage \
1685 "trace the route ip packets follow going to \"host\"\n" \
1686 "Options:\n" \
1687 "\t-d\tset SO_DEBUG options to socket\n" \
1688 "\t-n\tPrint hop addresses numerically rather than symbolically\n" \
1689 "\t-r\tBypass the normal routing tables and send directly to a host\n" \
1690 "\t-v\tVerbose output\n" \
1691 "\t-m max_ttl\tSet the max time-to-live (max number of hops)\n" \
1692 "\t-p port#\tSet the base UDP port number used in probes\n" \
1693 "\t\t(default is 33434)\n" \
1694 "\t-q nqueries\tSet the number of probes per ``ttl'' to nqueries\n" \
1695 "\t\t(default is 3)\n" \
1696 "\t-s src_addr\tUse the following IP address as the source address\n" \
1697 "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \
1698 "\t\t(default 0)\n" \
1699 "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \
1700 "\t\t(default 3 sec.)."
1701
1702
1703#define true_trivial_usage \
1704 ""
1705#define true_full_usage \
1706 "Return an exit code of TRUE (0)."
1707#define true_example_usage \
1708 "$ true\n" \
1709 "$ echo $?\n" \
1710 "0\n"
1711
1712#define tty_trivial_usage \
1713 ""
1714#define tty_full_usage \
1715 "Print the file name of the terminal connected to standard input.\n\n"\
1716 "Options:\n" \
1717 "\t-s\tprint nothing, only return an exit status"
1718#define tty_example_usage \
1719 "$ tty\n" \
1720 "/dev/tty2\n"
1721
1722#ifdef BB_FEATURE_MOUNT_FORCE
1723 #define USAGE_MOUNT_FORCE(a) a
1724#else
1725 #define USAGE_MOUNT_FORCE(a)
1726#endif
1727#define umount_trivial_usage \
1728 "[flags] FILESYSTEM|DIRECTORY"
1729#define umount_full_usage \
1730 "Unmount file systems\n" \
1731 "\nFlags:\n" "\t-a\tUnmount all file systems" \
1732 USAGE_MTAB(" in /etc/mtab\n\t-n\tDon't erase /etc/mtab entries") \
1733 "\n\t-r\tTry to remount devices as read-only if mount is busy" \
1734 USAGE_MOUNT_FORCE("\n\t-f\tForce umount (i.e., unreachable NFS server)") \
1735 USAGE_MOUNT_LOOP("\n\t-l\tDo not free loop device (if a loop device has been used)")
1736#define umount_example_usage \
1737 "$ umount /dev/hdc1 \n"
1738
1739#define uname_trivial_usage \
1740 "[OPTION]..."
1741#define uname_full_usage \
1742 "Print certain system information. With no OPTION, same as -s.\n\n" \
1743 "Options:\n" \
1744 "\t-a\tprint all information\n" \
1745 "\t-m\tthe machine (hardware) type\n" \
1746 "\t-n\tprint the machine's network node hostname\n" \
1747 "\t-r\tprint the operating system release\n" \
1748 "\t-s\tprint the operating system name\n" \
1749 "\t-p\tprint the host processor type\n" \
1750 "\t-v\tprint the operating system version"
1751#define uname_example_usage \
1752 "$ uname -a\n" \
1753 "Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown\n"
1754
1755#define uniq_trivial_usage \
1756 "[OPTION]... [INPUT [OUTPUT]]"
1757#define uniq_full_usage \
1758 "Discard all but one of successive identical lines from INPUT\n" \
1759 "(or standard input), writing to OUTPUT (or standard output).\n\n" \
1760 "Options:\n" \
1761 "\t-c\tprefix lines by the number of occurrences\n" \
1762 "\t-d\tonly print duplicate lines\n" \
1763 "\t-u\tonly print unique lines"
1764#define uniq_example_usage \
1765 "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \
1766 "a\n" \
1767 "b\n" \
1768 "c\n"
1769
1770#define unix2dos_trivial_usage \
1771 "[option] [FILE]"
1772#define unix2dos_full_usage \
1773 "Converts FILE from unix format to dos format. When no option\n" \
1774 "is given, the input is converted to the opposite output format.\n" \
1775 "When no file is given, uses stdin for input and stdout for output.\n" \
1776 "Options:\n" \
1777 "\t-u\toutput will be in UNIX format\n" \
1778 "\t-d\toutput will be in DOS format"
1779
1780#define update_trivial_usage \
1781 "[options]"
1782#define update_full_usage \
1783 "Periodically flushes filesystem buffers.\n\n" \
1784 "Options:\n" \
1785 "\t-S\tforce use of sync(2) instead of flushing\n" \
1786 "\t-s SECS\tcall sync this often (default 30)\n" \
1787 "\t-f SECS\tflush some buffers this often (default 5)"
1788
1789#define uptime_trivial_usage \
1790 ""
1791#define uptime_full_usage \
1792 "Display the time since the last boot."
1793#define uptime_example_usage \
1794 "$ uptime\n" \
1795 " 1:55pm up 2:30, load average: 0.09, 0.04, 0.00\n"
1796
1797#define usleep_trivial_usage \
1798 "N"
1799#define usleep_full_usage \
1800 "Pause for N microseconds."
1801#define usleep_example_usage \
1802 "$ usleep 1000000\n" \
1803 "[pauses for 1 second]\n"
1804
1805#define uudecode_trivial_usage \
1806 "[FILE]..."
1807#define uudecode_full_usage \
1808 "Uudecode a file that is uuencoded.\n\n" \
1809 "Options:\n" \
1810 "\t-o FILE\tdirect output to FILE"
1811#define uudecode_example_usage \
1812 "$ uudecode -o busybox busybox.uu\n" \
1813 "$ ls -l busybox\n" \
1814 "-rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox\n"
1815
1816#define uuencode_trivial_usage \
1817 "[OPTION] [INFILE] REMOTEFILE"
1818#define uuencode_full_usage \
1819 "Uuencode a file.\n\n" \
1820 "Options:\n" \
1821 "\t-m\tuse base64 encoding per RFC1521"
1822#define uuencode_example_usage \
1823 "$ uuencode busybox busybox\n" \
1824 "begin 755 busybox\n" \
1825 "<encoded file snipped>\n" \
1826 "$ uudecode busybox busybox > busybox.uu\n" \
1827 "$\n"
1828
1829#define vi_trivial_usage \
1830 "[OPTION] [FILE]..."
1831#define vi_full_usage \
1832 "edit FILE.\n\n" \
1833 "Options:\n" \
1834 "\t-R\tRead-only- do not write to the file."
1835
1836#define watchdog_trivial_usage \
1837 "DEV"
1838#define watchdog_full_usage \
1839 "Periodically write to watchdog device DEV"
1840
1841#define wc_trivial_usage \
1842 "[OPTION]... [FILE]..."
1843#define wc_full_usage \
1844 "Print line, word, and byte counts for each FILE, and a total line if\n" \
1845 "more than one FILE is specified. With no FILE, read standard input.\n\n" \
1846 "Options:\n" \
1847 "\t-c\tprint the byte counts\n" \
1848 "\t-l\tprint the newline counts\n" \
1849 "\t-L\tprint the length of the longest line\n" \
1850 "\t-w\tprint the word counts"
1851#define wc_example_usage \
1852 "$ wc /etc/passwd\n" \
1853 " 31 46 1365 /etc/passwd\n"
1854
1855#define wget_trivial_usage \
1856 "[-c|--continue] [-q|--quiet] [-O|--output-document file]\n\t[--header 'header: value'] [-P DIR] url"
1857#define wget_full_usage \
1858 "wget retrieves files via HTTP or FTP\n\n" \
1859 "Options:\n" \
1860 "\t-c\tcontinue retrieval of aborted transfers\n" \
1861 "\t-q\tquiet mode - do not print\n" \
1862 "\t-P\tSet directory prefix to DIR\n" \
1863 "\t-O\tsave to filename ('-' for stdout)"
1864
1865#define which_trivial_usage \
1866 "[COMMAND ...]"
1867#define which_full_usage \
1868 "Locates a COMMAND."
1869#define which_example_usage \
1870 "$ which login\n" \
1871 "/bin/login\n"
1872
1873#define whoami_trivial_usage \
1874 ""
1875#define whoami_full_usage \
1876 "Prints the user name associated with the current effective user id."
1877
1878#define xargs_trivial_usage \
1879 "[COMMAND] [ARGS...]"
1880#define xargs_full_usage \
1881 "Executes COMMAND on every item given by standard input."
1882#define xargs_example_usage \
1883 "$ ls | xargs gzip\n" \
1884 "$ find . -name '*.c' -print | xargs rm\n"
1885
1886#define yes_trivial_usage \
1887 "[OPTION]... [STRING]..."
1888#define yes_full_usage \
1889 "Repeatedly outputs a line with all specified STRING(s), or 'y'."
1890
1891#define zcat_trivial_usage \
1892 "FILE"
1893#define zcat_full_usage \
1894 "Uncompress to stdout."
diff --git a/usleep.c b/usleep.c
deleted file mode 100644
index 6023bf430..000000000
--- a/usleep.c
+++ /dev/null
@@ -1,38 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini usleep implementation for busybox
4 *
5 *
6 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24/* getopt not needed */
25
26#include <stdlib.h>
27#include <unistd.h>
28#include "busybox.h"
29
30extern int usleep_main(int argc, char **argv)
31{
32 if ((argc < 2) || (**(argv + 1) == '-')) {
33 show_usage();
34 }
35
36 usleep(atoi(*(++argv))); /* return void */
37 return EXIT_SUCCESS;
38}
diff --git a/util-linux/Makefile b/util-linux/Makefile
new file mode 100644
index 000000000..ddecf50d3
--- /dev/null
+++ b/util-linux/Makefile
@@ -0,0 +1,48 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR :=..
21L_TARGET := util-linux.a
22
23obj-y :=
24obj-n :=
25obj- :=
26
27obj-$(CONFIG_DMESG) += dmesg.o
28obj-$(CONFIG_FBSET) += fbset.o
29obj-$(CONFIG_FDFLUSH) += fdflush.o
30obj-$(CONFIG_FREERAMDISK) += freeramdisk.o
31obj-$(CONFIG_FSCK_MINIX) += fsck_minix.o
32obj-$(CONFIG_GETOPT) += getopt.o
33obj-$(CONFIG_MKFS_MINIX) += mkfs_minix.o
34obj-$(CONFIG_MKSWAP) += mkswap.o
35obj-$(CONFIG_MORE) += more.o
36obj-$(CONFIG_MOUNT) += mount.o
37obj-$(CONFIG_NFSMOUNT) += nfsmount.o
38obj-$(CONFIG_PIVOT_ROOT) += pivot_root.o
39obj-$(CONFIG_RDATE) += rdate.o
40obj-$(CONFIG_SWAPONOFF) += swaponoff.o
41obj-$(CONFIG_UMOUNT) += umount.o
42
43# Hand off to toplevel Rules.mak
44include $(TOPDIR)/Rules.mak
45
46clean:
47 rm -f $(L_TARGET) *.o core
48
diff --git a/util-linux/config.in b/util-linux/config.in
new file mode 100644
index 000000000..3eb8ee0b5
--- /dev/null
+++ b/util-linux/config.in
@@ -0,0 +1,27 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Linux System Utilities'
8
9
10bool 'dmesg' CONFIG_DMESG
11bool 'fbset' CONFIG_FBSET
12bool 'fdflush' CONFIG_FDFLUSH
13bool 'freeramdisk' CONFIG_FREERAMDISK
14bool 'fsck_minix' CONFIG_FSCK_MINIX
15bool 'getopt' CONFIG_GETOPT
16bool 'mkfs_minix' CONFIG_MKFS_MINIX
17bool 'mkswap' CONFIG_MKSWAP
18bool 'more' CONFIG_MORE
19bool 'mount' CONFIG_MOUNT
20bool 'nfsmount' CONFIG_NFSMOUNT
21bool 'pivot_root' CONFIG_PIVOT_ROOT
22bool 'rdate' CONFIG_RDATE
23bool 'swaponoff' CONFIG_SWAPONOFF
24bool 'umount' CONFIG_UMOUNT
25
26endmenu
27
diff --git a/util-linux/fbset.c b/util-linux/fbset.c
index 5ccd80e79..2a959c21c 100644
--- a/util-linux/fbset.c
+++ b/util-linux/fbset.c
@@ -56,7 +56,7 @@ enum {
56 CMD_INFO = 12, 56 CMD_INFO = 12,
57 CMD_CHANGE = 13, 57 CMD_CHANGE = 13,
58 58
59#ifdef BB_FEATURE_FBSET_FANCY 59#ifdef CONFIG_FEATURE_FBSET_FANCY
60 CMD_XRES = 100, 60 CMD_XRES = 100,
61 CMD_YRES = 101, 61 CMD_YRES = 101,
62 CMD_VXRES = 102, 62 CMD_VXRES = 102,
@@ -149,7 +149,7 @@ static struct cmdoptions_t {
149 "-laced", 1, CMD_LACED}, { 149 "-laced", 1, CMD_LACED}, {
150 "-double", 1, CMD_DOUBLE}, { 150 "-double", 1, CMD_DOUBLE}, {
151 "-n", 0, CMD_CHANGE}, { 151 "-n", 0, CMD_CHANGE}, {
152#ifdef BB_FEATURE_FBSET_FANCY 152#ifdef CONFIG_FEATURE_FBSET_FANCY
153 "-all", 0, CMD_ALL}, { 153 "-all", 0, CMD_ALL}, {
154 "-xres", 1, CMD_XRES}, { 154 "-xres", 1, CMD_XRES}, {
155 "-yres", 1, CMD_YRES}, { 155 "-yres", 1, CMD_YRES}, {
@@ -177,7 +177,7 @@ static struct cmdoptions_t {
177 0, 0, 0} 177 0, 0, 0}
178}; 178};
179 179
180#ifdef BB_FEATURE_FBSET_READMODE 180#ifdef CONFIG_FEATURE_FBSET_READMODE
181/* taken from linux/fb.h */ 181/* taken from linux/fb.h */
182static const int FB_VMODE_INTERLACED = 1; /* interlaced */ 182static const int FB_VMODE_INTERLACED = 1; /* interlaced */
183static const int FB_VMODE_DOUBLE = 2; /* double scan */ 183static const int FB_VMODE_DOUBLE = 2; /* double scan */
@@ -189,7 +189,7 @@ static const int FB_SYNC_COMP_HIGH_ACT = 8; /* composite sync high active */
189static int readmode(struct fb_var_screeninfo *base, const char *fn, 189static int readmode(struct fb_var_screeninfo *base, const char *fn,
190 const char *mode) 190 const char *mode)
191{ 191{
192#ifdef BB_FEATURE_FBSET_READMODE 192#ifdef CONFIG_FEATURE_FBSET_READMODE
193 FILE *f; 193 FILE *f;
194 char buf[256]; 194 char buf[256];
195 char *p = buf; 195 char *p = buf;
@@ -313,7 +313,7 @@ static void showmode(struct fb_var_screeninfo *v)
313 v->vsync_len); 313 v->vsync_len);
314 } 314 }
315 printf("\nmode \"%ux%u-%u\"\n", v->xres, v->yres, (int) (vrate + 0.5)); 315 printf("\nmode \"%ux%u-%u\"\n", v->xres, v->yres, (int) (vrate + 0.5));
316#ifdef BB_FEATURE_FBSET_FANCY 316#ifdef CONFIG_FEATURE_FBSET_FANCY
317 printf("\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n", drate / 1e6, 317 printf("\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n", drate / 1e6,
318 hrate / 1e3, vrate); 318 hrate / 1e3, vrate);
319#endif 319#endif
@@ -377,7 +377,7 @@ extern int fbset_main(int argc, char **argv)
377 case CMD_CHANGE: 377 case CMD_CHANGE:
378 g_options |= OPT_CHANGE; 378 g_options |= OPT_CHANGE;
379 break; 379 break;
380#ifdef BB_FEATURE_FBSET_FANCY 380#ifdef CONFIG_FEATURE_FBSET_FANCY
381 case CMD_XRES: 381 case CMD_XRES:
382 varset.xres = strtoul(argv[1], 0, 0); 382 varset.xres = strtoul(argv[1], 0, 0);
383 break; 383 break;
diff --git a/util-linux/fsck_minix.c b/util-linux/fsck_minix.c
index 952968d85..dbe4f74b3 100644
--- a/util-linux/fsck_minix.c
+++ b/util-linux/fsck_minix.c
@@ -191,7 +191,7 @@ static const int ROOT_INO = 1;
191 191
192#define UPPER(size,n) ((size+((n)-1))/(n)) 192#define UPPER(size,n) ((size+((n)-1))/(n))
193#define INODE_SIZE (sizeof(struct minix_inode)) 193#define INODE_SIZE (sizeof(struct minix_inode))
194#ifdef BB_FEATURE_MINIX2 194#ifdef CONFIG_FEATURE_MINIX2
195#define INODE_SIZE2 (sizeof(struct minix2_inode)) 195#define INODE_SIZE2 (sizeof(struct minix2_inode))
196#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \ 196#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
197 : MINIX_INODES_PER_BLOCK)) 197 : MINIX_INODES_PER_BLOCK))
@@ -232,7 +232,7 @@ static char super_block_buffer[BLOCK_SIZE];
232 232
233#define Super (*(struct minix_super_block *)super_block_buffer) 233#define Super (*(struct minix_super_block *)super_block_buffer)
234#define INODES ((unsigned long)Super.s_ninodes) 234#define INODES ((unsigned long)Super.s_ninodes)
235#ifdef BB_FEATURE_MINIX2 235#ifdef CONFIG_FEATURE_MINIX2
236#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones)) 236#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
237#else 237#else
238#define ZONES ((unsigned long)(Super.s_nzones)) 238#define ZONES ((unsigned long)(Super.s_nzones))
@@ -252,7 +252,7 @@ static unsigned char *inode_count = NULL;
252static unsigned char *zone_count = NULL; 252static unsigned char *zone_count = NULL;
253 253
254static void recursive_check(unsigned int ino); 254static void recursive_check(unsigned int ino);
255#ifdef BB_FEATURE_MINIX2 255#ifdef CONFIG_FEATURE_MINIX2
256static void recursive_check2(unsigned int ino); 256static void recursive_check2(unsigned int ino);
257#endif 257#endif
258 258
@@ -408,7 +408,7 @@ static int check_zone_nr(unsigned short *nr, int *corrected)
408 return 0; 408 return 0;
409} 409}
410 410
411#ifdef BB_FEATURE_MINIX2 411#ifdef CONFIG_FEATURE_MINIX2
412static int check_zone_nr2(unsigned int *nr, int *corrected) 412static int check_zone_nr2(unsigned int *nr, int *corrected)
413{ 413{
414 if (!*nr) 414 if (!*nr)
@@ -515,7 +515,7 @@ static int map_block(struct minix_inode *inode, unsigned int blknr)
515 return result; 515 return result;
516} 516}
517 517
518#ifdef BB_FEATURE_MINIX2 518#ifdef CONFIG_FEATURE_MINIX2
519static int map_block2(struct minix2_inode *inode, unsigned int blknr) 519static int map_block2(struct minix2_inode *inode, unsigned int blknr)
520{ 520{
521 unsigned int ind[BLOCK_SIZE >> 2]; 521 unsigned int ind[BLOCK_SIZE >> 2];
@@ -613,7 +613,7 @@ static void get_dirsize(void)
613 char blk[BLOCK_SIZE]; 613 char blk[BLOCK_SIZE];
614 int size; 614 int size;
615 615
616#ifdef BB_FEATURE_MINIX2 616#ifdef CONFIG_FEATURE_MINIX2
617 if (version2) 617 if (version2)
618 block = Inode2[ROOT_INO].i_zone[0]; 618 block = Inode2[ROOT_INO].i_zone[0];
619 else 619 else
@@ -644,7 +644,7 @@ static void read_superblock(void)
644 namelen = 30; 644 namelen = 30;
645 dirsize = 32; 645 dirsize = 32;
646 version2 = 0; 646 version2 = 0;
647#ifdef BB_FEATURE_MINIX2 647#ifdef CONFIG_FEATURE_MINIX2
648 } else if (MAGIC == MINIX2_SUPER_MAGIC) { 648 } else if (MAGIC == MINIX2_SUPER_MAGIC) {
649 namelen = 14; 649 namelen = 14;
650 dirsize = 16; 650 dirsize = 16;
@@ -742,7 +742,7 @@ static struct minix_inode *get_inode(unsigned int nr)
742 return inode; 742 return inode;
743} 743}
744 744
745#ifdef BB_FEATURE_MINIX2 745#ifdef CONFIG_FEATURE_MINIX2
746static struct minix2_inode *get_inode2(unsigned int nr) 746static struct minix2_inode *get_inode2(unsigned int nr)
747{ 747{
748 struct minix2_inode *inode; 748 struct minix2_inode *inode;
@@ -798,7 +798,7 @@ static void check_root(void)
798 die("root inode isn't a directory"); 798 die("root inode isn't a directory");
799} 799}
800 800
801#ifdef BB_FEATURE_MINIX2 801#ifdef CONFIG_FEATURE_MINIX2
802static void check_root2(void) 802static void check_root2(void)
803{ 803{
804 struct minix2_inode *inode = Inode2 + ROOT_INO; 804 struct minix2_inode *inode = Inode2 + ROOT_INO;
@@ -841,7 +841,7 @@ static int add_zone(unsigned short *znr, int *corrected)
841 return block; 841 return block;
842} 842}
843 843
844#ifdef BB_FEATURE_MINIX2 844#ifdef CONFIG_FEATURE_MINIX2
845static int add_zone2(unsigned int *znr, int *corrected) 845static int add_zone2(unsigned int *znr, int *corrected)
846{ 846{
847 int result; 847 int result;
@@ -892,7 +892,7 @@ static void add_zone_ind(unsigned short *znr, int *corrected)
892 write_block(block, blk); 892 write_block(block, blk);
893} 893}
894 894
895#ifdef BB_FEATURE_MINIX2 895#ifdef CONFIG_FEATURE_MINIX2
896static void add_zone_ind2(unsigned int *znr, int *corrected) 896static void add_zone_ind2(unsigned int *znr, int *corrected)
897{ 897{
898 static char blk[BLOCK_SIZE]; 898 static char blk[BLOCK_SIZE];
@@ -926,7 +926,7 @@ static void add_zone_dind(unsigned short *znr, int *corrected)
926 write_block(block, blk); 926 write_block(block, blk);
927} 927}
928 928
929#ifdef BB_FEATURE_MINIX2 929#ifdef CONFIG_FEATURE_MINIX2
930static void add_zone_dind2(unsigned int *znr, int *corrected) 930static void add_zone_dind2(unsigned int *znr, int *corrected)
931{ 931{
932 static char blk[BLOCK_SIZE]; 932 static char blk[BLOCK_SIZE];
@@ -977,7 +977,7 @@ static void check_zones(unsigned int i)
977 add_zone_dind(8 + inode->i_zone, &changed); 977 add_zone_dind(8 + inode->i_zone, &changed);
978} 978}
979 979
980#ifdef BB_FEATURE_MINIX2 980#ifdef CONFIG_FEATURE_MINIX2
981static void check_zones2(unsigned int i) 981static void check_zones2(unsigned int i)
982{ 982{
983 struct minix2_inode *inode; 983 struct minix2_inode *inode;
@@ -1062,7 +1062,7 @@ static void check_file(struct minix_inode *dir, unsigned int offset)
1062 return; 1062 return;
1063} 1063}
1064 1064
1065#ifdef BB_FEATURE_MINIX2 1065#ifdef CONFIG_FEATURE_MINIX2
1066static void check_file2(struct minix2_inode *dir, unsigned int offset) 1066static void check_file2(struct minix2_inode *dir, unsigned int offset)
1067{ 1067{
1068 static char blk[BLOCK_SIZE]; 1068 static char blk[BLOCK_SIZE];
@@ -1143,7 +1143,7 @@ static void recursive_check(unsigned int ino)
1143 check_file(dir, offset); 1143 check_file(dir, offset);
1144} 1144}
1145 1145
1146#ifdef BB_FEATURE_MINIX2 1146#ifdef CONFIG_FEATURE_MINIX2
1147static void recursive_check2(unsigned int ino) 1147static void recursive_check2(unsigned int ino)
1148{ 1148{
1149 struct minix2_inode *dir; 1149 struct minix2_inode *dir;
@@ -1221,7 +1221,7 @@ static void check_counts(void)
1221 } 1221 }
1222} 1222}
1223 1223
1224#ifdef BB_FEATURE_MINIX2 1224#ifdef CONFIG_FEATURE_MINIX2
1225static void check_counts2(void) 1225static void check_counts2(void)
1226{ 1226{
1227 int i; 1227 int i;
@@ -1283,7 +1283,7 @@ static void check(void)
1283 check_counts(); 1283 check_counts();
1284} 1284}
1285 1285
1286#ifdef BB_FEATURE_MINIX2 1286#ifdef CONFIG_FEATURE_MINIX2
1287static void check2(void) 1287static void check2(void)
1288{ 1288{
1289 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count)); 1289 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
@@ -1305,7 +1305,7 @@ static void alloc_name_list(void)
1305 name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1); 1305 name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1);
1306} 1306}
1307 1307
1308#ifdef BB_FEATURE_CLEAN_UP 1308#ifdef CONFIG_FEATURE_CLEAN_UP
1309/* execute this atexit() to deallocate name_list[] */ 1309/* execute this atexit() to deallocate name_list[] */
1310/* piptigger was here */ 1310/* piptigger was here */
1311static void free_name_list(void) 1311static void free_name_list(void)
@@ -1330,7 +1330,7 @@ extern int fsck_minix_main(int argc, char **argv)
1330 int retcode = 0; 1330 int retcode = 0;
1331 1331
1332 alloc_name_list(); 1332 alloc_name_list();
1333#ifdef BB_FEATURE_CLEAN_UP 1333#ifdef CONFIG_FEATURE_CLEAN_UP
1334 /* Don't bother to free memory. Exit does 1334 /* Don't bother to free memory. Exit does
1335 * that automagically, so we can save a few bytes */ 1335 * that automagically, so we can save a few bytes */
1336 atexit(free_name_list); 1336 atexit(free_name_list);
@@ -1338,7 +1338,7 @@ extern int fsck_minix_main(int argc, char **argv)
1338 1338
1339 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) 1339 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
1340 die("bad inode size"); 1340 die("bad inode size");
1341#ifdef BB_FEATURE_MINIX2 1341#ifdef CONFIG_FEATURE_MINIX2
1342 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) 1342 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
1343 die("bad v2 inode size"); 1343 die("bad v2 inode size");
1344#endif 1344#endif
@@ -1422,7 +1422,7 @@ extern int fsck_minix_main(int argc, char **argv)
1422 tcsetattr(0, TCSANOW, &tmp); 1422 tcsetattr(0, TCSANOW, &tmp);
1423 termios_set = 1; 1423 termios_set = 1;
1424 } 1424 }
1425#ifdef BB_FEATURE_MINIX2 1425#ifdef CONFIG_FEATURE_MINIX2
1426 if (version2) { 1426 if (version2) {
1427 check_root2(); 1427 check_root2();
1428 check2(); 1428 check2();
diff --git a/util-linux/mkfs_minix.c b/util-linux/mkfs_minix.c
index ccc0e85d7..a388d0ab0 100644
--- a/util-linux/mkfs_minix.c
+++ b/util-linux/mkfs_minix.c
@@ -180,7 +180,7 @@ struct minix_dir_entry {
180 180
181#define UPPER(size,n) (((size)+((n)-1))/(n)) 181#define UPPER(size,n) (((size)+((n)-1))/(n))
182#define INODE_SIZE (sizeof(struct minix_inode)) 182#define INODE_SIZE (sizeof(struct minix_inode))
183#ifdef BB_FEATURE_MINIX2 183#ifdef CONFIG_FEATURE_MINIX2
184#define INODE_SIZE2 (sizeof(struct minix2_inode)) 184#define INODE_SIZE2 (sizeof(struct minix2_inode))
185#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \ 185#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
186 : MINIX_INODES_PER_BLOCK)) 186 : MINIX_INODES_PER_BLOCK))
@@ -208,7 +208,7 @@ static char root_block[BLOCK_SIZE] = "\0";
208static char *inode_buffer = NULL; 208static char *inode_buffer = NULL;
209 209
210#define Inode (((struct minix_inode *) inode_buffer)-1) 210#define Inode (((struct minix_inode *) inode_buffer)-1)
211#ifdef BB_FEATURE_MINIX2 211#ifdef CONFIG_FEATURE_MINIX2
212#define Inode2 (((struct minix2_inode *) inode_buffer)-1) 212#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
213#endif 213#endif
214static char super_block_buffer[BLOCK_SIZE]; 214static char super_block_buffer[BLOCK_SIZE];
@@ -216,7 +216,7 @@ static char boot_block_buffer[512];
216 216
217#define Super (*(struct minix_super_block *)super_block_buffer) 217#define Super (*(struct minix_super_block *)super_block_buffer)
218#define INODES ((unsigned long)Super.s_ninodes) 218#define INODES ((unsigned long)Super.s_ninodes)
219#ifdef BB_FEATURE_MINIX2 219#ifdef CONFIG_FEATURE_MINIX2
220#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones)) 220#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
221#else 221#else
222#define ZONES ((unsigned long)(Super.s_nzones)) 222#define ZONES ((unsigned long)(Super.s_nzones))
@@ -436,7 +436,7 @@ static void make_bad_inode(void)
436 write_block(dind, (char *) dind_block); 436 write_block(dind, (char *) dind_block);
437} 437}
438 438
439#ifdef BB_FEATURE_MINIX2 439#ifdef CONFIG_FEATURE_MINIX2
440static void make_bad_inode2(void) 440static void make_bad_inode2(void)
441{ 441{
442 struct minix2_inode *inode = &Inode2[MINIX_BAD_INO]; 442 struct minix2_inode *inode = &Inode2[MINIX_BAD_INO];
@@ -509,7 +509,7 @@ static void make_root_inode(void)
509 write_block(inode->i_zone[0], root_block); 509 write_block(inode->i_zone[0], root_block);
510} 510}
511 511
512#ifdef BB_FEATURE_MINIX2 512#ifdef CONFIG_FEATURE_MINIX2
513static void make_root_inode2(void) 513static void make_root_inode2(void)
514{ 514{
515 struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO]; 515 struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO];
@@ -550,7 +550,7 @@ static void setup_tables(void)
550 else 550 else
551 inodes = req_nr_inodes; 551 inodes = req_nr_inodes;
552 /* Round up inode count to fill block size */ 552 /* Round up inode count to fill block size */
553#ifdef BB_FEATURE_MINIX2 553#ifdef CONFIG_FEATURE_MINIX2
554 if (version2) 554 if (version2)
555 inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) & 555 inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) &
556 ~(MINIX2_INODES_PER_BLOCK - 1)); 556 ~(MINIX2_INODES_PER_BLOCK - 1));
@@ -699,7 +699,7 @@ extern int mkfs_minix_main(int argc, char **argv)
699 699
700 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) 700 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
701 error_msg_and_die("bad inode size"); 701 error_msg_and_die("bad inode size");
702#ifdef BB_FEATURE_MINIX2 702#ifdef CONFIG_FEATURE_MINIX2
703 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) 703 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
704 error_msg_and_die("bad inode size"); 704 error_msg_and_die("bad inode size");
705#endif 705#endif
@@ -764,7 +764,7 @@ extern int mkfs_minix_main(int argc, char **argv)
764 break; 764 break;
765 } 765 }
766 case 'v': 766 case 'v':
767#ifdef BB_FEATURE_MINIX2 767#ifdef CONFIG_FEATURE_MINIX2
768 version2 = 1; 768 version2 = 1;
769#else 769#else
770 error_msg("%s: not compiled with minix v2 support", 770 error_msg("%s: not compiled with minix v2 support",
@@ -796,7 +796,7 @@ goodbye:
796 if (!device_name || BLOCKS < 10) { 796 if (!device_name || BLOCKS < 10) {
797 show_usage(); 797 show_usage();
798 } 798 }
799#ifdef BB_FEATURE_MINIX2 799#ifdef CONFIG_FEATURE_MINIX2
800 if (version2) { 800 if (version2) {
801 if (namelen == 14) 801 if (namelen == 14)
802 magic = MINIX2_SUPER_MAGIC; 802 magic = MINIX2_SUPER_MAGIC;
@@ -830,7 +830,7 @@ goodbye:
830 check_blocks(); 830 check_blocks();
831 else if (listfile) 831 else if (listfile)
832 get_list_blocks(listfile); 832 get_list_blocks(listfile);
833#ifdef BB_FEATURE_MINIX2 833#ifdef CONFIG_FEATURE_MINIX2
834 if (version2) { 834 if (version2) {
835 make_root_inode2(); 835 make_root_inode2();
836 make_bad_inode2(); 836 make_bad_inode2();
diff --git a/util-linux/more.c b/util-linux/more.c
index 780cddf66..5fe1da423 100644
--- a/util-linux/more.c
+++ b/util-linux/more.c
@@ -37,7 +37,7 @@
37 37
38static FILE *cin; 38static FILE *cin;
39 39
40#ifdef BB_FEATURE_USE_TERMIOS 40#ifdef CONFIG_FEATURE_USE_TERMIOS
41#include <termios.h> 41#include <termios.h>
42#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) 42#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
43#define getTermSettings(fd,argp) tcgetattr(fd, argp); 43#define getTermSettings(fd,argp) tcgetattr(fd, argp);
@@ -54,7 +54,7 @@ static void gotsig(int sig)
54 putchar('\n'); 54 putchar('\n');
55 exit(EXIT_FAILURE); 55 exit(EXIT_FAILURE);
56} 56}
57#endif /* BB_FEATURE_USE_TERMIOS */ 57#endif /* CONFIG_FEATURE_USE_TERMIOS */
58 58
59 59
60static int terminal_width = 79; /* not 80 in case terminal has linefold bug */ 60static int terminal_width = 79; /* not 80 in case terminal has linefold bug */
@@ -69,7 +69,7 @@ extern int more_main(int argc, char **argv)
69 FILE *file; 69 FILE *file;
70 int len, page_height; 70 int len, page_height;
71 71
72#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS 72#if defined CONFIG_FEATURE_AUTOWIDTH && defined CONFIG_FEATURE_USE_TERMIOS
73 struct winsize win = { 0, 0, 0, 0 }; 73 struct winsize win = { 0, 0, 0, 0 };
74#endif 74#endif
75 75
@@ -83,7 +83,7 @@ extern int more_main(int argc, char **argv)
83 if (!cin) 83 if (!cin)
84 cin = xfopen(CONSOLE_DEV, "r"); 84 cin = xfopen(CONSOLE_DEV, "r");
85 please_display_more_prompt = 0; 85 please_display_more_prompt = 0;
86#ifdef BB_FEATURE_USE_TERMIOS 86#ifdef CONFIG_FEATURE_USE_TERMIOS
87 getTermSettings(fileno(cin), &initial_settings); 87 getTermSettings(fileno(cin), &initial_settings);
88 new_settings = initial_settings; 88 new_settings = initial_settings;
89 new_settings.c_lflag &= ~ICANON; 89 new_settings.c_lflag &= ~ICANON;
@@ -114,7 +114,7 @@ extern int more_main(int argc, char **argv)
114 if(please_display_more_prompt>0) 114 if(please_display_more_prompt>0)
115 please_display_more_prompt = 0; 115 please_display_more_prompt = 0;
116 116
117#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS 117#if defined CONFIG_FEATURE_AUTOWIDTH && defined CONFIG_FEATURE_USE_TERMIOS
118 ioctl(fileno(stdout), TIOCGWINSZ, &win); 118 ioctl(fileno(stdout), TIOCGWINSZ, &win);
119 if (win.ws_row > 4) 119 if (win.ws_row > 4)
120 terminal_height = win.ws_row - 2; 120 terminal_height = win.ws_row - 2;
@@ -147,7 +147,7 @@ extern int more_main(int argc, char **argv)
147 * to get input from the user. 147 * to get input from the user.
148 */ 148 */
149 input = getc(cin); 149 input = getc(cin);
150#ifndef BB_FEATURE_USE_TERMIOS 150#ifndef CONFIG_FEATURE_USE_TERMIOS
151 printf("\033[A"); /* up cursor */ 151 printf("\033[A"); /* up cursor */
152#endif 152#endif
153 /* Erase the "More" message */ 153 /* Erase the "More" message */
diff --git a/util-linux/mount.c b/util-linux/mount.c
index af57a7623..bfa9a3040 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -52,7 +52,7 @@
52#include <mntent.h> 52#include <mntent.h>
53#include <ctype.h> 53#include <ctype.h>
54#include "busybox.h" 54#include "busybox.h"
55#if defined BB_FEATURE_USE_DEVPS_PATCH 55#if defined CONFIG_FEATURE_USE_DEVPS_PATCH
56# include <linux/devmtab.h> /* For Erik's nifty devmtab device driver */ 56# include <linux/devmtab.h> /* For Erik's nifty devmtab device driver */
57#endif 57#endif
58 58
@@ -74,7 +74,7 @@ enum {
74}; 74};
75 75
76 76
77#if defined BB_FEATURE_MOUNT_LOOP 77#if defined CONFIG_FEATURE_MOUNT_LOOP
78#include <fcntl.h> 78#include <fcntl.h>
79#include <sys/ioctl.h> 79#include <sys/ioctl.h>
80static int use_loop = FALSE; 80static int use_loop = FALSE;
@@ -123,13 +123,13 @@ do_mount(char *specialfile, char *dir, char *filesystemtype,
123 char *mtab_opts, int mount_all) 123 char *mtab_opts, int mount_all)
124{ 124{
125 int status = 0; 125 int status = 0;
126#if defined BB_FEATURE_MOUNT_LOOP 126#if defined CONFIG_FEATURE_MOUNT_LOOP
127 char *lofile = NULL; 127 char *lofile = NULL;
128#endif 128#endif
129 129
130 if (fakeIt == FALSE) 130 if (fakeIt == FALSE)
131 { 131 {
132#if defined BB_FEATURE_MOUNT_LOOP 132#if defined CONFIG_FEATURE_MOUNT_LOOP
133 if (use_loop==TRUE) { 133 if (use_loop==TRUE) {
134 int loro = flags & MS_RDONLY; 134 int loro = flags & MS_RDONLY;
135 135
@@ -162,7 +162,7 @@ do_mount(char *specialfile, char *dir, char *filesystemtype,
162 /* If the mount was sucessful, do anything needed, then return TRUE */ 162 /* If the mount was sucessful, do anything needed, then return TRUE */
163 if (status == 0 || fakeIt==TRUE) { 163 if (status == 0 || fakeIt==TRUE) {
164 164
165#if defined BB_FEATURE_MTAB_SUPPORT 165#if defined CONFIG_FEATURE_MTAB_SUPPORT
166 if (useMtab == TRUE) { 166 if (useMtab == TRUE) {
167 erase_mtab(specialfile); // Clean any stale entries 167 erase_mtab(specialfile); // Clean any stale entries
168 write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts); 168 write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
@@ -172,7 +172,7 @@ do_mount(char *specialfile, char *dir, char *filesystemtype,
172 } 172 }
173 173
174 /* Bummer. mount failed. Clean up */ 174 /* Bummer. mount failed. Clean up */
175#if defined BB_FEATURE_MOUNT_LOOP 175#if defined CONFIG_FEATURE_MOUNT_LOOP
176 if (lofile != NULL) { 176 if (lofile != NULL) {
177 del_loop(specialfile); 177 del_loop(specialfile);
178 } 178 }
@@ -209,7 +209,7 @@ parse_mount_options(char *options, int *flags, char *strflags)
209 } 209 }
210 f++; 210 f++;
211 } 211 }
212#if defined BB_FEATURE_MOUNT_LOOP 212#if defined CONFIG_FEATURE_MOUNT_LOOP
213 if (gotone == FALSE && !strcasecmp("loop", options)) { /* loop device support */ 213 if (gotone == FALSE && !strcasecmp("loop", options)) { /* loop device support */
214 use_loop = TRUE; 214 use_loop = TRUE;
215 gotone = TRUE; 215 gotone = TRUE;
@@ -240,7 +240,7 @@ mount_one(char *blockDevice, char *directory, char *filesystemType,
240{ 240{
241 int status = 0; 241 int status = 0;
242 242
243#if defined BB_FEATURE_USE_DEVPS_PATCH 243#if defined CONFIG_FEATURE_USE_DEVPS_PATCH
244 if (strcmp(filesystemType, "auto") == 0) { 244 if (strcmp(filesystemType, "auto") == 0) {
245 static const char *noauto_array[] = { "tmpfs", "shm", "proc", "ramfs", "devpts", "devfs", "usbdevfs", 0 }; 245 static const char *noauto_array[] = { "tmpfs", "shm", "proc", "ramfs", "devpts", "devfs", "usbdevfs", 0 };
246 const char **noauto_fstype; 246 const char **noauto_fstype;
@@ -310,7 +310,7 @@ mount_one(char *blockDevice, char *directory, char *filesystemType,
310 310
311void show_mounts(void) 311void show_mounts(void)
312{ 312{
313#if defined BB_FEATURE_USE_DEVPS_PATCH 313#if defined CONFIG_FEATURE_USE_DEVPS_PATCH
314 int fd, i, numfilesystems; 314 int fd, i, numfilesystems;
315 char device[] = "/dev/mtab"; 315 char device[] = "/dev/mtab";
316 struct k_mntent *mntentlist; 316 struct k_mntent *mntentlist;
@@ -337,7 +337,7 @@ void show_mounts(void)
337 mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, 337 mntentlist[i].mnt_opts, mntentlist[i].mnt_freq,
338 mntentlist[i].mnt_passno); 338 mntentlist[i].mnt_passno);
339 } 339 }
340#ifdef BB_FEATURE_CLEAN_UP 340#ifdef CONFIG_FEATURE_CLEAN_UP
341 /* Don't bother to close files or free memory. Exit 341 /* Don't bother to close files or free memory. Exit
342 * does that automagically, so we can save a few bytes */ 342 * does that automagically, so we can save a few bytes */
343 free( mntentlist); 343 free( mntentlist);
@@ -357,7 +357,7 @@ void show_mounts(void)
357 } 357 }
358 printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir, 358 printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
359 m->mnt_type, m->mnt_opts); 359 m->mnt_type, m->mnt_opts);
360#ifdef BB_FEATURE_CLEAN_UP 360#ifdef CONFIG_FEATURE_CLEAN_UP
361 if(blockDevice != m->mnt_fsname) 361 if(blockDevice != m->mnt_fsname)
362 free(blockDevice); 362 free(blockDevice);
363#endif 363#endif
@@ -408,7 +408,7 @@ extern int mount_main(int argc, char **argv)
408 case 'f': 408 case 'f':
409 fakeIt = TRUE; 409 fakeIt = TRUE;
410 break; 410 break;
411#ifdef BB_FEATURE_MTAB_SUPPORT 411#ifdef CONFIG_FEATURE_MTAB_SUPPORT
412 case 'n': 412 case 'n':
413 useMtab = FALSE; 413 useMtab = FALSE;
414 break; 414 break;
@@ -467,7 +467,7 @@ extern int mount_main(int argc, char **argv)
467singlemount: 467singlemount:
468 string_flags = strdup(string_flags); 468 string_flags = strdup(string_flags);
469 rc = EXIT_SUCCESS; 469 rc = EXIT_SUCCESS;
470#ifdef BB_NFSMOUNT 470#ifdef CONFIG_NFSMOUNT
471 if (strchr(device, ':') != NULL) 471 if (strchr(device, ':') != NULL)
472 filesystemType = "nfs"; 472 filesystemType = "nfs";
473 if (strcmp(filesystemType, "nfs") == 0) { 473 if (strcmp(filesystemType, "nfs") == 0) {
diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c
index d9eb5baae..6cc736ab1 100644
--- a/util-linux/swaponoff.c
+++ b/util-linux/swaponoff.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Mini swapon/swapoff implementation for busybox 3 * Mini swapon/swapoff implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
diff --git a/util-linux/umount.c b/util-linux/umount.c
index 74638d21c..99db3084c 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -2,9 +2,8 @@
2/* 2/*
3 * Mini umount implementation for busybox 3 * Mini umount implementation for busybox
4 * 4 *
5 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Lineo, inc. 6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 * 7 *
9 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -57,13 +56,13 @@ static struct _mtab_entry_t *mtab_cache = NULL;
57 56
58 57
59 58
60#if defined BB_FEATURE_MOUNT_FORCE 59#if defined CONFIG_FEATURE_MOUNT_FORCE
61static int doForce = FALSE; 60static int doForce = FALSE;
62#endif 61#endif
63#if defined BB_FEATURE_MOUNT_LOOP 62#if defined CONFIG_FEATURE_MOUNT_LOOP
64static int freeLoop = TRUE; 63static int freeLoop = TRUE;
65#endif 64#endif
66#if defined BB_FEATURE_MTAB_SUPPORT 65#if defined CONFIG_FEATURE_MTAB_SUPPORT
67static int useMtab = TRUE; 66static int useMtab = TRUE;
68#endif 67#endif
69static int umountAll = FALSE; 68static int umountAll = FALSE;
@@ -112,7 +111,7 @@ static char *mtab_getinfo(const char *match, const char which)
112 if (which == MTAB_GETMOUNTPT) { 111 if (which == MTAB_GETMOUNTPT) {
113 return cur->mountpt; 112 return cur->mountpt;
114 } else { 113 } else {
115#if !defined BB_FEATURE_MTAB_SUPPORT 114#if !defined CONFIG_FEATURE_MTAB_SUPPORT
116 if (strcmp(cur->device, "/dev/root") == 0) { 115 if (strcmp(cur->device, "/dev/root") == 0) {
117 /* Adjusts device to be the real root device, 116 /* Adjusts device to be the real root device,
118 * or leaves device alone if it can't find it */ 117 * or leaves device alone if it can't find it */
@@ -151,7 +150,7 @@ static char *mtab_first(void **iter)
151 150
152/* Don't bother to clean up, since exit() does that 151/* Don't bother to clean up, since exit() does that
153 * automagically, so we can save a few bytes */ 152 * automagically, so we can save a few bytes */
154#ifdef BB_FEATURE_CLEAN_UP 153#ifdef CONFIG_FEATURE_CLEAN_UP
155static void mtab_free(void) 154static void mtab_free(void)
156{ 155{
157 struct _mtab_entry_t *this, *next; 156 struct _mtab_entry_t *this, *next;
@@ -179,12 +178,12 @@ static int do_umount(const char *name)
179 178
180 status = umount(name); 179 status = umount(name);
181 180
182#if defined BB_FEATURE_MOUNT_LOOP 181#if defined CONFIG_FEATURE_MOUNT_LOOP
183 if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9)) 182 if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
184 /* this was a loop device, delete it */ 183 /* this was a loop device, delete it */
185 del_loop(blockDevice); 184 del_loop(blockDevice);
186#endif 185#endif
187#if defined BB_FEATURE_MOUNT_FORCE 186#if defined CONFIG_FEATURE_MOUNT_FORCE
188 if (status != 0 && doForce == TRUE) { 187 if (status != 0 && doForce == TRUE) {
189 status = umount2(blockDevice, MNT_FORCE); 188 status = umount2(blockDevice, MNT_FORCE);
190 if (status != 0) { 189 if (status != 0) {
@@ -202,7 +201,7 @@ static int do_umount(const char *name)
202 } 201 }
203 } 202 }
204 if (status == 0) { 203 if (status == 0) {
205#if defined BB_FEATURE_MTAB_SUPPORT 204#if defined CONFIG_FEATURE_MTAB_SUPPORT
206 if (useMtab == TRUE) 205 if (useMtab == TRUE)
207 erase_mtab(name); 206 erase_mtab(name);
208#endif 207#endif
@@ -246,7 +245,7 @@ extern int umount_main(int argc, char **argv)
246 if (argc < 2) { 245 if (argc < 2) {
247 show_usage(); 246 show_usage();
248 } 247 }
249#ifdef BB_FEATURE_CLEAN_UP 248#ifdef CONFIG_FEATURE_CLEAN_UP
250 atexit(mtab_free); 249 atexit(mtab_free);
251#endif 250#endif
252 251
@@ -257,17 +256,17 @@ extern int umount_main(int argc, char **argv)
257 case 'a': 256 case 'a':
258 umountAll = TRUE; 257 umountAll = TRUE;
259 break; 258 break;
260#if defined BB_FEATURE_MOUNT_LOOP 259#if defined CONFIG_FEATURE_MOUNT_LOOP
261 case 'l': 260 case 'l':
262 freeLoop = FALSE; 261 freeLoop = FALSE;
263 break; 262 break;
264#endif 263#endif
265#ifdef BB_FEATURE_MTAB_SUPPORT 264#ifdef CONFIG_FEATURE_MTAB_SUPPORT
266 case 'n': 265 case 'n':
267 useMtab = FALSE; 266 useMtab = FALSE;
268 break; 267 break;
269#endif 268#endif
270#ifdef BB_FEATURE_MOUNT_FORCE 269#ifdef CONFIG_FEATURE_MOUNT_FORCE
271 case 'f': 270 case 'f':
272 doForce = TRUE; 271 doForce = TRUE;
273 break; 272 break;
diff --git a/uudecode.c b/uudecode.c
deleted file mode 100644
index a4059ddfe..000000000
--- a/uudecode.c
+++ /dev/null
@@ -1,353 +0,0 @@
1/* uudecode.c -- uudecode utility.
2 * Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3 *
4 * This product is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This product is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this product; see the file COPYING. If not, write to
16 * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
18 *
19 * Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93.
20 *
21 * Original copyright notice is retained at the end of this file.
22 */
23
24
25
26#include <stdio.h>
27#include <errno.h>
28#include <getopt.h>
29#include <string.h>
30#include <stdlib.h>
31#include "busybox.h"
32#include "pwd_grp/pwd.h"
33#include "pwd_grp/grp.h"
34
35/*struct passwd *getpwnam();*/
36
37/* Single character decode. */
38#define DEC(Char) (((Char) - ' ') & 077)
39
40static int read_stduu (const char *inname)
41{
42 char buf[2 * BUFSIZ];
43
44 while (1) {
45 int n;
46 char *p;
47
48 if (fgets (buf, sizeof(buf), stdin) == NULL) {
49 error_msg("%s: Short file", inname);
50 return FALSE;
51 }
52 p = buf;
53
54 /* N is used to avoid writing out all the characters at the end of
55 the file. */
56 n = DEC (*p);
57 if (n <= 0)
58 break;
59 for (++p; n > 0; p += 4, n -= 3) {
60 char ch;
61
62 if (n >= 3) {
63 ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
64 putchar (ch);
65 ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
66 putchar (ch);
67 ch = DEC (p[2]) << 6 | DEC (p[3]);
68 putchar (ch);
69 } else {
70 if (n >= 1) {
71 ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
72 putchar (ch);
73 }
74 if (n >= 2) {
75 ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
76 putchar (ch);
77 }
78 }
79 }
80 }
81
82 if (fgets (buf, sizeof(buf), stdin) == NULL
83 || strcmp (buf, "end\n")) {
84 error_msg("%s: No `end' line", inname);
85 return FALSE;
86 }
87
88 return TRUE;
89}
90
91static int read_base64 (const char *inname)
92{
93 static const char b64_tab[256] = {
94 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/
95 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/
96 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/
97 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/
98 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/
99 '\177', '\177', '\177', '\76', '\177', '\177', '\177', '\77', /*050-057*/
100 '\64', '\65', '\66', '\67', '\70', '\71', '\72', '\73', /*060-067*/
101 '\74', '\75', '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/
102 '\177', '\0', '\1', '\2', '\3', '\4', '\5', '\6', /*100-107*/
103 '\7', '\10', '\11', '\12', '\13', '\14', '\15', '\16', /*110-117*/
104 '\17', '\20', '\21', '\22', '\23', '\24', '\25', '\26', /*120-127*/
105 '\27', '\30', '\31', '\177', '\177', '\177', '\177', '\177', /*130-137*/
106 '\177', '\32', '\33', '\34', '\35', '\36', '\37', '\40', /*140-147*/
107 '\41', '\42', '\43', '\44', '\45', '\46', '\47', '\50', /*150-157*/
108 '\51', '\52', '\53', '\54', '\55', '\56', '\57', '\60', /*160-167*/
109 '\61', '\62', '\63', '\177', '\177', '\177', '\177', '\177', /*170-177*/
110 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/
111 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/
112 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/
113 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/
114 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/
115 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/
116 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/
117 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/
118 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/
119 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/
120 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/
121 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/
122 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/
123 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/
124 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/
125 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/
126 };
127 unsigned char buf[2 * BUFSIZ];
128
129 while (1) {
130 int last_data = 0;
131 unsigned char *p;
132
133 if (fgets (buf, sizeof(buf), stdin) == NULL) {
134 error_msg("%s: Short file", inname);
135 return FALSE;
136 }
137 p = buf;
138
139 if (memcmp (buf, "====", 4) == 0)
140 break;
141 if (last_data != 0) {
142 error_msg("%s: data following `=' padding character", inname);
143 return FALSE;
144 }
145
146 /* The following implementation of the base64 decoding might look
147 a bit clumsy but I only try to follow the POSIX standard:
148 ``All line breaks or other characters not found in the table
149 [with base64 characters] shall be ignored by decoding
150 software.'' */
151 while (*p != '\n') {
152 char c1, c2, c3;
153
154 while ((b64_tab[*p] & '\100') != 0)
155 if (*p == '\n' || *p++ == '=')
156 break;
157 if (*p == '\n')
158 /* This leaves the loop. */
159 continue;
160 c1 = b64_tab[*p++];
161
162 while ((b64_tab[*p] & '\100') != 0)
163 if (*p == '\n' || *p++ == '=') {
164 error_msg("%s: illegal line", inname);
165 return FALSE;
166 }
167 c2 = b64_tab[*p++];
168
169 while (b64_tab[*p] == '\177')
170 if (*p++ == '\n') {
171 error_msg("%s: illegal line", inname);
172 return FALSE;
173 }
174 if (*p == '=') {
175 putchar (c1 << 2 | c2 >> 4);
176 last_data = 1;
177 break;
178 }
179 c3 = b64_tab[*p++];
180
181 while (b64_tab[*p] == '\177')
182 if (*p++ == '\n') {
183 error_msg("%s: illegal line", inname);
184 return FALSE;
185 }
186 putchar (c1 << 2 | c2 >> 4);
187 putchar (c2 << 4 | c3 >> 2);
188 if (*p == '=') {
189 last_data = 1;
190 break;
191 }
192 else
193 putchar (c3 << 6 | b64_tab[*p++]);
194 }
195 }
196
197 return TRUE;
198}
199
200static int decode (const char *inname,
201 const char *forced_outname)
202{
203 struct passwd *pw;
204 register char *p;
205 int mode;
206 char buf[2 * BUFSIZ];
207 char *outname;
208 int do_base64 = 0;
209 int res;
210 int dofre;
211
212 /* Search for header line. */
213
214 while (1) {
215 if (fgets (buf, sizeof (buf), stdin) == NULL) {
216 error_msg("%s: No `begin' line", inname);
217 return FALSE;
218 }
219
220 if (strncmp (buf, "begin", 5) == 0) {
221 if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) {
222 do_base64 = 1;
223 break;
224 } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2)
225 break;
226 }
227 }
228
229 /* If the output file name is given on the command line this rules. */
230 dofre = FALSE;
231 if (forced_outname != NULL)
232 outname = (char *) forced_outname;
233 else {
234 /* Handle ~user/file format. */
235 if (buf[0] != '~')
236 outname = buf;
237 else {
238 p = buf + 1;
239 while (*p != '/')
240 ++p;
241 if (*p == '\0') {
242 error_msg("%s: Illegal ~user", inname);
243 return FALSE;
244 }
245 *p++ = '\0';
246 pw = getpwnam (buf + 1);
247 if (pw == NULL) {
248 error_msg("%s: No user `%s'", inname, buf + 1);
249 return FALSE;
250 }
251 outname = concat_path_file(pw->pw_dir, p);
252 dofre = TRUE;
253 }
254 }
255
256 /* Create output file and set mode. */
257 if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0
258 && (freopen (outname, "w", stdout) == NULL
259 || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO))
260 )) {
261 perror_msg("%s", outname); /* */
262 if (dofre)
263 free(outname);
264 return FALSE;
265 }
266
267 /* We differenciate decoding standard UU encoding and base64. A
268 common function would only slow down the program. */
269
270 /* For each input line: */
271 if (do_base64)
272 res = read_base64 (inname);
273 else
274 res = read_stduu (inname);
275 if (dofre)
276 free(outname);
277 return res;
278}
279
280int uudecode_main (int argc,
281 char **argv)
282{
283 int opt;
284 int exit_status;
285 const char *outname;
286 outname = NULL;
287
288 while ((opt = getopt(argc, argv, "o:")) != EOF) {
289 switch (opt) {
290 case 0:
291 break;
292
293 case 'o':
294 outname = optarg;
295 break;
296
297 default:
298 show_usage();
299 }
300 }
301
302 if (optind == argc)
303 exit_status = decode ("stdin", outname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
304 else {
305 exit_status = EXIT_SUCCESS;
306 do {
307 if (freopen (argv[optind], "r", stdin) != NULL) {
308 if (decode (argv[optind], outname) != 0)
309 exit_status = FALSE;
310 } else {
311 perror_msg("%s", argv[optind]);
312 exit_status = EXIT_FAILURE;
313 }
314 optind++;
315 }
316 while (optind < argc);
317 }
318 return(exit_status);
319}
320
321/* Copyright (c) 1983 Regents of the University of California.
322 * All rights reserved.
323 *
324 * Redistribution and use in source and binary forms, with or without
325 * modification, are permitted provided that the following conditions
326 * are met:
327 * 1. Redistributions of source code must retain the above copyright
328 * notice, this list of conditions and the following disclaimer.
329 * 2. Redistributions in binary form must reproduce the above copyright
330 * notice, this list of conditions and the following disclaimer in the
331 * documentation and/or other materials provided with the distribution.
332 *
333 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
334 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
335 *
336 * 4. Neither the name of the University nor the names of its contributors
337 * may be used to endorse or promote products derived from this software
338 * without specific prior written permission.
339 *
340 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
341 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
342 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
343 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
344 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
345 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
346 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
347 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
348 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
349 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
350 * SUCH DAMAGE.
351 */
352
353
diff --git a/uuencode.c b/uuencode.c
deleted file mode 100644
index fc037403a..000000000
--- a/uuencode.c
+++ /dev/null
@@ -1,180 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2000 by Glenn McGrath
4 *
5 * based on the function base64_encode from http.c in wget v1.6
6 * Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22#include <getopt.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include "busybox.h"
29
30/* Conversion table. for base 64 */
31static char tbl_base64[64] = {
32 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
33 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
34 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
35 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
36 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
37 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
38 'w', 'x', 'y', 'z', '0', '1', '2', '3',
39 '4', '5', '6', '7', '8', '9', '+', '/'
40};
41
42static char tbl_std[64] = {
43 '`', '!', '"', '#', '$', '%', '&', '\'',
44 '(', ')', '*', '+', ',', '-', '.', '/',
45 '0', '1', '2', '3', '4', '5', '6', '7',
46 '8', '9', ':', ';', '<', '=', '>', '?',
47 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
48 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
49 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
50 'X', 'Y', 'Z', '[', '\\', ']', '^', '_'
51};
52
53/*
54 * Encode the string S of length LENGTH to base64 format and place it
55 * to STORE. STORE will be 0-terminated, and must point to a writable
56 * buffer of at least 1+BASE64_LENGTH(length) bytes.
57 * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
58 */
59static void uuencode (const char *s, const char *store, const int length, const char *tbl)
60{
61 int i;
62 unsigned char *p = (unsigned char *)store;
63
64 /* Transform the 3x8 bits to 4x6 bits, as required by base64. */
65 for (i = 0; i < length; i += 3) {
66 *p++ = tbl[s[0] >> 2];
67 *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
68 *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
69 *p++ = tbl[s[2] & 0x3f];
70 s += 3;
71 }
72 /* Pad the result if necessary... */
73 if (i == length + 1) {
74 *(p - 1) = '=';
75 }
76 else if (i == length + 2) {
77 *(p - 1) = *(p - 2) = '=';
78 }
79 /* ...and zero-terminate it. */
80 *p = '\0';
81}
82
83int uuencode_main(int argc, char **argv)
84{
85 const int src_buf_size = 60; // This *MUST* be a multiple of 3
86 const int dst_buf_size = 4 * ((src_buf_size + 2) / 3);
87 RESERVE_BB_BUFFER(src_buf, src_buf_size + 1);
88 RESERVE_BB_BUFFER(dst_buf, dst_buf_size + 1);
89 struct stat stat_buf;
90 FILE *src_stream = stdin;
91 char *tbl = tbl_std;
92 size_t size;
93 mode_t mode;
94 int opt;
95 int column = 0;
96 int write_size = 0;
97 int remaining;
98 int buffer_offset = 0;
99
100 while ((opt = getopt(argc, argv, "m")) != -1) {
101 switch (opt) {
102 case 'm':
103 tbl = tbl_base64;
104 break;
105 default:
106 show_usage();
107 }
108 }
109
110 switch (argc - optind) {
111 case 2:
112 src_stream = xfopen(argv[optind], "r");
113 stat(argv[optind], &stat_buf);
114 mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
115 if (src_stream == stdout) {
116 printf("NULL\n");
117 }
118 break;
119 case 1:
120 mode = 0666 & ~umask(0666);
121 break;
122 default:
123 show_usage();
124 }
125
126 printf("begin%s %o %s", tbl == tbl_std ? "" : "-base64", mode, argv[argc - 1]);
127
128 while ((size = fread(src_buf, 1, src_buf_size, src_stream)) > 0) {
129 /* Encode the buffer we just read in */
130 uuencode(src_buf, dst_buf, size, tbl);
131
132 /* Write the buffer to stdout, wrapping at 60 chars.
133 * This looks overly complex, but it gets tricky as
134 * the line has to continue to wrap correctly if we
135 * have to refill the buffer
136 *
137 * Improvments most welcome
138 */
139
140 /* Initialise values for the new buffer */
141 remaining = 4 * ((size + 2) / 3);
142 buffer_offset = 0;
143
144 /* Write the buffer to stdout, wrapping at 60 chars
145 * starting from the column the last buffer ran out
146 */
147 do {
148 if (remaining > (60 - column)) {
149 write_size = 60 - column;
150 }
151 else if (remaining < 60) {
152 write_size = remaining;
153 } else {
154 write_size = 60;
155 }
156
157 /* Setup a new row if required */
158 if (column == 0) {
159 putchar('\n');
160 if (tbl == tbl_std) {
161 putchar('M');
162 }
163 }
164 /* Write to the 60th column */
165 if (fwrite(&dst_buf[buffer_offset], 1, write_size, stdout) != write_size) {
166 perror("Couldnt finish writing");
167 }
168 /* Update variables based on last write */
169 buffer_offset += write_size;
170 remaining -= write_size;
171 column += write_size;
172 if (column % 60 == 0) {
173 column = 0;
174 }
175 } while (remaining > 0);
176 }
177 printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n");
178
179 return(EXIT_SUCCESS);
180}
diff --git a/vi.c b/vi.c
deleted file mode 100644
index 8d7506d0f..000000000
--- a/vi.c
+++ /dev/null
@@ -1,3947 +0,0 @@
1/* vi: set sw=8 ts=8: */
2/*
3 * tiny vi.c: A small 'vi' clone
4 * Copyright (C) 2000, 2001 Sterling Huxley <sterling@europa.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21static const char vi_Version[] =
22 "$Id: vi.c,v 1.15 2001/08/02 05:26:41 andersen Exp $";
23
24/*
25 * To compile for standalone use:
26 * gcc -Wall -Os -s -DSTANDALONE -o vi vi.c
27 * or
28 * gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c # include testing features
29 * strip vi
30 */
31
32/*
33 * Things To Do:
34 * EXINIT
35 * $HOME/.exrc and ./.exrc
36 * add magic to search /foo.*bar
37 * add :help command
38 * :map macros
39 * how about mode lines: vi: set sw=8 ts=8:
40 * if mark[] values were line numbers rather than pointers
41 * it would be easier to change the mark when add/delete lines
42 * More intelligence in refresh()
43 * ":r !cmd" and "!cmd" to filter text through an external command
44 * A true "undo" facility
45 * An "ex" line oriented mode- maybe using "cmdedit"
46 */
47
48//---- Feature -------------- Bytes to immplement
49#ifdef STANDALONE
50#define vi_main main
51#define BB_FEATURE_VI_COLON // 4288
52#define BB_FEATURE_VI_YANKMARK // 1408
53#define BB_FEATURE_VI_SEARCH // 1088
54#define BB_FEATURE_VI_USE_SIGNALS // 1056
55#define BB_FEATURE_VI_DOT_CMD // 576
56#define BB_FEATURE_VI_READONLY // 128
57#define BB_FEATURE_VI_SETOPTS // 576
58#define BB_FEATURE_VI_SET // 224
59#define BB_FEATURE_VI_WIN_RESIZE // 256 WIN_RESIZE
60// To test editor using CRASHME:
61// vi -C filename
62// To stop testing, wait until all to text[] is deleted, or
63// Ctrl-Z and kill -9 %1
64// while in the editor Ctrl-T will toggle the crashme function on and off.
65//#define BB_FEATURE_VI_CRASHME // randomly pick commands to execute
66#endif /* STANDALONE */
67
68#include <stdio.h>
69#include <stdlib.h>
70#include <string.h>
71#include <termios.h>
72#include <unistd.h>
73#include <sys/ioctl.h>
74#include <sys/time.h>
75#include <sys/types.h>
76#include <sys/stat.h>
77#include <time.h>
78#include <fcntl.h>
79#include <signal.h>
80#include <setjmp.h>
81#include <regex.h>
82#include <ctype.h>
83#include <assert.h>
84#include <errno.h>
85#include <stdarg.h>
86#ifndef STANDALONE
87#include "busybox.h"
88#endif /* STANDALONE */
89
90#ifndef TRUE
91#define TRUE ((int)1)
92#define FALSE ((int)0)
93#endif /* TRUE */
94#define MAX_SCR_COLS BUFSIZ
95
96// Misc. non-Ascii keys that report an escape sequence
97#define VI_K_UP 128 // cursor key Up
98#define VI_K_DOWN 129 // cursor key Down
99#define VI_K_RIGHT 130 // Cursor Key Right
100#define VI_K_LEFT 131 // cursor key Left
101#define VI_K_HOME 132 // Cursor Key Home
102#define VI_K_END 133 // Cursor Key End
103#define VI_K_INSERT 134 // Cursor Key Insert
104#define VI_K_PAGEUP 135 // Cursor Key Page Up
105#define VI_K_PAGEDOWN 136 // Cursor Key Page Down
106#define VI_K_FUN1 137 // Function Key F1
107#define VI_K_FUN2 138 // Function Key F2
108#define VI_K_FUN3 139 // Function Key F3
109#define VI_K_FUN4 140 // Function Key F4
110#define VI_K_FUN5 141 // Function Key F5
111#define VI_K_FUN6 142 // Function Key F6
112#define VI_K_FUN7 143 // Function Key F7
113#define VI_K_FUN8 144 // Function Key F8
114#define VI_K_FUN9 145 // Function Key F9
115#define VI_K_FUN10 146 // Function Key F10
116#define VI_K_FUN11 147 // Function Key F11
117#define VI_K_FUN12 148 // Function Key F12
118
119static const int YANKONLY = FALSE;
120static const int YANKDEL = TRUE;
121static const int FORWARD = 1; // code depends on "1" for array index
122static const int BACK = -1; // code depends on "-1" for array index
123static const int LIMITED = 0; // how much of text[] in char_search
124static const int FULL = 1; // how much of text[] in char_search
125
126static const int S_BEFORE_WS = 1; // used in skip_thing() for moving "dot"
127static const int S_TO_WS = 2; // used in skip_thing() for moving "dot"
128static const int S_OVER_WS = 3; // used in skip_thing() for moving "dot"
129static const int S_END_PUNCT = 4; // used in skip_thing() for moving "dot"
130static const int S_END_ALNUM = 5; // used in skip_thing() for moving "dot"
131
132typedef unsigned char Byte;
133
134
135static int editing; // >0 while we are editing a file
136static int cmd_mode; // 0=command 1=insert
137static int file_modified; // buffer contents changed
138static int err_method; // indicate error with beep or flash
139static int fn_start; // index of first cmd line file name
140static int save_argc; // how many file names on cmd line
141static int cmdcnt; // repetition count
142static fd_set rfds; // use select() for small sleeps
143static struct timeval tv; // use select() for small sleeps
144static char erase_char; // the users erase character
145static int rows, columns; // the terminal screen is this size
146static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset
147static char *SOs, *SOn; // terminal standout start/normal ESC sequence
148static char *bell; // terminal bell sequence
149static char *Ceol, *Ceos; // Clear-end-of-line and Clear-end-of-screen ESC sequence
150static char *CMrc; // Cursor motion arbitrary destination ESC sequence
151static char *CMup, *CMdown; // Cursor motion up and down ESC sequence
152static Byte *status_buffer; // mesages to the user
153static Byte last_input_char; // last char read from user
154static Byte last_forward_char; // last char searched for with 'f'
155static Byte *cfn; // previous, current, and next file name
156static Byte *text, *end, *textend; // pointers to the user data in memory
157static Byte *screen; // pointer to the virtual screen buffer
158static int screensize; // and its size
159static Byte *screenbegin; // index into text[], of top line on the screen
160static Byte *dot; // where all the action takes place
161static int tabstop;
162static struct termios term_orig, term_vi; // remember what the cooked mode was
163
164#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
165static int last_row; // where the cursor was last moved to
166#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
167#ifdef BB_FEATURE_VI_USE_SIGNALS
168static jmp_buf restart; // catch_sig()
169#endif /* BB_FEATURE_VI_USE_SIGNALS */
170#ifdef BB_FEATURE_VI_WIN_RESIZE
171static struct winsize winsize; // remember the window size
172#endif /* BB_FEATURE_VI_WIN_RESIZE */
173#ifdef BB_FEATURE_VI_DOT_CMD
174static int adding2q; // are we currently adding user input to q
175static Byte *last_modifying_cmd; // last modifying cmd for "."
176static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read"
177#endif /* BB_FEATURE_VI_DOT_CMD */
178#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK)
179static Byte *modifying_cmds; // cmds that modify text[]
180#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */
181#ifdef BB_FEATURE_VI_READONLY
182static int vi_readonly, readonly;
183#endif /* BB_FEATURE_VI_READONLY */
184#ifdef BB_FEATURE_VI_SETOPTS
185static int autoindent;
186static int showmatch;
187static int ignorecase;
188#endif /* BB_FEATURE_VI_SETOPTS */
189#ifdef BB_FEATURE_VI_YANKMARK
190static Byte *reg[28]; // named register a-z, "D", and "U" 0-25,26,27
191static int YDreg, Ureg; // default delete register and orig line for "U"
192static Byte *mark[28]; // user marks points somewhere in text[]- a-z and previous context ''
193static Byte *context_start, *context_end;
194#endif /* BB_FEATURE_VI_YANKMARK */
195#ifdef BB_FEATURE_VI_SEARCH
196static Byte *last_search_pattern; // last pattern from a '/' or '?' search
197#endif /* BB_FEATURE_VI_SEARCH */
198
199
200static void edit_file(Byte *); // edit one file
201static void do_cmd(Byte); // execute a command
202static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot
203static Byte *begin_line(Byte *); // return pointer to cur line B-o-l
204static Byte *end_line(Byte *); // return pointer to cur line E-o-l
205static Byte *dollar_line(Byte *); // return pointer to just before NL
206static Byte *prev_line(Byte *); // return pointer to prev line B-o-l
207static Byte *next_line(Byte *); // return pointer to next line B-o-l
208static Byte *end_screen(void); // get pointer to last char on screen
209static int count_lines(Byte *, Byte *); // count line from start to stop
210static Byte *find_line(int); // find begining of line #li
211static Byte *move_to_col(Byte *, int); // move "p" to column l
212static int isblnk(Byte); // is the char a blank or tab
213static void dot_left(void); // move dot left- dont leave line
214static void dot_right(void); // move dot right- dont leave line
215static void dot_begin(void); // move dot to B-o-l
216static void dot_end(void); // move dot to E-o-l
217static void dot_next(void); // move dot to next line B-o-l
218static void dot_prev(void); // move dot to prev line B-o-l
219static void dot_scroll(int, int); // move the screen up or down
220static void dot_skip_over_ws(void); // move dot pat WS
221static void dot_delete(void); // delete the char at 'dot'
222static Byte *bound_dot(Byte *); // make sure text[0] <= P < "end"
223static Byte *new_screen(int, int); // malloc virtual screen memory
224static Byte *new_text(int); // malloc memory for text[] buffer
225static Byte *char_insert(Byte *, Byte); // insert the char c at 'p'
226static Byte *stupid_insert(Byte *, Byte); // stupidly insert the char c at 'p'
227static Byte find_range(Byte **, Byte **, Byte); // return pointers for an object
228static int st_test(Byte *, int, int, Byte *); // helper for skip_thing()
229static Byte *skip_thing(Byte *, int, int, int); // skip some object
230static Byte *find_pair(Byte *, Byte); // find matching pair () [] {}
231static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte hole
232static Byte *text_hole_make(Byte *, int); // at "p", make a 'size' byte hole
233static Byte *yank_delete(Byte *, Byte *, int, int); // yank text[] into register then delete
234static void show_help(void); // display some help info
235static void print_literal(Byte *, Byte *); // copy s to buf, convert unprintable
236static void rawmode(void); // set "raw" mode on tty
237static void cookmode(void); // return to "cooked" mode on tty
238static int mysleep(int); // sleep for 'h' 1/100 seconds
239static Byte readit(void); // read (maybe cursor) key from stdin
240static Byte get_one_char(void); // read 1 char from stdin
241static int file_size(Byte *); // what is the byte size of "fn"
242static int file_insert(Byte *, Byte *, int);
243static int file_write(Byte *, Byte *, Byte *);
244static void place_cursor(int, int, int);
245static void screen_erase();
246static void clear_to_eol(void);
247static void clear_to_eos(void);
248static void standout_start(void); // send "start reverse video" sequence
249static void standout_end(void); // send "end reverse video" sequence
250static void flash(int); // flash the terminal screen
251static void beep(void); // beep the terminal
252static void indicate_error(char); // use flash or beep to indicate error
253static void show_status_line(void); // put a message on the bottom line
254static void psb(char *, ...); // Print Status Buf
255static void psbs(char *, ...); // Print Status Buf in standout mode
256static void ni(Byte *); // display messages
257static void edit_status(void); // show file status on status line
258static void redraw(int); // force a full screen refresh
259static void format_line(Byte*, Byte*, int);
260static void refresh(int); // update the terminal from screen[]
261
262#ifdef BB_FEATURE_VI_SEARCH
263static Byte *char_search(Byte *, Byte *, int, int); // search for pattern starting at p
264static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase"
265#endif /* BB_FEATURE_VI_SEARCH */
266#ifdef BB_FEATURE_VI_COLON
267static void Hit_Return(void);
268static Byte *get_one_address(Byte *, int *); // get colon addr, if present
269static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present
270static void colon(Byte *); // execute the "colon" mode cmds
271#endif /* BB_FEATURE_VI_COLON */
272static Byte *get_input_line(Byte *); // get input line- use "status line"
273#ifdef BB_FEATURE_VI_USE_SIGNALS
274static void winch_sig(int); // catch window size changes
275static void suspend_sig(int); // catch ctrl-Z
276static void alarm_sig(int); // catch alarm time-outs
277static void catch_sig(int); // catch ctrl-C
278static void core_sig(int); // catch a core dump signal
279#endif /* BB_FEATURE_VI_USE_SIGNALS */
280#ifdef BB_FEATURE_VI_DOT_CMD
281static void start_new_cmd_q(Byte); // new queue for command
282static void end_cmd_q(); // stop saving input chars
283#else /* BB_FEATURE_VI_DOT_CMD */
284#define end_cmd_q()
285#endif /* BB_FEATURE_VI_DOT_CMD */
286#ifdef BB_FEATURE_VI_WIN_RESIZE
287static void window_size_get(int); // find out what size the window is
288#endif /* BB_FEATURE_VI_WIN_RESIZE */
289#ifdef BB_FEATURE_VI_SETOPTS
290static void showmatching(Byte *); // show the matching pair () [] {}
291#endif /* BB_FEATURE_VI_SETOPTS */
292#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME)
293static Byte *string_insert(Byte *, Byte *); // insert the string at 'p'
294#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */
295#ifdef BB_FEATURE_VI_YANKMARK
296static Byte *text_yank(Byte *, Byte *, int); // save copy of "p" into a register
297static Byte what_reg(void); // what is letter of current YDreg
298static void check_context(Byte); // remember context for '' command
299static Byte *swap_context(Byte *); // goto new context for '' command
300#endif /* BB_FEATURE_VI_YANKMARK */
301#ifdef BB_FEATURE_VI_CRASHME
302static void crash_dummy();
303static void crash_test();
304static int crashme = 0;
305#endif /* BB_FEATURE_VI_CRASHME */
306
307
308extern int vi_main(int argc, char **argv)
309{
310 int c;
311
312#ifdef BB_FEATURE_VI_YANKMARK
313 int i;
314#endif /* BB_FEATURE_VI_YANKMARK */
315
316 CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence
317 CMup= "\033[A"; // move cursor up one line, same col
318 CMdown="\n"; // move cursor down one line, same col
319 Ceol= "\033[0K"; // Clear from cursor to end of line
320 Ceos= "\033[0J"; // Clear from cursor to end of screen
321 SOs = "\033[7m"; // Terminal standout mode on
322 SOn = "\033[0m"; // Terminal standout mode off
323 bell= "\007"; // Terminal bell sequence
324#ifdef BB_FEATURE_VI_CRASHME
325 (void) srand((long) getpid());
326#endif /* BB_FEATURE_VI_CRASHME */
327 status_buffer = (Byte *) malloc(200); // hold messages to user
328#ifdef BB_FEATURE_VI_READONLY
329 vi_readonly = readonly = FALSE;
330 if (strncmp(argv[0], "view", 4) == 0) {
331 readonly = TRUE;
332 vi_readonly = TRUE;
333 }
334#endif /* BB_FEATURE_VI_READONLY */
335#ifdef BB_FEATURE_VI_SETOPTS
336 autoindent = 1;
337 ignorecase = 1;
338 showmatch = 1;
339#endif /* BB_FEATURE_VI_SETOPTS */
340#ifdef BB_FEATURE_VI_YANKMARK
341 for (i = 0; i < 28; i++) {
342 reg[i] = 0;
343 } // init the yank regs
344#endif /* BB_FEATURE_VI_YANKMARK */
345#ifdef BB_FEATURE_VI_DOT_CMD
346 modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[]
347#endif /* BB_FEATURE_VI_DOT_CMD */
348
349 // 1- process $HOME/.exrc file
350 // 2- process EXINIT variable from environment
351 // 3- process command line args
352 while ((c = getopt(argc, argv, "hCR")) != -1) {
353 switch (c) {
354#ifdef BB_FEATURE_VI_CRASHME
355 case 'C':
356 crashme = 1;
357 break;
358#endif /* BB_FEATURE_VI_CRASHME */
359#ifdef BB_FEATURE_VI_READONLY
360 case 'R': // Read-only flag
361 readonly = TRUE;
362 break;
363#endif /* BB_FEATURE_VI_READONLY */
364 //case 'r': // recover flag- ignore- we don't use tmp file
365 //case 'x': // encryption flag- ignore
366 //case 'c': // execute command first
367 //case 'h': // help -- just use default
368 default:
369 show_help();
370 return 1;
371 }
372 }
373
374 // The argv array can be used by the ":next" and ":rewind" commands
375 // save optind.
376 fn_start = optind; // remember first file name for :next and :rew
377 save_argc = argc;
378
379 //----- This is the main file handling loop --------------
380 if (optind >= argc) {
381 editing = 1; // 0= exit, 1= one file, 2= multiple files
382 edit_file(0);
383 } else {
384 for (; optind < argc; optind++) {
385 editing = 1; // 0=exit, 1=one file, 2+ =many files
386 if (cfn != 0)
387 free(cfn);
388 cfn = (Byte *) strdup(argv[optind]);
389 edit_file(cfn);
390 }
391 }
392 //-----------------------------------------------------------
393
394 return (0);
395}
396
397static void edit_file(Byte * fn)
398{
399 char c;
400 int cnt, size, ch;
401
402#ifdef BB_FEATURE_VI_USE_SIGNALS
403 char *msg;
404 int sig;
405#endif /* BB_FEATURE_VI_USE_SIGNALS */
406#ifdef BB_FEATURE_VI_YANKMARK
407 static Byte *cur_line;
408#endif /* BB_FEATURE_VI_YANKMARK */
409
410 rawmode();
411 rows = 24;
412 columns = 80;
413 ch= -1;
414#ifdef BB_FEATURE_VI_WIN_RESIZE
415 window_size_get(0);
416#endif /* BB_FEATURE_VI_WIN_RESIZE */
417 new_screen(rows, columns); // get memory for virtual screen
418
419 cnt = file_size(fn); // file size
420 size = 2 * cnt; // 200% of file size
421 new_text(size); // get a text[] buffer
422 screenbegin = dot = end = text;
423 if (fn != 0) {
424 ch= file_insert(fn, text, cnt);
425 }
426 if (ch < 1) {
427 (void) char_insert(text, '\n'); // start empty buf with dummy line
428 }
429 file_modified = FALSE;
430#ifdef BB_FEATURE_VI_YANKMARK
431 YDreg = 26; // default Yank/Delete reg
432 Ureg = 27; // hold orig line for "U" cmd
433 for (cnt = 0; cnt < 28; cnt++) {
434 mark[cnt] = 0;
435 } // init the marks
436 mark[26] = mark[27] = text; // init "previous context"
437#endif /* BB_FEATURE_VI_YANKMARK */
438
439 err_method = 1; // flash
440 last_forward_char = last_input_char = '\0';
441 crow = 0;
442 ccol = 0;
443 edit_status();
444
445#ifdef BB_FEATURE_VI_USE_SIGNALS
446 signal(SIGHUP, catch_sig);
447 signal(SIGINT, catch_sig);
448 signal(SIGALRM, alarm_sig);
449 signal(SIGTERM, catch_sig);
450 signal(SIGQUIT, core_sig);
451 signal(SIGILL, core_sig);
452 signal(SIGTRAP, core_sig);
453 signal(SIGIOT, core_sig);
454 signal(SIGABRT, core_sig);
455 signal(SIGFPE, core_sig);
456 signal(SIGBUS, core_sig);
457 signal(SIGSEGV, core_sig);
458#ifdef SIGSYS
459 signal(SIGSYS, core_sig);
460#endif
461 signal(SIGWINCH, winch_sig);
462 signal(SIGTSTP, suspend_sig);
463 sig = setjmp(restart);
464 if (sig != 0) {
465 msg = "";
466 if (sig == SIGWINCH)
467 msg = "(window resize)";
468 if (sig == SIGHUP)
469 msg = "(hangup)";
470 if (sig == SIGINT)
471 msg = "(interrupt)";
472 if (sig == SIGTERM)
473 msg = "(terminate)";
474 if (sig == SIGBUS)
475 msg = "(bus error)";
476 if (sig == SIGSEGV)
477 msg = "(I tried to touch invalid memory)";
478 if (sig == SIGALRM)
479 msg = "(alarm)";
480
481 psbs("-- caught signal %d %s--", sig, msg);
482 screenbegin = dot = text;
483 }
484#endif /* BB_FEATURE_VI_USE_SIGNALS */
485
486 editing = 1;
487 cmd_mode = 0; // 0=command 1=insert 2='R'eplace
488 cmdcnt = 0;
489 tabstop = 8;
490 offset = 0; // no horizontal offset
491 c = '\0';
492#ifdef BB_FEATURE_VI_DOT_CMD
493 if (last_modifying_cmd != 0)
494 free(last_modifying_cmd);
495 if (ioq_start != NULL)
496 free(ioq_start);
497 ioq = ioq_start = last_modifying_cmd = 0;
498 adding2q = 0;
499#endif /* BB_FEATURE_VI_DOT_CMD */
500 redraw(FALSE); // dont force every col re-draw
501 show_status_line();
502
503 //------This is the main Vi cmd handling loop -----------------------
504 while (editing > 0) {
505#ifdef BB_FEATURE_VI_CRASHME
506 if (crashme > 0) {
507 if ((end - text) > 1) {
508 crash_dummy(); // generate a random command
509 } else {
510 crashme = 0;
511 dot =
512 string_insert(text, (Byte *) "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string
513 refresh(FALSE);
514 }
515 }
516#endif /* BB_FEATURE_VI_CRASHME */
517 last_input_char = c = get_one_char(); // get a cmd from user
518#ifdef BB_FEATURE_VI_YANKMARK
519 // save a copy of the current line- for the 'U" command
520 if (begin_line(dot) != cur_line) {
521 cur_line = begin_line(dot);
522 text_yank(begin_line(dot), end_line(dot), Ureg);
523 }
524#endif /* BB_FEATURE_VI_YANKMARK */
525#ifdef BB_FEATURE_VI_DOT_CMD
526 // These are commands that change text[].
527 // Remember the input for the "." command
528 if (!adding2q && ioq_start == 0
529 && strchr((char *) modifying_cmds, c) != NULL) {
530 start_new_cmd_q(c);
531 }
532#endif /* BB_FEATURE_VI_DOT_CMD */
533 do_cmd(c); // execute the user command
534 //
535 // poll to see if there is input already waiting. if we are
536 // not able to display output fast enough to keep up, skip
537 // the display update until we catch up with input.
538 if (mysleep(0) == 0) {
539 // no input pending- so update output
540 refresh(FALSE);
541 show_status_line();
542 }
543#ifdef BB_FEATURE_VI_CRASHME
544 if (crashme > 0)
545 crash_test(); // test editor variables
546#endif /* BB_FEATURE_VI_CRASHME */
547 }
548 //-------------------------------------------------------------------
549
550 place_cursor(rows, 0, FALSE); // go to bottom of screen
551 clear_to_eol(); // Erase to end of line
552 cookmode();
553}
554
555static Byte readbuffer[BUFSIZ];
556
557#ifdef BB_FEATURE_VI_CRASHME
558static int totalcmds = 0;
559static int Mp = 85; // Movement command Probability
560static int Np = 90; // Non-movement command Probability
561static int Dp = 96; // Delete command Probability
562static int Ip = 97; // Insert command Probability
563static int Yp = 98; // Yank command Probability
564static int Pp = 99; // Put command Probability
565static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0;
566char chars[20] = "\t012345 abcdABCD-=.$";
567char *words[20] = { "this", "is", "a", "test",
568 "broadcast", "the", "emergency", "of",
569 "system", "quick", "brown", "fox",
570 "jumped", "over", "lazy", "dogs",
571 "back", "January", "Febuary", "March"
572};
573char *lines[20] = {
574 "You should have received a copy of the GNU General Public License\n",
575 "char c, cm, *cmd, *cmd1;\n",
576 "generate a command by percentages\n",
577 "Numbers may be typed as a prefix to some commands.\n",
578 "Quit, discarding changes!\n",
579 "Forced write, if permission originally not valid.\n",
580 "In general, any ex or ed command (such as substitute or delete).\n",
581 "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
582 "Please get w/ me and I will go over it with you.\n",
583 "The following is a list of scheduled, committed changes.\n",
584 "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
585 "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
586 "Any question about transactions please contact Sterling Huxley.\n",
587 "I will try to get back to you by Friday, December 31.\n",
588 "This Change will be implemented on Friday.\n",
589 "Let me know if you have problems accessing this;\n",
590 "Sterling Huxley recently added you to the access list.\n",
591 "Would you like to go to lunch?\n",
592 "The last command will be automatically run.\n",
593 "This is too much english for a computer geek.\n",
594};
595char *multilines[20] = {
596 "You should have received a copy of the GNU General Public License\n",
597 "char c, cm, *cmd, *cmd1;\n",
598 "generate a command by percentages\n",
599 "Numbers may be typed as a prefix to some commands.\n",
600 "Quit, discarding changes!\n",
601 "Forced write, if permission originally not valid.\n",
602 "In general, any ex or ed command (such as substitute or delete).\n",
603 "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
604 "Please get w/ me and I will go over it with you.\n",
605 "The following is a list of scheduled, committed changes.\n",
606 "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
607 "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
608 "Any question about transactions please contact Sterling Huxley.\n",
609 "I will try to get back to you by Friday, December 31.\n",
610 "This Change will be implemented on Friday.\n",
611 "Let me know if you have problems accessing this;\n",
612 "Sterling Huxley recently added you to the access list.\n",
613 "Would you like to go to lunch?\n",
614 "The last command will be automatically run.\n",
615 "This is too much english for a computer geek.\n",
616};
617
618// create a random command to execute
619static void crash_dummy()
620{
621 static int sleeptime; // how long to pause between commands
622 char c, cm, *cmd, *cmd1;
623 int i, cnt, thing, rbi, startrbi, percent;
624
625 // "dot" movement commands
626 cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
627
628 // is there already a command running?
629 if (strlen((char *) readbuffer) > 0)
630 goto cd1;
631 cd0:
632 startrbi = rbi = 0;
633 sleeptime = 0; // how long to pause between commands
634 memset(readbuffer, '\0', BUFSIZ - 1); // clear the read buffer
635 // generate a command by percentages
636 percent = (int) lrand48() % 100; // get a number from 0-99
637 if (percent < Mp) { // Movement commands
638 // available commands
639 cmd = cmd1;
640 M++;
641 } else if (percent < Np) { // non-movement commands
642 cmd = "mz<>\'\""; // available commands
643 N++;
644 } else if (percent < Dp) { // Delete commands
645 cmd = "dx"; // available commands
646 D++;
647 } else if (percent < Ip) { // Inset commands
648 cmd = "iIaAsrJ"; // available commands
649 I++;
650 } else if (percent < Yp) { // Yank commands
651 cmd = "yY"; // available commands
652 Y++;
653 } else if (percent < Pp) { // Put commands
654 cmd = "pP"; // available commands
655 P++;
656 } else {
657 // We do not know how to handle this command, try again
658 U++;
659 goto cd0;
660 }
661 // randomly pick one of the available cmds from "cmd[]"
662 i = (int) lrand48() % strlen(cmd);
663 cm = cmd[i];
664 if (strchr(":\024", cm))
665 goto cd0; // dont allow colon or ctrl-T commands
666 readbuffer[rbi++] = cm; // put cmd into input buffer
667
668 // now we have the command-
669 // there are 1, 2, and multi char commands
670 // find out which and generate the rest of command as necessary
671 if (strchr("dmryz<>\'\"", cm)) { // 2-char commands
672 cmd1 = " \n\r0$^-+wWeEbBhjklHL";
673 if (cm == 'm' || cm == '\'' || cm == '\"') { // pick a reg[]
674 cmd1 = "abcdefghijklmnopqrstuvwxyz";
675 }
676 thing = (int) lrand48() % strlen(cmd1); // pick a movement command
677 c = cmd1[thing];
678 readbuffer[rbi++] = c; // add movement to input buffer
679 }
680 if (strchr("iIaAsc", cm)) { // multi-char commands
681 if (cm == 'c') {
682 // change some thing
683 thing = (int) lrand48() % strlen(cmd1); // pick a movement command
684 c = cmd1[thing];
685 readbuffer[rbi++] = c; // add movement to input buffer
686 }
687 thing = (int) lrand48() % 4; // what thing to insert
688 cnt = (int) lrand48() % 10; // how many to insert
689 for (i = 0; i < cnt; i++) {
690 if (thing == 0) { // insert chars
691 readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))];
692 } else if (thing == 1) { // insert words
693 strcat((char *) readbuffer, words[(int) lrand48() % 20]);
694 strcat((char *) readbuffer, " ");
695 sleeptime = 0; // how fast to type
696 } else if (thing == 2) { // insert lines
697 strcat((char *) readbuffer, lines[(int) lrand48() % 20]);
698 sleeptime = 0; // how fast to type
699 } else { // insert multi-lines
700 strcat((char *) readbuffer, multilines[(int) lrand48() % 20]);
701 sleeptime = 0; // how fast to type
702 }
703 }
704 strcat((char *) readbuffer, "\033");
705 }
706 cd1:
707 totalcmds++;
708 if (sleeptime > 0)
709 (void) mysleep(sleeptime); // sleep 1/100 sec
710}
711
712// test to see if there are any errors
713static void crash_test()
714{
715 static time_t oldtim;
716 time_t tim;
717 char d[2], buf[BUFSIZ], msg[BUFSIZ];
718
719 msg[0] = '\0';
720 if (end < text) {
721 strcat((char *) msg, "end<text ");
722 }
723 if (end > textend) {
724 strcat((char *) msg, "end>textend ");
725 }
726 if (dot < text) {
727 strcat((char *) msg, "dot<text ");
728 }
729 if (dot > end) {
730 strcat((char *) msg, "dot>end ");
731 }
732 if (screenbegin < text) {
733 strcat((char *) msg, "screenbegin<text ");
734 }
735 if (screenbegin > end - 1) {
736 strcat((char *) msg, "screenbegin>end-1 ");
737 }
738
739 if (strlen(msg) > 0) {
740 alarm(0);
741 sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
742 totalcmds, last_input_char, msg, SOs, SOn);
743 write(1, buf, strlen(buf));
744 while (read(0, d, 1) > 0) {
745 if (d[0] == '\n' || d[0] == '\r')
746 break;
747 }
748 alarm(3);
749 }
750 tim = (time_t) time((time_t *) 0);
751 if (tim >= (oldtim + 3)) {
752 sprintf((char *) status_buffer,
753 "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d",
754 totalcmds, M, N, I, D, Y, P, U, end - text + 1);
755 oldtim = tim;
756 }
757 return;
758}
759#endif /* BB_FEATURE_VI_CRASHME */
760
761//---------------------------------------------------------------------
762//----- the Ascii Chart -----------------------------------------------
763//
764// 00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel
765// 08 bs 09 ht 0a nl 0b vt 0c np 0d cr 0e so 0f si
766// 10 dle 11 dc1 12 dc2 13 dc3 14 dc4 15 nak 16 syn 17 etb
767// 18 can 19 em 1a sub 1b esc 1c fs 1d gs 1e rs 1f us
768// 20 sp 21 ! 22 " 23 # 24 $ 25 % 26 & 27 '
769// 28 ( 29 ) 2a * 2b + 2c , 2d - 2e . 2f /
770// 30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7
771// 38 8 39 9 3a : 3b ; 3c < 3d = 3e > 3f ?
772// 40 @ 41 A 42 B 43 C 44 D 45 E 46 F 47 G
773// 48 H 49 I 4a J 4b K 4c L 4d M 4e N 4f O
774// 50 P 51 Q 52 R 53 S 54 T 55 U 56 V 57 W
775// 58 X 59 Y 5a Z 5b [ 5c \ 5d ] 5e ^ 5f _
776// 60 ` 61 a 62 b 63 c 64 d 65 e 66 f 67 g
777// 68 h 69 i 6a j 6b k 6c l 6d m 6e n 6f o
778// 70 p 71 q 72 r 73 s 74 t 75 u 76 v 77 w
779// 78 x 79 y 7a z 7b { 7c | 7d } 7e ~ 7f del
780//---------------------------------------------------------------------
781
782//----- Execute a Vi Command -----------------------------------
783static void do_cmd(Byte c)
784{
785 Byte c1, *p, *q, *msg, buf[9], *save_dot;
786 int cnt, i, j, dir, yf;
787
788 c1 = c; // quiet the compiler
789 cnt = yf = dir = 0; // quiet the compiler
790 p = q = save_dot = msg = buf; // quiet the compiler
791 memset(buf, '\0', 9); // clear buf
792 if (cmd_mode == 2) {
793 // we are 'R'eplacing the current *dot with new char
794 if (*dot == '\n') {
795 // don't Replace past E-o-l
796 cmd_mode = 1; // convert to insert
797 } else {
798 if (1 <= c && c <= 127) { // only ASCII chars
799 if (c != 27)
800 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char
801 dot = char_insert(dot, c); // insert new char
802 }
803 goto dc1;
804 }
805 }
806 if (cmd_mode == 1) {
807 // hitting "Insert" twice means "R" replace mode
808 if (c == VI_K_INSERT) goto dc5;
809 // insert the char c at "dot"
810 if (1 <= c && c <= 127) {
811 dot = char_insert(dot, c); // only ASCII chars
812 }
813 goto dc1;
814 }
815
816 switch (c) {
817 //case 0x01: // soh
818 //case 0x09: // ht
819 //case 0x0b: // vt
820 //case 0x0e: // so
821 //case 0x0f: // si
822 //case 0x10: // dle
823 //case 0x11: // dc1
824 //case 0x13: // dc3
825#ifdef BB_FEATURE_VI_CRASHME
826 case 0x14: // dc4 ctrl-T
827 crashme = (crashme == 0) ? 1 : 0;
828 break;
829#endif /* BB_FEATURE_VI_CRASHME */
830 //case 0x16: // syn
831 //case 0x17: // etb
832 //case 0x18: // can
833 //case 0x1c: // fs
834 //case 0x1d: // gs
835 //case 0x1e: // rs
836 //case 0x1f: // us
837 //case '!': // !-
838 //case '#': // #-
839 //case '&': // &-
840 //case '(': // (-
841 //case ')': // )-
842 //case '*': // *-
843 //case ',': // ,-
844 //case '=': // =-
845 //case '@': // @-
846 //case 'F': // F-
847 //case 'K': // K-
848 //case 'Q': // Q-
849 //case 'S': // S-
850 //case 'T': // T-
851 //case 'V': // V-
852 //case '[': // [-
853 //case '\\': // \-
854 //case ']': // ]-
855 //case '_': // _-
856 //case '`': // `-
857 //case 'g': // g-
858 //case 'u': // u- FIXME- there is no undo
859 //case 'v': // v-
860 default: // unrecognised command
861 buf[0] = c;
862 buf[1] = '\0';
863 if (c <= ' ') {
864 buf[0] = '^';
865 buf[1] = c + '@';
866 buf[2] = '\0';
867 }
868 ni((Byte *) buf);
869 end_cmd_q(); // stop adding to q
870 case 0x00: // nul- ignore
871 break;
872 case 2: // ctrl-B scroll up full screen
873 case VI_K_PAGEUP: // Cursor Key Page Up
874 dot_scroll(rows - 2, -1);
875 break;
876#ifdef BB_FEATURE_VI_USE_SIGNALS
877 case 0x03: // ctrl-C interrupt
878 longjmp(restart, 1);
879 break;
880 case 26: // ctrl-Z suspend
881 suspend_sig(SIGTSTP);
882 break;
883#endif /* BB_FEATURE_VI_USE_SIGNALS */
884 case 4: // ctrl-D scroll down half screen
885 dot_scroll((rows - 2) / 2, 1);
886 break;
887 case 5: // ctrl-E scroll down one line
888 dot_scroll(1, 1);
889 break;
890 case 6: // ctrl-F scroll down full screen
891 case VI_K_PAGEDOWN: // Cursor Key Page Down
892 dot_scroll(rows - 2, 1);
893 break;
894 case 7: // ctrl-G show current status
895 edit_status();
896 break;
897 case 'h': // h- move left
898 case VI_K_LEFT: // cursor key Left
899 case 8: // ctrl-H- move left (This may be ERASE char)
900 case 127: // DEL- move left (This may be ERASE char)
901 if (cmdcnt-- > 1) {
902 do_cmd(c);
903 } // repeat cnt
904 dot_left();
905 break;
906 case 10: // Newline ^J
907 case 'j': // j- goto next line, same col
908 case VI_K_DOWN: // cursor key Down
909 if (cmdcnt-- > 1) {
910 do_cmd(c);
911 } // repeat cnt
912 dot_next(); // go to next B-o-l
913 dot = move_to_col(dot, ccol + offset); // try stay in same col
914 break;
915 case 12: // ctrl-L force redraw whole screen
916 case 18: // ctrl-R force redraw
917 place_cursor(0, 0, FALSE); // put cursor in correct place
918 clear_to_eos(); // tel terminal to erase display
919 (void) mysleep(10);
920 screen_erase(); // erase the internal screen buffer
921 refresh(TRUE); // this will redraw the entire display
922 break;
923 case 13: // Carriage Return ^M
924 case '+': // +- goto next line
925 if (cmdcnt-- > 1) {
926 do_cmd(c);
927 } // repeat cnt
928 dot_next();
929 dot_skip_over_ws();
930 break;
931 case 21: // ctrl-U scroll up half screen
932 dot_scroll((rows - 2) / 2, -1);
933 break;
934 case 25: // ctrl-Y scroll up one line
935 dot_scroll(1, -1);
936 break;
937 case 27: // esc
938 if (cmd_mode == 0)
939 indicate_error(c);
940 cmd_mode = 0; // stop insrting
941 end_cmd_q();
942 *status_buffer = '\0'; // clear status buffer
943 break;
944 case ' ': // move right
945 case 'l': // move right
946 case VI_K_RIGHT: // Cursor Key Right
947 if (cmdcnt-- > 1) {
948 do_cmd(c);
949 } // repeat cnt
950 dot_right();
951 break;
952#ifdef BB_FEATURE_VI_YANKMARK
953 case '"': // "- name a register to use for Delete/Yank
954 c1 = get_one_char();
955 c1 = tolower(c1);
956 if (islower(c1)) {
957 YDreg = c1 - 'a';
958 } else {
959 indicate_error(c);
960 }
961 break;
962 case '\'': // '- goto a specific mark
963 c1 = get_one_char();
964 c1 = tolower(c1);
965 if (islower(c1)) {
966 c1 = c1 - 'a';
967 // get the b-o-l
968 q = mark[(int) c1];
969 if (text <= q && q < end) {
970 dot = q;
971 dot_begin(); // go to B-o-l
972 dot_skip_over_ws();
973 }
974 } else if (c1 == '\'') { // goto previous context
975 dot = swap_context(dot); // swap current and previous context
976 dot_begin(); // go to B-o-l
977 dot_skip_over_ws();
978 } else {
979 indicate_error(c);
980 }
981 break;
982 case 'm': // m- Mark a line
983 // this is really stupid. If there are any inserts or deletes
984 // between text[0] and dot then this mark will not point to the
985 // correct location! It could be off by many lines!
986 // Well..., at least its quick and dirty.
987 c1 = get_one_char();
988 c1 = tolower(c1);
989 if (islower(c1)) {
990 c1 = c1 - 'a';
991 // remember the line
992 mark[(int) c1] = dot;
993 } else {
994 indicate_error(c);
995 }
996 break;
997 case 'P': // P- Put register before
998 case 'p': // p- put register after
999 p = reg[YDreg];
1000 if (p == 0) {
1001 psbs("Nothing in register %c", what_reg());
1002 break;
1003 }
1004 // are we putting whole lines or strings
1005 if (strchr((char *) p, '\n') != NULL) {
1006 if (c == 'P') {
1007 dot_begin(); // putting lines- Put above
1008 }
1009 if (c == 'p') {
1010 // are we putting after very last line?
1011 if (end_line(dot) == (end - 1)) {
1012 dot = end; // force dot to end of text[]
1013 } else {
1014 dot_next(); // next line, then put before
1015 }
1016 }
1017 } else {
1018 if (c == 'p')
1019 dot_right(); // move to right, can move to NL
1020 }
1021 dot = string_insert(dot, p); // insert the string
1022 end_cmd_q(); // stop adding to q
1023 break;
1024 case 'U': // U- Undo; replace current line with original version
1025 if (reg[Ureg] != 0) {
1026 p = begin_line(dot);
1027 q = end_line(dot);
1028 p = text_hole_delete(p, q); // delete cur line
1029 p = string_insert(p, reg[Ureg]); // insert orig line
1030 dot = p;
1031 dot_skip_over_ws();
1032 }
1033 break;
1034#endif /* BB_FEATURE_VI_YANKMARK */
1035 case '$': // $- goto end of line
1036 case VI_K_END: // Cursor Key End
1037 if (cmdcnt-- > 1) {
1038 do_cmd(c);
1039 } // repeat cnt
1040 dot = end_line(dot + 1);
1041 break;
1042 case '%': // %- find matching char of pair () [] {}
1043 for (q = dot; q < end && *q != '\n'; q++) {
1044 if (strchr("()[]{}", *q) != NULL) {
1045 // we found half of a pair
1046 p = find_pair(q, *q);
1047 if (p == NULL) {
1048 indicate_error(c);
1049 } else {
1050 dot = p;
1051 }
1052 break;
1053 }
1054 }
1055 if (*q == '\n')
1056 indicate_error(c);
1057 break;
1058 case 'f': // f- forward to a user specified char
1059 last_forward_char = get_one_char(); // get the search char
1060 //
1061 // dont seperate these two commands. 'f' depends on ';'
1062 //
1063 //**** fall thru to ... 'i'
1064 case ';': // ;- look at rest of line for last forward char
1065 if (cmdcnt-- > 1) {
1066 do_cmd(';');
1067 } // repeat cnt
1068 if (last_forward_char == 0) break;
1069 q = dot + 1;
1070 while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
1071 q++;
1072 }
1073 if (*q == last_forward_char)
1074 dot = q;
1075 break;
1076 case '-': // -- goto prev line
1077 if (cmdcnt-- > 1) {
1078 do_cmd(c);
1079 } // repeat cnt
1080 dot_prev();
1081 dot_skip_over_ws();
1082 break;
1083#ifdef BB_FEATURE_VI_DOT_CMD
1084 case '.': // .- repeat the last modifying command
1085 // Stuff the last_modifying_cmd back into stdin
1086 // and let it be re-executed.
1087 if (last_modifying_cmd != 0) {
1088 ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd);
1089 }
1090 break;
1091#endif /* BB_FEATURE_VI_DOT_CMD */
1092#ifdef BB_FEATURE_VI_SEARCH
1093 case '?': // /- search for a pattern
1094 case '/': // /- search for a pattern
1095 buf[0] = c;
1096 buf[1] = '\0';
1097 q = get_input_line(buf); // get input line- use "status line"
1098 if (strlen((char *) q) == 1)
1099 goto dc3; // if no pat re-use old pat
1100 if (strlen((char *) q) > 1) { // new pat- save it and find
1101 // there is a new pat
1102 if (last_search_pattern != 0) {
1103 free(last_search_pattern);
1104 }
1105 last_search_pattern = (Byte *) strdup((char *) q);
1106 goto dc3; // now find the pattern
1107 }
1108 // user changed mind and erased the "/"- do nothing
1109 break;
1110 case 'N': // N- backward search for last pattern
1111 if (cmdcnt-- > 1) {
1112 do_cmd(c);
1113 } // repeat cnt
1114 dir = BACK; // assume BACKWARD search
1115 p = dot - 1;
1116 if (last_search_pattern[0] == '?') {
1117 dir = FORWARD;
1118 p = dot + 1;
1119 }
1120 goto dc4; // now search for pattern
1121 break;
1122 case 'n': // n- repeat search for last pattern
1123 // search rest of text[] starting at next char
1124 // if search fails return orignal "p" not the "p+1" address
1125 if (cmdcnt-- > 1) {
1126 do_cmd(c);
1127 } // repeat cnt
1128 dc3:
1129 if (last_search_pattern == 0) {
1130 msg = (Byte *) "No previous regular expression";
1131 goto dc2;
1132 }
1133 if (last_search_pattern[0] == '/') {
1134 dir = FORWARD; // assume FORWARD search
1135 p = dot + 1;
1136 }
1137 if (last_search_pattern[0] == '?') {
1138 dir = BACK;
1139 p = dot - 1;
1140 }
1141 dc4:
1142 q = char_search(p, last_search_pattern + 1, dir, FULL);
1143 if (q != NULL) {
1144 dot = q; // good search, update "dot"
1145 msg = (Byte *) "";
1146 goto dc2;
1147 }
1148 // no pattern found between "dot" and "end"- continue at top
1149 p = text;
1150 if (dir == BACK) {
1151 p = end - 1;
1152 }
1153 q = char_search(p, last_search_pattern + 1, dir, FULL);
1154 if (q != NULL) { // found something
1155 dot = q; // found new pattern- goto it
1156 msg = (Byte *) "search hit BOTTOM, continuing at TOP";
1157 if (dir == BACK) {
1158 msg = (Byte *) "search hit TOP, continuing at BOTTOM";
1159 }
1160 } else {
1161 msg = (Byte *) "Pattern not found";
1162 }
1163 dc2:
1164 psbs("%s", msg);
1165 break;
1166 case '{': // {- move backward paragraph
1167 q = char_search(dot, (Byte *) "\n\n", BACK, FULL);
1168 if (q != NULL) { // found blank line
1169 dot = next_line(q); // move to next blank line
1170 }
1171 break;
1172 case '}': // }- move forward paragraph
1173 q = char_search(dot, (Byte *) "\n\n", FORWARD, FULL);
1174 if (q != NULL) { // found blank line
1175 dot = next_line(q); // move to next blank line
1176 }
1177 break;
1178#endif /* BB_FEATURE_VI_SEARCH */
1179 case '0': // 0- goto begining of line
1180 case '1': // 1-
1181 case '2': // 2-
1182 case '3': // 3-
1183 case '4': // 4-
1184 case '5': // 5-
1185 case '6': // 6-
1186 case '7': // 7-
1187 case '8': // 8-
1188 case '9': // 9-
1189 if (c == '0' && cmdcnt < 1) {
1190 dot_begin(); // this was a standalone zero
1191 } else {
1192 cmdcnt = cmdcnt * 10 + (c - '0'); // this 0 is part of a number
1193 }
1194 break;
1195 case ':': // :- the colon mode commands
1196 p = get_input_line((Byte *) ":"); // get input line- use "status line"
1197#ifdef BB_FEATURE_VI_COLON
1198 colon(p); // execute the command
1199#else /* BB_FEATURE_VI_COLON */
1200 if (*p == ':')
1201 p++; // move past the ':'
1202 cnt = strlen((char *) p);
1203 if (cnt <= 0)
1204 break;
1205 if (strncasecmp((char *) p, "quit", cnt) == 0 ||
1206 strncasecmp((char *) p, "q!", cnt) == 0) { // delete lines
1207 if (file_modified == TRUE && p[1] != '!') {
1208 psbs("No write since last change (:quit! overrides)");
1209 } else {
1210 editing = 0;
1211 }
1212 } else if (strncasecmp((char *) p, "write", cnt) == 0 ||
1213 strncasecmp((char *) p, "wq", cnt) == 0) {
1214 cnt = file_write(cfn, text, end - 1);
1215 file_modified = FALSE;
1216 psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt);
1217 if (p[1] == 'q') {
1218 editing = 0;
1219 }
1220 } else if (strncasecmp((char *) p, "file", cnt) == 0 ) {
1221 edit_status(); // show current file status
1222 } else if (sscanf((char *) p, "%d", &j) > 0) {
1223 dot = find_line(j); // go to line # j
1224 dot_skip_over_ws();
1225 } else { // unrecognised cmd
1226 ni((Byte *) p);
1227 }
1228#endif /* BB_FEATURE_VI_COLON */
1229 break;
1230 case '<': // <- Left shift something
1231 case '>': // >- Right shift something
1232 cnt = count_lines(text, dot); // remember what line we are on
1233 c1 = get_one_char(); // get the type of thing to delete
1234 find_range(&p, &q, c1);
1235 (void) yank_delete(p, q, 1, YANKONLY); // save copy before change
1236 p = begin_line(p);
1237 q = end_line(q);
1238 i = count_lines(p, q); // # of lines we are shifting
1239 for ( ; i > 0; i--, p = next_line(p)) {
1240 if (c == '<') {
1241 // shift left- remove tab or 8 spaces
1242 if (*p == '\t') {
1243 // shrink buffer 1 char
1244 (void) text_hole_delete(p, p);
1245 } else if (*p == ' ') {
1246 // we should be calculating columns, not just SPACE
1247 for (j = 0; *p == ' ' && j < tabstop; j++) {
1248 (void) text_hole_delete(p, p);
1249 }
1250 }
1251 } else if (c == '>') {
1252 // shift right -- add tab or 8 spaces
1253 (void) char_insert(p, '\t');
1254 }
1255 }
1256 dot = find_line(cnt); // what line were we on
1257 dot_skip_over_ws();
1258 end_cmd_q(); // stop adding to q
1259 break;
1260 case 'A': // A- append at e-o-l
1261 dot_end(); // go to e-o-l
1262 //**** fall thru to ... 'a'
1263 case 'a': // a- append after current char
1264 if (*dot != '\n')
1265 dot++;
1266 goto dc_i;
1267 break;
1268 case 'B': // B- back a blank-delimited Word
1269 case 'E': // E- end of a blank-delimited word
1270 case 'W': // W- forward a blank-delimited word
1271 if (cmdcnt-- > 1) {
1272 do_cmd(c);
1273 } // repeat cnt
1274 dir = FORWARD;
1275 if (c == 'B')
1276 dir = BACK;
1277 if (c == 'W' || isspace(dot[dir])) {
1278 dot = skip_thing(dot, 1, dir, S_TO_WS);
1279 dot = skip_thing(dot, 2, dir, S_OVER_WS);
1280 }
1281 if (c != 'W')
1282 dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
1283 break;
1284 case 'C': // C- Change to e-o-l
1285 case 'D': // D- delete to e-o-l
1286 save_dot = dot;
1287 dot = dollar_line(dot); // move to before NL
1288 // copy text into a register and delete
1289 dot = yank_delete(save_dot, dot, 0, YANKDEL); // delete to e-o-l
1290 if (c == 'C')
1291 goto dc_i; // start inserting
1292#ifdef BB_FEATURE_VI_DOT_CMD
1293 if (c == 'D')
1294 end_cmd_q(); // stop adding to q
1295#endif /* BB_FEATURE_VI_DOT_CMD */
1296 break;
1297 case 'G': // G- goto to a line number (default= E-O-F)
1298 dot = end - 1; // assume E-O-F
1299 if (cmdcnt > 0) {
1300 dot = find_line(cmdcnt); // what line is #cmdcnt
1301 }
1302 dot_skip_over_ws();
1303 break;
1304 case 'H': // H- goto top line on screen
1305 dot = screenbegin;
1306 if (cmdcnt > (rows - 1)) {
1307 cmdcnt = (rows - 1);
1308 }
1309 if (cmdcnt-- > 1) {
1310 do_cmd('+');
1311 } // repeat cnt
1312 dot_skip_over_ws();
1313 break;
1314 case 'I': // I- insert before first non-blank
1315 dot_begin(); // 0
1316 dot_skip_over_ws();
1317 //**** fall thru to ... 'i'
1318 case 'i': // i- insert before current char
1319 case VI_K_INSERT: // Cursor Key Insert
1320 dc_i:
1321 cmd_mode = 1; // start insrting
1322 psb("-- Insert --");
1323 break;
1324 case 'J': // J- join current and next lines together
1325 if (cmdcnt-- > 2) {
1326 do_cmd(c);
1327 } // repeat cnt
1328 dot_end(); // move to NL
1329 if (dot < end - 1) { // make sure not last char in text[]
1330 *dot++ = ' '; // replace NL with space
1331 while (isblnk(*dot)) { // delete leading WS
1332 dot_delete();
1333 }
1334 }
1335 end_cmd_q(); // stop adding to q
1336 break;
1337 case 'L': // L- goto bottom line on screen
1338 dot = end_screen();
1339 if (cmdcnt > (rows - 1)) {
1340 cmdcnt = (rows - 1);
1341 }
1342 if (cmdcnt-- > 1) {
1343 do_cmd('-');
1344 } // repeat cnt
1345 dot_begin();
1346 dot_skip_over_ws();
1347 break;
1348 case 'M': // M- goto middle line on screen
1349 dot = screenbegin;
1350 for (cnt = 0; cnt < (rows-1) / 2; cnt++)
1351 dot = next_line(dot);
1352 break;
1353 case 'O': // O- open a empty line above
1354 // 0i\n ESC -i
1355 p = begin_line(dot);
1356 if (p[-1] == '\n') {
1357 dot_prev();
1358 case 'o': // o- open a empty line below; Yes, I know it is in the middle of the "if (..."
1359 dot_end();
1360 dot = char_insert(dot, '\n');
1361 } else {
1362 dot_begin(); // 0
1363 dot = char_insert(dot, '\n'); // i\n ESC
1364 dot_prev(); // -
1365 }
1366 goto dc_i;
1367 break;
1368 case 'R': // R- continuous Replace char
1369 dc5:
1370 cmd_mode = 2;
1371 psb("-- Replace --");
1372 break;
1373 case 'X': // X- delete char before dot
1374 case 'x': // x- delete the current char
1375 case 's': // s- substitute the current char
1376 if (cmdcnt-- > 1) {
1377 do_cmd(c);
1378 } // repeat cnt
1379 dir = 0;
1380 if (c == 'X')
1381 dir = -1;
1382 if (dot[dir] != '\n') {
1383 if (c == 'X')
1384 dot--; // delete prev char
1385 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char
1386 }
1387 if (c == 's')
1388 goto dc_i; // start insrting
1389 end_cmd_q(); // stop adding to q
1390 break;
1391 case 'Z': // Z- if modified, {write}; exit
1392 // ZZ means to save file (if necessary), then exit
1393 c1 = get_one_char();
1394 if (c1 != 'Z') {
1395 indicate_error(c);
1396 break;
1397 }
1398 if (file_modified == TRUE
1399#ifdef BB_FEATURE_VI_READONLY
1400 && vi_readonly == FALSE
1401 && readonly == FALSE
1402#endif /* BB_FEATURE_VI_READONLY */
1403 ) {
1404 cnt = file_write(cfn, text, end - 1);
1405 if (cnt == (end - 1 - text + 1)) {
1406 editing = 0;
1407 }
1408 } else {
1409 editing = 0;
1410 }
1411 break;
1412 case '^': // ^- move to first non-blank on line
1413 dot_begin();
1414 dot_skip_over_ws();
1415 break;
1416 case 'b': // b- back a word
1417 case 'e': // e- end of word
1418 if (cmdcnt-- > 1) {
1419 do_cmd(c);
1420 } // repeat cnt
1421 dir = FORWARD;
1422 if (c == 'b')
1423 dir = BACK;
1424 if ((dot + dir) < text || (dot + dir) > end - 1)
1425 break;
1426 dot += dir;
1427 if (isspace(*dot)) {
1428 dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
1429 }
1430 if (isalnum(*dot) || *dot == '_') {
1431 dot = skip_thing(dot, 1, dir, S_END_ALNUM);
1432 } else if (ispunct(*dot)) {
1433 dot = skip_thing(dot, 1, dir, S_END_PUNCT);
1434 }
1435 break;
1436 case 'c': // c- change something
1437 case 'd': // d- delete something
1438#ifdef BB_FEATURE_VI_YANKMARK
1439 case 'y': // y- yank something
1440 case 'Y': // Y- Yank a line
1441#endif /* BB_FEATURE_VI_YANKMARK */
1442 yf = YANKDEL; // assume either "c" or "d"
1443#ifdef BB_FEATURE_VI_YANKMARK
1444 if (c == 'y' || c == 'Y')
1445 yf = YANKONLY;
1446#endif /* BB_FEATURE_VI_YANKMARK */
1447 c1 = 'y';
1448 if (c != 'Y')
1449 c1 = get_one_char(); // get the type of thing to delete
1450 find_range(&p, &q, c1);
1451 if (c1 == 27) { // ESC- user changed mind and wants out
1452 c = c1 = 27; // Escape- do nothing
1453 } else if (strchr("wW", c1)) {
1454 if (c == 'c') {
1455 // don't include trailing WS as part of word
1456 while (isblnk(*q)) {
1457 if (q <= text || q[-1] == '\n')
1458 break;
1459 q--;
1460 }
1461 }
1462 dot = yank_delete(p, q, 0, yf); // delete word
1463 } else if (strchr("^0bBeEft$", c1)) {
1464 // single line copy text into a register and delete
1465 dot = yank_delete(p, q, 0, yf); // delete word
1466 } else if (strchr("cdykjHL%+-{}\r\n", c1)) {
1467 // multiple line copy text into a register and delete
1468 dot = yank_delete(p, q, 1, yf); // delete lines
1469 if (c == 'c') {
1470 dot = char_insert(dot, '\n');
1471 // on the last line of file don't move to prev line
1472 if (dot != (end-1)) {
1473 dot_prev();
1474 }
1475 } else if (c == 'd') {
1476 dot_begin();
1477 dot_skip_over_ws();
1478 }
1479 } else {
1480 // could not recognize object
1481 c = c1 = 27; // error-
1482 indicate_error(c);
1483 }
1484 if (c1 != 27) {
1485 // if CHANGING, not deleting, start inserting after the delete
1486 if (c == 'c') {
1487 strcpy((char *) buf, "Change");
1488 goto dc_i; // start inserting
1489 }
1490 if (c == 'd') {
1491 strcpy((char *) buf, "Delete");
1492 }
1493#ifdef BB_FEATURE_VI_YANKMARK
1494 if (c == 'y' || c == 'Y') {
1495 strcpy((char *) buf, "Yank");
1496 }
1497 p = reg[YDreg];
1498 q = p + strlen((char *) p);
1499 for (cnt = 0; p <= q; p++) {
1500 if (*p == '\n')
1501 cnt++;
1502 }
1503 psb("%s %d lines (%d chars) using [%c]",
1504 buf, cnt, strlen((char *) reg[YDreg]), what_reg());
1505#endif /* BB_FEATURE_VI_YANKMARK */
1506 end_cmd_q(); // stop adding to q
1507 }
1508 break;
1509 case 'k': // k- goto prev line, same col
1510 case VI_K_UP: // cursor key Up
1511 if (cmdcnt-- > 1) {
1512 do_cmd(c);
1513 } // repeat cnt
1514 dot_prev();
1515 dot = move_to_col(dot, ccol + offset); // try stay in same col
1516 break;
1517 case 'r': // r- replace the current char with user input
1518 c1 = get_one_char(); // get the replacement char
1519 if (*dot != '\n') {
1520 *dot = c1;
1521 file_modified = TRUE; // has the file been modified
1522 }
1523 end_cmd_q(); // stop adding to q
1524 break;
1525 case 't': // t- move to char prior to next x
1526 last_forward_char = get_one_char();
1527 do_cmd(';');
1528 if (*dot == last_forward_char)
1529 dot_left();
1530 last_forward_char= 0;
1531 break;
1532 case 'w': // w- forward a word
1533 if (cmdcnt-- > 1) {
1534 do_cmd(c);
1535 } // repeat cnt
1536 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM
1537 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
1538 } else if (ispunct(*dot)) { // we are on PUNCT
1539 dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
1540 }
1541 if (dot < end - 1)
1542 dot++; // move over word
1543 if (isspace(*dot)) {
1544 dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
1545 }
1546 break;
1547 case 'z': // z-
1548 c1 = get_one_char(); // get the replacement char
1549 cnt = 0;
1550 if (c1 == '.')
1551 cnt = (rows - 2) / 2; // put dot at center
1552 if (c1 == '-')
1553 cnt = rows - 2; // put dot at bottom
1554 screenbegin = begin_line(dot); // start dot at top
1555 dot_scroll(cnt, -1);
1556 break;
1557 case '|': // |- move to column "cmdcnt"
1558 dot = move_to_col(dot, cmdcnt - 1); // try to move to column
1559 break;
1560 case '~': // ~- flip the case of letters a-z -> A-Z
1561 if (cmdcnt-- > 1) {
1562 do_cmd(c);
1563 } // repeat cnt
1564 if (islower(*dot)) {
1565 *dot = toupper(*dot);
1566 file_modified = TRUE; // has the file been modified
1567 } else if (isupper(*dot)) {
1568 *dot = tolower(*dot);
1569 file_modified = TRUE; // has the file been modified
1570 }
1571 dot_right();
1572 end_cmd_q(); // stop adding to q
1573 break;
1574 //----- The Cursor and Function Keys -----------------------------
1575 case VI_K_HOME: // Cursor Key Home
1576 dot_begin();
1577 break;
1578 // The Fn keys could point to do_macro which could translate them
1579 case VI_K_FUN1: // Function Key F1
1580 case VI_K_FUN2: // Function Key F2
1581 case VI_K_FUN3: // Function Key F3
1582 case VI_K_FUN4: // Function Key F4
1583 case VI_K_FUN5: // Function Key F5
1584 case VI_K_FUN6: // Function Key F6
1585 case VI_K_FUN7: // Function Key F7
1586 case VI_K_FUN8: // Function Key F8
1587 case VI_K_FUN9: // Function Key F9
1588 case VI_K_FUN10: // Function Key F10
1589 case VI_K_FUN11: // Function Key F11
1590 case VI_K_FUN12: // Function Key F12
1591 break;
1592 }
1593
1594 dc1:
1595 // if text[] just became empty, add back an empty line
1596 if (end == text) {
1597 (void) char_insert(text, '\n'); // start empty buf with dummy line
1598 dot = text;
1599 }
1600 // it is OK for dot to exactly equal to end, otherwise check dot validity
1601 if (dot != end) {
1602 dot = bound_dot(dot); // make sure "dot" is valid
1603 }
1604#ifdef BB_FEATURE_VI_YANKMARK
1605 check_context(c); // update the current context
1606#endif /* BB_FEATURE_VI_YANKMARK */
1607
1608 if (!isdigit(c))
1609 cmdcnt = 0; // cmd was not a number, reset cmdcnt
1610 cnt = dot - begin_line(dot);
1611 // Try to stay off of the Newline
1612 if (*dot == '\n' && cnt > 0 && cmd_mode == 0)
1613 dot--;
1614}
1615
1616//----- The Colon commands -------------------------------------
1617#ifdef BB_FEATURE_VI_COLON
1618static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present
1619{
1620 int st;
1621 Byte *q;
1622
1623#ifdef BB_FEATURE_VI_YANKMARK
1624 Byte c;
1625#endif /* BB_FEATURE_VI_YANKMARK */
1626#ifdef BB_FEATURE_VI_SEARCH
1627 Byte *pat, buf[BUFSIZ];
1628#endif /* BB_FEATURE_VI_SEARCH */
1629
1630 *addr = -1; // assume no addr
1631 if (*p == '.') { // the current line
1632 p++;
1633 q = begin_line(dot);
1634 *addr = count_lines(text, q);
1635#ifdef BB_FEATURE_VI_YANKMARK
1636 } else if (*p == '\'') { // is this a mark addr
1637 p++;
1638 c = tolower(*p);
1639 p++;
1640 if (c >= 'a' && c <= 'z') {
1641 // we have a mark
1642 c = c - 'a';
1643 q = mark[(int) c];
1644 if (q != NULL) { // is mark valid
1645 *addr = count_lines(text, q); // count lines
1646 }
1647 }
1648#endif /* BB_FEATURE_VI_YANKMARK */
1649#ifdef BB_FEATURE_VI_SEARCH
1650 } else if (*p == '/') { // a search pattern
1651 q = buf;
1652 for (p++; *p; p++) {
1653 if (*p == '/')
1654 break;
1655 *q++ = *p;
1656 *q = '\0';
1657 }
1658 pat = (Byte *) strdup((char *) buf); // save copy of pattern
1659 if (*p == '/')
1660 p++;
1661 q = char_search(dot, pat, FORWARD, FULL);
1662 if (q != NULL) {
1663 *addr = count_lines(text, q);
1664 }
1665 free(pat);
1666#endif /* BB_FEATURE_VI_SEARCH */
1667 } else if (*p == '$') { // the last line in file
1668 p++;
1669 q = begin_line(end - 1);
1670 *addr = count_lines(text, q);
1671 } else if (isdigit(*p)) { // specific line number
1672 sscanf((char *) p, "%d%n", addr, &st);
1673 p += st;
1674 } else { // I don't reconise this
1675 // unrecognised address- assume -1
1676 *addr = -1;
1677 }
1678 return (p);
1679}
1680
1681static Byte *get_address(Byte *p, int *b, int *e) // get two colon addrs, if present
1682{
1683 //----- get the address' i.e., 1,3 'a,'b -----
1684 // get FIRST addr, if present
1685 while (isblnk(*p))
1686 p++; // skip over leading spaces
1687 if (*p == '%') { // alias for 1,$
1688 p++;
1689 *b = 1;
1690 *e = count_lines(text, end-1);
1691 goto ga0;
1692 }
1693 p = get_one_address(p, b);
1694 while (isblnk(*p))
1695 p++;
1696 if (*p == ',') { // is there a address seperator
1697 p++;
1698 while (isblnk(*p))
1699 p++;
1700 // get SECOND addr, if present
1701 p = get_one_address(p, e);
1702 }
1703ga0:
1704 while (isblnk(*p))
1705 p++; // skip over trailing spaces
1706 return (p);
1707}
1708
1709static void colon(Byte * buf)
1710{
1711 Byte c, *orig_buf, *buf1, *q, *r;
1712 Byte *fn, cmd[BUFSIZ], args[BUFSIZ];
1713 int i, l, li, ch, st, b, e;
1714 int useforce, forced;
1715 struct stat st_buf;
1716
1717 // :3154 // if (-e line 3154) goto it else stay put
1718 // :4,33w! foo // write a portion of buffer to file "foo"
1719 // :w // write all of buffer to current file
1720 // :q // quit
1721 // :q! // quit- dont care about modified file
1722 // :'a,'z!sort -u // filter block through sort
1723 // :'f // goto mark "f"
1724 // :'fl // list literal the mark "f" line
1725 // :.r bar // read file "bar" into buffer before dot
1726 // :/123/,/abc/d // delete lines from "123" line to "abc" line
1727 // :/xyz/ // goto the "xyz" line
1728 // :s/find/replace/ // substitute pattern "find" with "replace"
1729 // :!<cmd> // run <cmd> then return
1730 //
1731 if (strlen((char *) buf) <= 0)
1732 goto vc1;
1733 if (*buf == ':')
1734 buf++; // move past the ':'
1735
1736 forced = useforce = FALSE;
1737 li = st = ch = i = 0;
1738 b = e = -1;
1739 q = text; // assume 1,$ for the range
1740 r = end - 1;
1741 li = count_lines(text, end - 1);
1742 fn = cfn; // default to current file
1743 memset(cmd, '\0', BUFSIZ); // clear cmd[]
1744 memset(args, '\0', BUFSIZ); // clear args[]
1745
1746 // look for optional address(es) :. :1 :1,9 :'q,'a :%
1747 buf = get_address(buf, &b, &e);
1748
1749 // remember orig command line
1750 orig_buf = buf;
1751
1752 // get the COMMAND into cmd[]
1753 buf1 = cmd;
1754 while (*buf != '\0') {
1755 if (isspace(*buf))
1756 break;
1757 *buf1++ = *buf++;
1758 }
1759 // get any ARGuments
1760 while (isblnk(*buf))
1761 buf++;
1762 strcpy((char *) args, (char *) buf);
1763 buf1 = last_char_is((char *)cmd, '!');
1764 if (buf1) {
1765 useforce = TRUE;
1766 *buf1 = '\0'; // get rid of !
1767 }
1768 if (b >= 0) {
1769 // if there is only one addr, then the addr
1770 // is the line number of the single line the
1771 // user wants. So, reset the end
1772 // pointer to point at end of the "b" line
1773 q = find_line(b); // what line is #b
1774 r = end_line(q);
1775 li = 1;
1776 }
1777 if (e >= 0) {
1778 // we were given two addrs. change the
1779 // end pointer to the addr given by user.
1780 r = find_line(e); // what line is #e
1781 r = end_line(r);
1782 li = e - b + 1;
1783 }
1784 // ------------ now look for the command ------------
1785 i = strlen((char *) cmd);
1786 if (i == 0) { // :123CR goto line #123
1787 if (b >= 0) {
1788 dot = find_line(b); // what line is #b
1789 dot_skip_over_ws();
1790 }
1791 } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd
1792 // :!ls run the <cmd>
1793 (void) alarm(0); // wait for input- no alarms
1794 place_cursor(rows - 1, 0, FALSE); // go to Status line
1795 clear_to_eol(); // clear the line
1796 cookmode();
1797 system(orig_buf+1); // run the cmd
1798 rawmode();
1799 Hit_Return(); // let user see results
1800 (void) alarm(3); // done waiting for input
1801 } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address
1802 if (b < 0) { // no addr given- use defaults
1803 b = e = count_lines(text, dot);
1804 }
1805 psb("%d", b);
1806 } else if (strncasecmp((char *) cmd, "delete", i) == 0) { // delete lines
1807 if (b < 0) { // no addr given- use defaults
1808 q = begin_line(dot); // assume .,. for the range
1809 r = end_line(dot);
1810 }
1811 dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines
1812 dot_skip_over_ws();
1813 } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file
1814 int sr;
1815 sr= 0;
1816 // don't edit, if the current file has been modified
1817 if (file_modified == TRUE && useforce != TRUE) {
1818 psbs("No write since last change (:edit! overrides)");
1819 goto vc1;
1820 }
1821 if (strlen(args) > 0) {
1822 // the user supplied a file name
1823 fn= args;
1824 } else if (cfn != 0 && strlen(cfn) > 0) {
1825 // no user supplied name- use the current filename
1826 fn= cfn;
1827 goto vc5;
1828 } else {
1829 // no user file name, no current name- punt
1830 psbs("No current filename");
1831 goto vc1;
1832 }
1833
1834 // see if file exists- if not, its just a new file request
1835 if ((sr=stat((char*)fn, &st_buf)) < 0) {
1836 // This is just a request for a new file creation.
1837 // The file_insert below will fail but we get
1838 // an empty buffer with a file name. Then the "write"
1839 // command can do the create.
1840 } else {
1841 if ((st_buf.st_mode & (S_IFREG)) == 0) {
1842 // This is not a regular file
1843 psbs("\"%s\" is not a regular file", fn);
1844 goto vc1;
1845 }
1846 if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
1847 // dont have any read permissions
1848 psbs("\"%s\" is not readable", fn);
1849 goto vc1;
1850 }
1851 }
1852
1853 // There is a read-able regular file
1854 // make this the current file
1855 q = (Byte *) strdup((char *) fn); // save the cfn
1856 if (cfn != 0)
1857 free(cfn); // free the old name
1858 cfn = q; // remember new cfn
1859
1860 vc5:
1861 // delete all the contents of text[]
1862 new_text(2 * file_size(fn));
1863 screenbegin = dot = end = text;
1864
1865 // insert new file
1866 ch = file_insert(fn, text, file_size(fn));
1867
1868 if (ch < 1) {
1869 // start empty buf with dummy line
1870 (void) char_insert(text, '\n');
1871 ch= 1;
1872 }
1873 file_modified = FALSE;
1874#ifdef BB_FEATURE_VI_YANKMARK
1875 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
1876 free(reg[Ureg]); // free orig line reg- for 'U'
1877 reg[Ureg]= 0;
1878 }
1879 if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {
1880 free(reg[YDreg]); // free default yank/delete register
1881 reg[YDreg]= 0;
1882 }
1883 for (li = 0; li < 28; li++) {
1884 mark[li] = 0;
1885 } // init the marks
1886#endif /* BB_FEATURE_VI_YANKMARK */
1887 // how many lines in text[]?
1888 li = count_lines(text, end - 1);
1889 psb("\"%s\"%s"
1890#ifdef BB_FEATURE_VI_READONLY
1891 "%s"
1892#endif /* BB_FEATURE_VI_READONLY */
1893 " %dL, %dC", cfn,
1894 (sr < 0 ? " [New file]" : ""),
1895#ifdef BB_FEATURE_VI_READONLY
1896 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
1897#endif /* BB_FEATURE_VI_READONLY */
1898 li, ch);
1899 } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
1900 if (b != -1 || e != -1) {
1901 ni((Byte *) "No address allowed on this command");
1902 goto vc1;
1903 }
1904 if (strlen((char *) args) > 0) {
1905 // user wants a new filename
1906 if (cfn != NULL)
1907 free(cfn);
1908 cfn = (Byte *) strdup((char *) args);
1909 } else {
1910 // user wants file status info
1911 edit_status();
1912 }
1913 } else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available
1914 // print out values of all features
1915 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
1916 clear_to_eol(); // clear the line
1917 cookmode();
1918 show_help();
1919 rawmode();
1920 Hit_Return();
1921 } else if (strncasecmp((char *) cmd, "list", i) == 0) { // literal print line
1922 if (b < 0) { // no addr given- use defaults
1923 q = begin_line(dot); // assume .,. for the range
1924 r = end_line(dot);
1925 }
1926 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
1927 clear_to_eol(); // clear the line
1928 write(1, "\r\n", 2);
1929 for (; q <= r; q++) {
1930 c = *q;
1931 if (c > '~')
1932 standout_start();
1933 if (c == '\n') {
1934 write(1, "$\r", 2);
1935 } else if (*q < ' ') {
1936 write(1, "^", 1);
1937 c += '@';
1938 }
1939 write(1, &c, 1);
1940 if (c > '~')
1941 standout_end();
1942 }
1943#ifdef BB_FEATURE_VI_SET
1944 vc2:
1945#endif /* BB_FEATURE_VI_SET */
1946 Hit_Return();
1947 } else if ((strncasecmp((char *) cmd, "quit", i) == 0) || // Quit
1948 (strncasecmp((char *) cmd, "next", i) == 0)) { // edit next file
1949 if (useforce == TRUE) {
1950 // force end of argv list
1951 if (*cmd == 'q') {
1952 optind = save_argc;
1953 }
1954 editing = 0;
1955 goto vc1;
1956 }
1957 // don't exit if the file been modified
1958 if (file_modified == TRUE) {
1959 psbs("No write since last change (:%s! overrides)",
1960 (*cmd == 'q' ? "quit" : "next"));
1961 goto vc1;
1962 }
1963 // are there other file to edit
1964 if (*cmd == 'q' && optind < save_argc - 1) {
1965 psbs("%d more file to edit", (save_argc - optind - 1));
1966 goto vc1;
1967 }
1968 if (*cmd == 'n' && optind >= save_argc - 1) {
1969 psbs("No more files to edit");
1970 goto vc1;
1971 }
1972 editing = 0;
1973 } else if (strncasecmp((char *) cmd, "read", i) == 0) { // read file into text[]
1974 fn = args;
1975 if (strlen((char *) fn) <= 0) {
1976 psbs("No filename given");
1977 goto vc1;
1978 }
1979 if (b < 0) { // no addr given- use defaults
1980 q = begin_line(dot); // assume "dot"
1981 }
1982 // read after current line- unless user said ":0r foo"
1983 if (b != 0)
1984 q = next_line(q);
1985#ifdef BB_FEATURE_VI_READONLY
1986 l= readonly; // remember current files' status
1987#endif
1988 ch = file_insert(fn, q, file_size(fn));
1989#ifdef BB_FEATURE_VI_READONLY
1990 readonly= l;
1991#endif
1992 if (ch < 0)
1993 goto vc1; // nothing was inserted
1994 // how many lines in text[]?
1995 li = count_lines(q, q + ch - 1);
1996 psb("\"%s\""
1997#ifdef BB_FEATURE_VI_READONLY
1998 "%s"
1999#endif /* BB_FEATURE_VI_READONLY */
2000 " %dL, %dC", fn,
2001#ifdef BB_FEATURE_VI_READONLY
2002 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
2003#endif /* BB_FEATURE_VI_READONLY */
2004 li, ch);
2005 if (ch > 0) {
2006 // if the insert is before "dot" then we need to update
2007 if (q <= dot)
2008 dot += ch;
2009 file_modified = TRUE;
2010 }
2011 } else if (strncasecmp((char *) cmd, "rewind", i) == 0) { // rewind cmd line args
2012 if (file_modified == TRUE && useforce != TRUE) {
2013 psbs("No write since last change (:rewind! overrides)");
2014 } else {
2015 // reset the filenames to edit
2016 optind = fn_start - 1;
2017 editing = 0;
2018 }
2019#ifdef BB_FEATURE_VI_SET
2020 } else if (strncasecmp((char *) cmd, "set", i) == 0) { // set or clear features
2021 i = 0; // offset into args
2022 if (strlen((char *) args) == 0) {
2023 // print out values of all options
2024 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
2025 clear_to_eol(); // clear the line
2026 printf("----------------------------------------\r\n");
2027#ifdef BB_FEATURE_VI_SETOPTS
2028 if (!autoindent)
2029 printf("no");
2030 printf("autoindent ");
2031 if (!err_method)
2032 printf("no");
2033 printf("flash ");
2034 if (!ignorecase)
2035 printf("no");
2036 printf("ignorecase ");
2037 if (!showmatch)
2038 printf("no");
2039 printf("showmatch ");
2040 printf("tabstop=%d ", tabstop);
2041#endif /* BB_FEATURE_VI_SETOPTS */
2042 printf("\r\n");
2043 goto vc2;
2044 }
2045 if (strncasecmp((char *) args, "no", 2) == 0)
2046 i = 2; // ":set noautoindent"
2047#ifdef BB_FEATURE_VI_SETOPTS
2048 if (strncasecmp((char *) args + i, "autoindent", 10) == 0 ||
2049 strncasecmp((char *) args + i, "ai", 2) == 0) {
2050 autoindent = (i == 2) ? 0 : 1;
2051 }
2052 if (strncasecmp((char *) args + i, "flash", 5) == 0 ||
2053 strncasecmp((char *) args + i, "fl", 2) == 0) {
2054 err_method = (i == 2) ? 0 : 1;
2055 }
2056 if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 ||
2057 strncasecmp((char *) args + i, "ic", 2) == 0) {
2058 ignorecase = (i == 2) ? 0 : 1;
2059 }
2060 if (strncasecmp((char *) args + i, "showmatch", 9) == 0 ||
2061 strncasecmp((char *) args + i, "sm", 2) == 0) {
2062 showmatch = (i == 2) ? 0 : 1;
2063 }
2064 if (strncasecmp((char *) args + i, "tabstop", 7) == 0) {
2065 sscanf(strchr((char *) args + i, '='), "=%d", &ch);
2066 if (ch > 0 && ch < columns - 1)
2067 tabstop = ch;
2068 }
2069#endif /* BB_FEATURE_VI_SETOPTS */
2070#endif /* BB_FEATURE_VI_SET */
2071#ifdef BB_FEATURE_VI_SEARCH
2072 } else if (strncasecmp((char *) cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern
2073 Byte *ls, *F, *R;
2074 int gflag;
2075
2076 // F points to the "find" pattern
2077 // R points to the "replace" pattern
2078 // replace the cmd line delimiters "/" with NULLs
2079 gflag = 0; // global replace flag
2080 c = orig_buf[1]; // what is the delimiter
2081 F = orig_buf + 2; // start of "find"
2082 R = (Byte *) strchr((char *) F, c); // middle delimiter
2083 if (!R) goto colon_s_fail;
2084 *R++ = '\0'; // terminate "find"
2085 buf1 = (Byte *) strchr((char *) R, c);
2086 if (!buf1) goto colon_s_fail;
2087 *buf1++ = '\0'; // terminate "replace"
2088 if (*buf1 == 'g') { // :s/foo/bar/g
2089 buf1++;
2090 gflag++; // turn on gflag
2091 }
2092 q = begin_line(q);
2093 if (b < 0) { // maybe :s/foo/bar/
2094 q = begin_line(dot); // start with cur line
2095 b = count_lines(text, q); // cur line number
2096 }
2097 if (e < 0)
2098 e = b; // maybe :.s/foo/bar/
2099 for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0
2100 ls = q; // orig line start
2101 vc4:
2102 buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"
2103 if (buf1 != NULL) {
2104 // we found the "find" pattern- delete it
2105 (void) text_hole_delete(buf1, buf1 + strlen((char *) F) - 1);
2106 // inset the "replace" patern
2107 (void) string_insert(buf1, R); // insert the string
2108 // check for "global" :s/foo/bar/g
2109 if (gflag == 1) {
2110 if ((buf1 + strlen((char *) R)) < end_line(ls)) {
2111 q = buf1 + strlen((char *) R);
2112 goto vc4; // don't let q move past cur line
2113 }
2114 }
2115 }
2116 q = next_line(ls);
2117 }
2118#endif /* BB_FEATURE_VI_SEARCH */
2119 } else if (strncasecmp((char *) cmd, "version", i) == 0) { // show software version
2120 psb("%s", vi_Version);
2121 } else if ((strncasecmp((char *) cmd, "write", i) == 0) || // write text to file
2122 (strncasecmp((char *) cmd, "wq", i) == 0)) { // write text to file
2123 // is there a file name to write to?
2124 if (strlen((char *) args) > 0) {
2125 fn = args;
2126 }
2127#ifdef BB_FEATURE_VI_READONLY
2128 if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) {
2129 psbs("\"%s\" File is read only", fn);
2130 goto vc3;
2131 }
2132#endif /* BB_FEATURE_VI_READONLY */
2133 // how many lines in text[]?
2134 li = count_lines(q, r);
2135 ch = r - q + 1;
2136 // see if file exists- if not, its just a new file request
2137 if (useforce == TRUE) {
2138 // if "fn" is not write-able, chmod u+w
2139 // sprintf(syscmd, "chmod u+w %s", fn);
2140 // system(syscmd);
2141 forced = TRUE;
2142 }
2143 l = file_write(fn, q, r);
2144 if (useforce == TRUE && forced == TRUE) {
2145 // chmod u-w
2146 // sprintf(syscmd, "chmod u-w %s", fn);
2147 // system(syscmd);
2148 forced = FALSE;
2149 }
2150 psb("\"%s\" %dL, %dC", fn, li, l);
2151 if (q == text && r == end - 1 && l == ch)
2152 file_modified = FALSE;
2153 if (cmd[1] == 'q' && l == ch) {
2154 editing = 0;
2155 }
2156#ifdef BB_FEATURE_VI_READONLY
2157 vc3:;
2158#endif /* BB_FEATURE_VI_READONLY */
2159#ifdef BB_FEATURE_VI_YANKMARK
2160 } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines
2161 if (b < 0) { // no addr given- use defaults
2162 q = begin_line(dot); // assume .,. for the range
2163 r = end_line(dot);
2164 }
2165 text_yank(q, r, YDreg);
2166 li = count_lines(q, r);
2167 psb("Yank %d lines (%d chars) into [%c]",
2168 li, strlen((char *) reg[YDreg]), what_reg());
2169#endif /* BB_FEATURE_VI_YANKMARK */
2170 } else {
2171 // cmd unknown
2172 ni((Byte *) cmd);
2173 }
2174 vc1:
2175 dot = bound_dot(dot); // make sure "dot" is valid
2176 return;
2177#ifdef BB_FEATURE_VI_SEARCH
2178colon_s_fail:
2179 psb(":s expression missing delimiters");
2180 return;
2181#endif
2182
2183}
2184
2185static void Hit_Return(void)
2186{
2187 char c;
2188
2189 standout_start(); // start reverse video
2190 write(1, "[Hit return to continue]", 24);
2191 standout_end(); // end reverse video
2192 while ((c = get_one_char()) != '\n' && c != '\r') /*do nothing */
2193 ;
2194 redraw(TRUE); // force redraw all
2195}
2196#endif /* BB_FEATURE_VI_COLON */
2197
2198//----- Synchronize the cursor to Dot --------------------------
2199static void sync_cursor(Byte * d, int *row, int *col)
2200{
2201 Byte *beg_cur, *end_cur; // begin and end of "d" line
2202 Byte *beg_scr, *end_scr; // begin and end of screen
2203 Byte *tp;
2204 int cnt, ro, co;
2205
2206 beg_cur = begin_line(d); // first char of cur line
2207 end_cur = end_line(d); // last char of cur line
2208
2209 beg_scr = end_scr = screenbegin; // first char of screen
2210 end_scr = end_screen(); // last char of screen
2211
2212 if (beg_cur < screenbegin) {
2213 // "d" is before top line on screen
2214 // how many lines do we have to move
2215 cnt = count_lines(beg_cur, screenbegin);
2216 sc1:
2217 screenbegin = beg_cur;
2218 if (cnt > (rows - 1) / 2) {
2219 // we moved too many lines. put "dot" in middle of screen
2220 for (cnt = 0; cnt < (rows - 1) / 2; cnt++) {
2221 screenbegin = prev_line(screenbegin);
2222 }
2223 }
2224 } else if (beg_cur > end_scr) {
2225 // "d" is after bottom line on screen
2226 // how many lines do we have to move
2227 cnt = count_lines(end_scr, beg_cur);
2228 if (cnt > (rows - 1) / 2)
2229 goto sc1; // too many lines
2230 for (ro = 0; ro < cnt - 1; ro++) {
2231 // move screen begin the same amount
2232 screenbegin = next_line(screenbegin);
2233 // now, move the end of screen
2234 end_scr = next_line(end_scr);
2235 end_scr = end_line(end_scr);
2236 }
2237 }
2238 // "d" is on screen- find out which row
2239 tp = screenbegin;
2240 for (ro = 0; ro < rows - 1; ro++) { // drive "ro" to correct row
2241 if (tp == beg_cur)
2242 break;
2243 tp = next_line(tp);
2244 }
2245
2246 // find out what col "d" is on
2247 co = 0;
2248 do { // drive "co" to correct column
2249 if (*tp == '\n' || *tp == '\0')
2250 break;
2251 if (*tp == '\t') {
2252 // 7 - (co % 8 )
2253 co += ((tabstop - 1) - (co % tabstop));
2254 } else if (*tp < ' ') {
2255 co++; // display as ^X, use 2 columns
2256 }
2257 } while (tp++ < d && ++co);
2258
2259 // "co" is the column where "dot" is.
2260 // The screen has "columns" columns.
2261 // The currently displayed columns are 0+offset -- columns+ofset
2262 // |-------------------------------------------------------------|
2263 // ^ ^ ^
2264 // offset | |------- columns ----------------|
2265 //
2266 // If "co" is already in this range then we do not have to adjust offset
2267 // but, we do have to subtract the "offset" bias from "co".
2268 // If "co" is outside this range then we have to change "offset".
2269 // If the first char of a line is a tab the cursor will try to stay
2270 // in column 7, but we have to set offset to 0.
2271
2272 if (co < 0 + offset) {
2273 offset = co;
2274 }
2275 if (co >= columns + offset) {
2276 offset = co - columns + 1;
2277 }
2278 // if the first char of the line is a tab, and "dot" is sitting on it
2279 // force offset to 0.
2280 if (d == beg_cur && *d == '\t') {
2281 offset = 0;
2282 }
2283 co -= offset;
2284
2285 *row = ro;
2286 *col = co;
2287}
2288
2289//----- Text Movement Routines ---------------------------------
2290static Byte *begin_line(Byte * p) // return pointer to first char cur line
2291{
2292 while (p > text && p[-1] != '\n')
2293 p--; // go to cur line B-o-l
2294 return (p);
2295}
2296
2297static Byte *end_line(Byte * p) // return pointer to NL of cur line line
2298{
2299 while (p < end - 1 && *p != '\n')
2300 p++; // go to cur line E-o-l
2301 return (p);
2302}
2303
2304static Byte *dollar_line(Byte * p) // return pointer to just before NL line
2305{
2306 while (p < end - 1 && *p != '\n')
2307 p++; // go to cur line E-o-l
2308 // Try to stay off of the Newline
2309 if (*p == '\n' && (p - begin_line(p)) > 0)
2310 p--;
2311 return (p);
2312}
2313
2314static Byte *prev_line(Byte * p) // return pointer first char prev line
2315{
2316 p = begin_line(p); // goto begining of cur line
2317 if (p[-1] == '\n' && p > text)
2318 p--; // step to prev line
2319 p = begin_line(p); // goto begining of prev line
2320 return (p);
2321}
2322
2323static Byte *next_line(Byte * p) // return pointer first char next line
2324{
2325 p = end_line(p);
2326 if (*p == '\n' && p < end - 1)
2327 p++; // step to next line
2328 return (p);
2329}
2330
2331//----- Text Information Routines ------------------------------
2332static Byte *end_screen(void)
2333{
2334 Byte *q;
2335 int cnt;
2336
2337 // find new bottom line
2338 q = screenbegin;
2339 for (cnt = 0; cnt < rows - 2; cnt++)
2340 q = next_line(q);
2341 q = end_line(q);
2342 return (q);
2343}
2344
2345static int count_lines(Byte * start, Byte * stop) // count line from start to stop
2346{
2347 Byte *q;
2348 int cnt;
2349
2350 if (stop < start) { // start and stop are backwards- reverse them
2351 q = start;
2352 start = stop;
2353 stop = q;
2354 }
2355 cnt = 0;
2356 stop = end_line(stop); // get to end of this line
2357 for (q = start; q <= stop && q <= end - 1; q++) {
2358 if (*q == '\n')
2359 cnt++;
2360 }
2361 return (cnt);
2362}
2363
2364static Byte *find_line(int li) // find begining of line #li
2365{
2366 Byte *q;
2367
2368 for (q = text; li > 1; li--) {
2369 q = next_line(q);
2370 }
2371 return (q);
2372}
2373
2374//----- Dot Movement Routines ----------------------------------
2375static void dot_left(void)
2376{
2377 if (dot > text && dot[-1] != '\n')
2378 dot--;
2379}
2380
2381static void dot_right(void)
2382{
2383 if (dot < end - 1 && *dot != '\n')
2384 dot++;
2385}
2386
2387static void dot_begin(void)
2388{
2389 dot = begin_line(dot); // return pointer to first char cur line
2390}
2391
2392static void dot_end(void)
2393{
2394 dot = end_line(dot); // return pointer to last char cur line
2395}
2396
2397static Byte *move_to_col(Byte * p, int l)
2398{
2399 int co;
2400
2401 p = begin_line(p);
2402 co = 0;
2403 do {
2404 if (*p == '\n' || *p == '\0')
2405 break;
2406 if (*p == '\t') {
2407 // 7 - (co % 8 )
2408 co += ((tabstop - 1) - (co % tabstop));
2409 } else if (*p < ' ') {
2410 co++; // display as ^X, use 2 columns
2411 }
2412 } while (++co <= l && p++ < end);
2413 return (p);
2414}
2415
2416static void dot_next(void)
2417{
2418 dot = next_line(dot);
2419}
2420
2421static void dot_prev(void)
2422{
2423 dot = prev_line(dot);
2424}
2425
2426static void dot_scroll(int cnt, int dir)
2427{
2428 Byte *q;
2429
2430 for (; cnt > 0; cnt--) {
2431 if (dir < 0) {
2432 // scroll Backwards
2433 // ctrl-Y scroll up one line
2434 screenbegin = prev_line(screenbegin);
2435 } else {
2436 // scroll Forwards
2437 // ctrl-E scroll down one line
2438 screenbegin = next_line(screenbegin);
2439 }
2440 }
2441 // make sure "dot" stays on the screen so we dont scroll off
2442 if (dot < screenbegin)
2443 dot = screenbegin;
2444 q = end_screen(); // find new bottom line
2445 if (dot > q)
2446 dot = begin_line(q); // is dot is below bottom line?
2447 dot_skip_over_ws();
2448}
2449
2450static void dot_skip_over_ws(void)
2451{
2452 // skip WS
2453 while (isspace(*dot) && *dot != '\n' && dot < end - 1)
2454 dot++;
2455}
2456
2457static void dot_delete(void) // delete the char at 'dot'
2458{
2459 (void) text_hole_delete(dot, dot);
2460}
2461
2462static Byte *bound_dot(Byte * p) // make sure text[0] <= P < "end"
2463{
2464 if (p >= end && end > text) {
2465 p = end - 1;
2466 indicate_error('1');
2467 }
2468 if (p < text) {
2469 p = text;
2470 indicate_error('2');
2471 }
2472 return (p);
2473}
2474
2475//----- Helper Utility Routines --------------------------------
2476
2477//----------------------------------------------------------------
2478//----- Char Routines --------------------------------------------
2479/* Chars that are part of a word-
2480 * 0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
2481 * Chars that are Not part of a word (stoppers)
2482 * !"#$%&'()*+,-./:;<=>?@[\]^`{|}~
2483 * Chars that are WhiteSpace
2484 * TAB NEWLINE VT FF RETURN SPACE
2485 * DO NOT COUNT NEWLINE AS WHITESPACE
2486 */
2487
2488static Byte *new_screen(int ro, int co)
2489{
2490 int li;
2491
2492 if (screen != 0)
2493 free(screen);
2494 screensize = ro * co + 8;
2495 screen = (Byte *) malloc(screensize);
2496 // initialize the new screen. assume this will be a empty file.
2497 screen_erase();
2498 // non-existant text[] lines start with a tilde (~).
2499 for (li = 1; li < ro - 1; li++) {
2500 screen[(li * co) + 0] = '~';
2501 }
2502 return (screen);
2503}
2504
2505static Byte *new_text(int size)
2506{
2507 if (size < 10240)
2508 size = 10240; // have a minimum size for new files
2509 if (text != 0) {
2510 //text -= 4;
2511 free(text);
2512 }
2513 text = (Byte *) malloc(size + 8);
2514 memset(text, '\0', size); // clear new text[]
2515 //text += 4; // leave some room for "oops"
2516 textend = text + size - 1;
2517 //textend -= 4; // leave some root for "oops"
2518 return (text);
2519}
2520
2521#ifdef BB_FEATURE_VI_SEARCH
2522static int mycmp(Byte * s1, Byte * s2, int len)
2523{
2524 int i;
2525
2526 i = strncmp((char *) s1, (char *) s2, len);
2527#ifdef BB_FEATURE_VI_SETOPTS
2528 if (ignorecase) {
2529 i = strncasecmp((char *) s1, (char *) s2, len);
2530 }
2531#endif /* BB_FEATURE_VI_SETOPTS */
2532 return (i);
2533}
2534
2535static Byte *char_search(Byte * p, Byte * pat, int dir, int range) // search for pattern starting at p
2536{
2537#ifndef REGEX_SEARCH
2538 Byte *start, *stop;
2539 int len;
2540
2541 len = strlen((char *) pat);
2542 if (dir == FORWARD) {
2543 stop = end - 1; // assume range is p - end-1
2544 if (range == LIMITED)
2545 stop = next_line(p); // range is to next line
2546 for (start = p; start < stop; start++) {
2547 if (mycmp(start, pat, len) == 0) {
2548 return (start);
2549 }
2550 }
2551 } else if (dir == BACK) {
2552 stop = text; // assume range is text - p
2553 if (range == LIMITED)
2554 stop = prev_line(p); // range is to prev line
2555 for (start = p - len; start >= stop; start--) {
2556 if (mycmp(start, pat, len) == 0) {
2557 return (start);
2558 }
2559 }
2560 }
2561 // pattern not found
2562 return (NULL);
2563#else /*REGEX_SEARCH */
2564 char *q;
2565 struct re_pattern_buffer preg;
2566 int i;
2567 int size, range;
2568
2569 re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
2570 preg.translate = 0;
2571 preg.fastmap = 0;
2572 preg.buffer = 0;
2573 preg.allocated = 0;
2574
2575 // assume a LIMITED forward search
2576 q = next_line(p);
2577 q = end_line(q);
2578 q = end - 1;
2579 if (dir == BACK) {
2580 q = prev_line(p);
2581 q = text;
2582 }
2583 // count the number of chars to search over, forward or backward
2584 size = q - p;
2585 if (size < 0)
2586 size = p - q;
2587 // RANGE could be negative if we are searching backwards
2588 range = q - p;
2589
2590 q = (char *) re_compile_pattern(pat, strlen((char *) pat), &preg);
2591 if (q != 0) {
2592 // The pattern was not compiled
2593 psbs("bad search pattern: \"%s\": %s", pat, q);
2594 i = 0; // return p if pattern not compiled
2595 goto cs1;
2596 }
2597
2598 q = p;
2599 if (range < 0) {
2600 q = p - size;
2601 if (q < text)
2602 q = text;
2603 }
2604 // search for the compiled pattern, preg, in p[]
2605 // range < 0- search backward
2606 // range > 0- search forward
2607 // 0 < start < size
2608 // re_search() < 0 not found or error
2609 // re_search() > 0 index of found pattern
2610 // struct pattern char int int int struct reg
2611 // re_search (*pattern_buffer, *string, size, start, range, *regs)
2612 i = re_search(&preg, q, size, 0, range, 0);
2613 if (i == -1) {
2614 p = 0;
2615 i = 0; // return NULL if pattern not found
2616 }
2617 cs1:
2618 if (dir == FORWARD) {
2619 p = p + i;
2620 } else {
2621 p = p - i;
2622 }
2623 return (p);
2624#endif /*REGEX_SEARCH */
2625}
2626#endif /* BB_FEATURE_VI_SEARCH */
2627
2628static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
2629{
2630 if (c == 22) { // Is this an ctrl-V?
2631 p = stupid_insert(p, '^'); // use ^ to indicate literal next
2632 p--; // backup onto ^
2633 refresh(FALSE); // show the ^
2634 c = get_one_char();
2635 *p = c;
2636 p++;
2637 file_modified = TRUE; // has the file been modified
2638 } else if (c == 27) { // Is this an ESC?
2639 cmd_mode = 0;
2640 cmdcnt = 0;
2641 end_cmd_q(); // stop adding to q
2642 strcpy((char *) status_buffer, " "); // clear the status buffer
2643 if ((p[-1] != '\n') && (dot>text)) {
2644 p--;
2645 }
2646 } else if (c == erase_char) { // Is this a BS
2647 // 123456789
2648 if ((p[-1] != '\n') && (dot>text)) {
2649 p--;
2650 p = text_hole_delete(p, p); // shrink buffer 1 char
2651#ifdef BB_FEATURE_VI_DOT_CMD
2652 // also rmove char from last_modifying_cmd
2653 if (strlen((char *) last_modifying_cmd) > 0) {
2654 Byte *q;
2655
2656 q = last_modifying_cmd;
2657 q[strlen((char *) q) - 1] = '\0'; // erase BS
2658 q[strlen((char *) q) - 1] = '\0'; // erase prev char
2659 }
2660#endif /* BB_FEATURE_VI_DOT_CMD */
2661 }
2662 } else {
2663 // insert a char into text[]
2664 Byte *sp; // "save p"
2665
2666 if (c == 13)
2667 c = '\n'; // translate \r to \n
2668 sp = p; // remember addr of insert
2669 p = stupid_insert(p, c); // insert the char
2670#ifdef BB_FEATURE_VI_SETOPTS
2671 if (showmatch && strchr(")]}", *sp) != NULL) {
2672 showmatching(sp);
2673 }
2674 if (autoindent && c == '\n') { // auto indent the new line
2675 Byte *q;
2676
2677 q = prev_line(p); // use prev line as templet
2678 for (; isblnk(*q); q++) {
2679 p = stupid_insert(p, *q); // insert the char
2680 }
2681 }
2682#endif /* BB_FEATURE_VI_SETOPTS */
2683 }
2684 return (p);
2685}
2686
2687static Byte *stupid_insert(Byte * p, Byte c) // stupidly insert the char c at 'p'
2688{
2689 p = text_hole_make(p, 1);
2690 if (p != 0) {
2691 *p = c;
2692 file_modified = TRUE; // has the file been modified
2693 p++;
2694 }
2695 return (p);
2696}
2697
2698static Byte find_range(Byte ** start, Byte ** stop, Byte c)
2699{
2700 Byte *save_dot, *p, *q;
2701 int cnt;
2702
2703 save_dot = dot;
2704 p = q = dot;
2705
2706 if (strchr("cdy><", c)) {
2707 // these cmds operate on whole lines
2708 p = q = begin_line(p);
2709 for (cnt = 1; cnt < cmdcnt; cnt++) {
2710 q = next_line(q);
2711 }
2712 q = end_line(q);
2713 } else if (strchr("^%$0bBeEft", c)) {
2714 // These cmds operate on char positions
2715 do_cmd(c); // execute movement cmd
2716 q = dot;
2717 } else if (strchr("wW", c)) {
2718 do_cmd(c); // execute movement cmd
2719 if (dot > text)
2720 dot--; // move back off of next word
2721 if (dot > text && *dot == '\n')
2722 dot--; // stay off NL
2723 q = dot;
2724 } else if (strchr("H-k{", c)) {
2725 // these operate on multi-lines backwards
2726 q = end_line(dot); // find NL
2727 do_cmd(c); // execute movement cmd
2728 dot_begin();
2729 p = dot;
2730 } else if (strchr("L+j}\r\n", c)) {
2731 // these operate on multi-lines forwards
2732 p = begin_line(dot);
2733 do_cmd(c); // execute movement cmd
2734 dot_end(); // find NL
2735 q = dot;
2736 } else {
2737 c = 27; // error- return an ESC char
2738 //break;
2739 }
2740 *start = p;
2741 *stop = q;
2742 if (q < p) {
2743 *start = q;
2744 *stop = p;
2745 }
2746 dot = save_dot;
2747 return (c);
2748}
2749
2750static int st_test(Byte * p, int type, int dir, Byte * tested)
2751{
2752 Byte c, c0, ci;
2753 int test, inc;
2754
2755 inc = dir;
2756 c = c0 = p[0];
2757 ci = p[inc];
2758 test = 0;
2759
2760 if (type == S_BEFORE_WS) {
2761 c = ci;
2762 test = ((!isspace(c)) || c == '\n');
2763 }
2764 if (type == S_TO_WS) {
2765 c = c0;
2766 test = ((!isspace(c)) || c == '\n');
2767 }
2768 if (type == S_OVER_WS) {
2769 c = c0;
2770 test = ((isspace(c)));
2771 }
2772 if (type == S_END_PUNCT) {
2773 c = ci;
2774 test = ((ispunct(c)));
2775 }
2776 if (type == S_END_ALNUM) {
2777 c = ci;
2778 test = ((isalnum(c)) || c == '_');
2779 }
2780 *tested = c;
2781 return (test);
2782}
2783
2784static Byte *skip_thing(Byte * p, int linecnt, int dir, int type)
2785{
2786 Byte c;
2787
2788 while (st_test(p, type, dir, &c)) {
2789 // make sure we limit search to correct number of lines
2790 if (c == '\n' && --linecnt < 1)
2791 break;
2792 if (dir >= 0 && p >= end - 1)
2793 break;
2794 if (dir < 0 && p <= text)
2795 break;
2796 p += dir; // move to next char
2797 }
2798 return (p);
2799}
2800
2801// find matching char of pair () [] {}
2802static Byte *find_pair(Byte * p, Byte c)
2803{
2804 Byte match, *q;
2805 int dir, level;
2806
2807 match = ')';
2808 level = 1;
2809 dir = 1; // assume forward
2810 switch (c) {
2811 case '(':
2812 match = ')';
2813 break;
2814 case '[':
2815 match = ']';
2816 break;
2817 case '{':
2818 match = '}';
2819 break;
2820 case ')':
2821 match = '(';
2822 dir = -1;
2823 break;
2824 case ']':
2825 match = '[';
2826 dir = -1;
2827 break;
2828 case '}':
2829 match = '{';
2830 dir = -1;
2831 break;
2832 }
2833 for (q = p + dir; text <= q && q < end; q += dir) {
2834 // look for match, count levels of pairs (( ))
2835 if (*q == c)
2836 level++; // increase pair levels
2837 if (*q == match)
2838 level--; // reduce pair level
2839 if (level == 0)
2840 break; // found matching pair
2841 }
2842 if (level != 0)
2843 q = NULL; // indicate no match
2844 return (q);
2845}
2846
2847#ifdef BB_FEATURE_VI_SETOPTS
2848// show the matching char of a pair, () [] {}
2849static void showmatching(Byte * p)
2850{
2851 Byte *q, *save_dot;
2852
2853 // we found half of a pair
2854 q = find_pair(p, *p); // get loc of matching char
2855 if (q == NULL) {
2856 indicate_error('3'); // no matching char
2857 } else {
2858 // "q" now points to matching pair
2859 save_dot = dot; // remember where we are
2860 dot = q; // go to new loc
2861 refresh(FALSE); // let the user see it
2862 (void) mysleep(40); // give user some time
2863 dot = save_dot; // go back to old loc
2864 refresh(FALSE);
2865 }
2866}
2867#endif /* BB_FEATURE_VI_SETOPTS */
2868
2869// open a hole in text[]
2870static Byte *text_hole_make(Byte * p, int size) // at "p", make a 'size' byte hole
2871{
2872 Byte *src, *dest;
2873 int cnt;
2874
2875 if (size <= 0)
2876 goto thm0;
2877 src = p;
2878 dest = p + size;
2879 cnt = end - src; // the rest of buffer
2880 if (memmove(dest, src, cnt) != dest) {
2881 psbs("can't create room for new characters");
2882 }
2883 memset(p, ' ', size); // clear new hole
2884 end = end + size; // adjust the new END
2885 file_modified = TRUE; // has the file been modified
2886 thm0:
2887 return (p);
2888}
2889
2890// close a hole in text[]
2891static Byte *text_hole_delete(Byte * p, Byte * q) // delete "p" thru "q", inclusive
2892{
2893 Byte *src, *dest;
2894 int cnt, hole_size;
2895
2896 // move forwards, from beginning
2897 // assume p <= q
2898 src = q + 1;
2899 dest = p;
2900 if (q < p) { // they are backward- swap them
2901 src = p + 1;
2902 dest = q;
2903 }
2904 hole_size = q - p + 1;
2905 cnt = end - src;
2906 if (src < text || src > end)
2907 goto thd0;
2908 if (dest < text || dest >= end)
2909 goto thd0;
2910 if (src >= end)
2911 goto thd_atend; // just delete the end of the buffer
2912 if (memmove(dest, src, cnt) != dest) {
2913 psbs("can't delete the character");
2914 }
2915 thd_atend:
2916 end = end - hole_size; // adjust the new END
2917 if (dest >= end)
2918 dest = end - 1; // make sure dest in below end-1
2919 if (end <= text)
2920 dest = end = text; // keep pointers valid
2921 file_modified = TRUE; // has the file been modified
2922 thd0:
2923 return (dest);
2924}
2925
2926// copy text into register, then delete text.
2927// if dist <= 0, do not include, or go past, a NewLine
2928//
2929static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf)
2930{
2931 Byte *p;
2932
2933 // make sure start <= stop
2934 if (start > stop) {
2935 // they are backwards, reverse them
2936 p = start;
2937 start = stop;
2938 stop = p;
2939 }
2940 if (dist <= 0) {
2941 // we can not cross NL boundaries
2942 p = start;
2943 if (*p == '\n')
2944 return (p);
2945 // dont go past a NewLine
2946 for (; p + 1 <= stop; p++) {
2947 if (p[1] == '\n') {
2948 stop = p; // "stop" just before NewLine
2949 break;
2950 }
2951 }
2952 }
2953 p = start;
2954#ifdef BB_FEATURE_VI_YANKMARK
2955 text_yank(start, stop, YDreg);
2956#endif /* BB_FEATURE_VI_YANKMARK */
2957 if (yf == YANKDEL) {
2958 p = text_hole_delete(start, stop);
2959 } // delete lines
2960 return (p);
2961}
2962
2963static void show_help(void)
2964{
2965 puts("These features are available:"
2966#ifdef BB_FEATURE_VI_SEARCH
2967 "\n\tPattern searches with / and ?"
2968#endif /* BB_FEATURE_VI_SEARCH */
2969#ifdef BB_FEATURE_VI_DOT_CMD
2970 "\n\tLast command repeat with \'.\'"
2971#endif /* BB_FEATURE_VI_DOT_CMD */
2972#ifdef BB_FEATURE_VI_YANKMARK
2973 "\n\tLine marking with 'x"
2974 "\n\tNamed buffers with \"x"
2975#endif /* BB_FEATURE_VI_YANKMARK */
2976#ifdef BB_FEATURE_VI_READONLY
2977 "\n\tReadonly if vi is called as \"view\""
2978 "\n\tReadonly with -R command line arg"
2979#endif /* BB_FEATURE_VI_READONLY */
2980#ifdef BB_FEATURE_VI_SET
2981 "\n\tSome colon mode commands with \':\'"
2982#endif /* BB_FEATURE_VI_SET */
2983#ifdef BB_FEATURE_VI_SETOPTS
2984 "\n\tSettable options with \":set\""
2985#endif /* BB_FEATURE_VI_SETOPTS */
2986#ifdef BB_FEATURE_VI_USE_SIGNALS
2987 "\n\tSignal catching- ^C"
2988 "\n\tJob suspend and resume with ^Z"
2989#endif /* BB_FEATURE_VI_USE_SIGNALS */
2990#ifdef BB_FEATURE_VI_WIN_RESIZE
2991 "\n\tAdapt to window re-sizes"
2992#endif /* BB_FEATURE_VI_WIN_RESIZE */
2993 );
2994}
2995
2996static void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable
2997{
2998 Byte c, b[2];
2999
3000 b[1] = '\0';
3001 strcpy((char *) buf, ""); // init buf
3002 if (strlen((char *) s) <= 0)
3003 s = (Byte *) "(NULL)";
3004 for (; *s > '\0'; s++) {
3005 c = *s;
3006 if (*s > '~') {
3007 strcat((char *) buf, SOs);
3008 c = *s - 128;
3009 }
3010 if (*s < ' ') {
3011 strcat((char *) buf, "^");
3012 c += '@';
3013 }
3014 b[0] = c;
3015 strcat((char *) buf, (char *) b);
3016 if (*s > '~')
3017 strcat((char *) buf, SOn);
3018 if (*s == '\n') {
3019 strcat((char *) buf, "$");
3020 }
3021 }
3022}
3023
3024#ifdef BB_FEATURE_VI_DOT_CMD
3025static void start_new_cmd_q(Byte c)
3026{
3027 // release old cmd
3028 if (last_modifying_cmd != 0)
3029 free(last_modifying_cmd);
3030 // get buffer for new cmd
3031 last_modifying_cmd = (Byte *) malloc(BUFSIZ);
3032 memset(last_modifying_cmd, '\0', BUFSIZ); // clear new cmd queue
3033 // if there is a current cmd count put it in the buffer first
3034 if (cmdcnt > 0)
3035 sprintf((char *) last_modifying_cmd, "%d", cmdcnt);
3036 // save char c onto queue
3037 last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c;
3038 adding2q = 1;
3039 return;
3040}
3041
3042static void end_cmd_q()
3043{
3044#ifdef BB_FEATURE_VI_YANKMARK
3045 YDreg = 26; // go back to default Yank/Delete reg
3046#endif /* BB_FEATURE_VI_YANKMARK */
3047 adding2q = 0;
3048 return;
3049}
3050#endif /* BB_FEATURE_VI_DOT_CMD */
3051
3052#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME)
3053static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p'
3054{
3055 int cnt, i;
3056
3057 i = strlen((char *) s);
3058 p = text_hole_make(p, i);
3059 strncpy((char *) p, (char *) s, i);
3060 for (cnt = 0; *s != '\0'; s++) {
3061 if (*s == '\n')
3062 cnt++;
3063 }
3064#ifdef BB_FEATURE_VI_YANKMARK
3065 psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
3066#endif /* BB_FEATURE_VI_YANKMARK */
3067 return (p);
3068}
3069#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */
3070
3071#ifdef BB_FEATURE_VI_YANKMARK
3072static Byte *text_yank(Byte * p, Byte * q, int dest) // copy text into a register
3073{
3074 Byte *t;
3075 int cnt;
3076
3077 if (q < p) { // they are backwards- reverse them
3078 t = q;
3079 q = p;
3080 p = t;
3081 }
3082 cnt = q - p + 1;
3083 t = reg[dest];
3084 if (t != 0) { // if already a yank register
3085 free(t); // free it
3086 }
3087 t = (Byte *) malloc(cnt + 1); // get a new register
3088 memset(t, '\0', cnt + 1); // clear new text[]
3089 strncpy((char *) t, (char *) p, cnt); // copy text[] into bufer
3090 reg[dest] = t;
3091 return (p);
3092}
3093
3094static Byte what_reg(void)
3095{
3096 Byte c;
3097 int i;
3098
3099 i = 0;
3100 c = 'D'; // default to D-reg
3101 if (0 <= YDreg && YDreg <= 25)
3102 c = 'a' + (Byte) YDreg;
3103 if (YDreg == 26)
3104 c = 'D';
3105 if (YDreg == 27)
3106 c = 'U';
3107 return (c);
3108}
3109
3110static void check_context(Byte cmd)
3111{
3112 // A context is defined to be "modifying text"
3113 // Any modifying command establishes a new context.
3114
3115 if (dot < context_start || dot > context_end) {
3116 if (strchr((char *) modifying_cmds, cmd) != NULL) {
3117 // we are trying to modify text[]- make this the current context
3118 mark[27] = mark[26]; // move cur to prev
3119 mark[26] = dot; // move local to cur
3120 context_start = prev_line(prev_line(dot));
3121 context_end = next_line(next_line(dot));
3122 //loiter= start_loiter= now;
3123 }
3124 }
3125 return;
3126}
3127
3128static Byte *swap_context(Byte * p) // goto new context for '' command make this the current context
3129{
3130 Byte *tmp;
3131
3132 // the current context is in mark[26]
3133 // the previous context is in mark[27]
3134 // only swap context if other context is valid
3135 if (text <= mark[27] && mark[27] <= end - 1) {
3136 tmp = mark[27];
3137 mark[27] = mark[26];
3138 mark[26] = tmp;
3139 p = mark[26]; // where we are going- previous context
3140 context_start = prev_line(prev_line(prev_line(p)));
3141 context_end = next_line(next_line(next_line(p)));
3142 }
3143 return (p);
3144}
3145#endif /* BB_FEATURE_VI_YANKMARK */
3146
3147static int isblnk(Byte c) // is the char a blank or tab
3148{
3149 return (c == ' ' || c == '\t');
3150}
3151
3152//----- Set terminal attributes --------------------------------
3153static void rawmode(void)
3154{
3155 tcgetattr(0, &term_orig);
3156 term_vi = term_orig;
3157 term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's
3158 term_vi.c_iflag &= (~IXON & ~ICRNL);
3159 term_vi.c_oflag &= (~ONLCR);
3160#ifndef linux
3161 term_vi.c_cc[VMIN] = 1;
3162 term_vi.c_cc[VTIME] = 0;
3163#endif
3164 erase_char = term_vi.c_cc[VERASE];
3165 tcsetattr(0, TCSANOW, &term_vi);
3166}
3167
3168static void cookmode(void)
3169{
3170 tcsetattr(0, TCSANOW, &term_orig);
3171}
3172
3173#ifdef BB_FEATURE_VI_WIN_RESIZE
3174//----- See what the window size currently is --------------------
3175static void window_size_get(int sig)
3176{
3177 int i;
3178
3179 i = ioctl(0, TIOCGWINSZ, &winsize);
3180 if (i != 0) {
3181 // force 24x80
3182 winsize.ws_row = 24;
3183 winsize.ws_col = 80;
3184 }
3185 if (winsize.ws_row <= 1) {
3186 winsize.ws_row = 24;
3187 }
3188 if (winsize.ws_col <= 1) {
3189 winsize.ws_col = 80;
3190 }
3191 rows = (int) winsize.ws_row;
3192 columns = (int) winsize.ws_col;
3193}
3194#endif /* BB_FEATURE_VI_WIN_RESIZE */
3195
3196//----- Come here when we get a window resize signal ---------
3197#ifdef BB_FEATURE_VI_USE_SIGNALS
3198static void winch_sig(int sig)
3199{
3200 signal(SIGWINCH, winch_sig);
3201#ifdef BB_FEATURE_VI_WIN_RESIZE
3202 window_size_get(0);
3203#endif /* BB_FEATURE_VI_WIN_RESIZE */
3204 new_screen(rows, columns); // get memory for virtual screen
3205 redraw(TRUE); // re-draw the screen
3206}
3207
3208//----- Come here when we get a continue signal -------------------
3209static void cont_sig(int sig)
3210{
3211 rawmode(); // terminal to "raw"
3212 *status_buffer = '\0'; // clear the status buffer
3213 redraw(TRUE); // re-draw the screen
3214
3215 signal(SIGTSTP, suspend_sig);
3216 signal(SIGCONT, SIG_DFL);
3217 kill(getpid(), SIGCONT);
3218}
3219
3220//----- Come here when we get a Suspend signal -------------------
3221static void suspend_sig(int sig)
3222{
3223 place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
3224 clear_to_eol(); // Erase to end of line
3225 cookmode(); // terminal to "cooked"
3226
3227 signal(SIGCONT, cont_sig);
3228 signal(SIGTSTP, SIG_DFL);
3229 kill(getpid(), SIGTSTP);
3230}
3231
3232//----- Come here when we get a signal ---------------------------
3233static void catch_sig(int sig)
3234{
3235 signal(SIGHUP, catch_sig);
3236 signal(SIGINT, catch_sig);
3237 signal(SIGTERM, catch_sig);
3238 longjmp(restart, sig);
3239}
3240
3241static void alarm_sig(int sig)
3242{
3243 signal(SIGALRM, catch_sig);
3244 longjmp(restart, sig);
3245}
3246
3247//----- Come here when we get a core dump signal -----------------
3248static void core_sig(int sig)
3249{
3250 signal(SIGQUIT, core_sig);
3251 signal(SIGILL, core_sig);
3252 signal(SIGTRAP, core_sig);
3253 signal(SIGIOT, core_sig);
3254 signal(SIGABRT, core_sig);
3255 signal(SIGFPE, core_sig);
3256 signal(SIGBUS, core_sig);
3257 signal(SIGSEGV, core_sig);
3258#ifdef SIGSYS
3259 signal(SIGSYS, core_sig);
3260#endif
3261
3262 dot = bound_dot(dot); // make sure "dot" is valid
3263
3264 longjmp(restart, sig);
3265}
3266#endif /* BB_FEATURE_VI_USE_SIGNALS */
3267
3268static int mysleep(int hund) // sleep for 'h' 1/100 seconds
3269{
3270 // Don't hang- Wait 5/100 seconds- 1 Sec= 1000000
3271 FD_ZERO(&rfds);
3272 FD_SET(0, &rfds);
3273 tv.tv_sec = 0;
3274 tv.tv_usec = hund * 10000;
3275 select(1, &rfds, NULL, NULL, &tv);
3276 return (FD_ISSET(0, &rfds));
3277}
3278
3279//----- IO Routines --------------------------------------------
3280static Byte readit(void) // read (maybe cursor) key from stdin
3281{
3282 Byte c;
3283 int i, bufsiz, cnt, cmdindex;
3284 struct esc_cmds {
3285 Byte *seq;
3286 Byte val;
3287 };
3288
3289 static struct esc_cmds esccmds[] = {
3290 {(Byte *) "OA", (Byte) VI_K_UP}, // cursor key Up
3291 {(Byte *) "OB", (Byte) VI_K_DOWN}, // cursor key Down
3292 {(Byte *) "OC", (Byte) VI_K_RIGHT}, // Cursor Key Right
3293 {(Byte *) "OD", (Byte) VI_K_LEFT}, // cursor key Left
3294 {(Byte *) "OH", (Byte) VI_K_HOME}, // Cursor Key Home
3295 {(Byte *) "OF", (Byte) VI_K_END}, // Cursor Key End
3296 {(Byte *) "", (Byte) VI_K_UP}, // cursor key Up
3297 {(Byte *) "", (Byte) VI_K_DOWN}, // cursor key Down
3298 {(Byte *) "", (Byte) VI_K_RIGHT}, // Cursor Key Right
3299 {(Byte *) "", (Byte) VI_K_LEFT}, // cursor key Left
3300 {(Byte *) "", (Byte) VI_K_HOME}, // Cursor Key Home
3301 {(Byte *) "", (Byte) VI_K_END}, // Cursor Key End
3302 {(Byte *) "[2~", (Byte) VI_K_INSERT}, // Cursor Key Insert
3303 {(Byte *) "[5~", (Byte) VI_K_PAGEUP}, // Cursor Key Page Up
3304 {(Byte *) "[6~", (Byte) VI_K_PAGEDOWN}, // Cursor Key Page Down
3305 {(Byte *) "OP", (Byte) VI_K_FUN1}, // Function Key F1
3306 {(Byte *) "OQ", (Byte) VI_K_FUN2}, // Function Key F2
3307 {(Byte *) "OR", (Byte) VI_K_FUN3}, // Function Key F3
3308 {(Byte *) "OS", (Byte) VI_K_FUN4}, // Function Key F4
3309 {(Byte *) "[15~", (Byte) VI_K_FUN5}, // Function Key F5
3310 {(Byte *) "[17~", (Byte) VI_K_FUN6}, // Function Key F6
3311 {(Byte *) "[18~", (Byte) VI_K_FUN7}, // Function Key F7
3312 {(Byte *) "[19~", (Byte) VI_K_FUN8}, // Function Key F8
3313 {(Byte *) "[20~", (Byte) VI_K_FUN9}, // Function Key F9
3314 {(Byte *) "[21~", (Byte) VI_K_FUN10}, // Function Key F10
3315 {(Byte *) "[23~", (Byte) VI_K_FUN11}, // Function Key F11
3316 {(Byte *) "[24~", (Byte) VI_K_FUN12}, // Function Key F12
3317 {(Byte *) "[11~", (Byte) VI_K_FUN1}, // Function Key F1
3318 {(Byte *) "[12~", (Byte) VI_K_FUN2}, // Function Key F2
3319 {(Byte *) "[13~", (Byte) VI_K_FUN3}, // Function Key F3
3320 {(Byte *) "[14~", (Byte) VI_K_FUN4}, // Function Key F4
3321 };
3322
3323#define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds))
3324
3325 (void) alarm(0); // turn alarm OFF while we wait for input
3326 // get input from User- are there already input chars in Q?
3327 bufsiz = strlen((char *) readbuffer);
3328 if (bufsiz <= 0) {
3329 ri0:
3330 // the Q is empty, wait for a typed char
3331 bufsiz = read(0, readbuffer, BUFSIZ - 1);
3332 if (bufsiz < 0) {
3333 if (errno == EINTR)
3334 goto ri0; // interrupted sys call
3335 if (errno == EBADF)
3336 editing = 0;
3337 if (errno == EFAULT)
3338 editing = 0;
3339 if (errno == EINVAL)
3340 editing = 0;
3341 if (errno == EIO)
3342 editing = 0;
3343 errno = 0;
3344 bufsiz = 0;
3345 }
3346 readbuffer[bufsiz] = '\0';
3347 }
3348 // return char if it is not part of ESC sequence
3349 if (readbuffer[0] != 27)
3350 goto ri1;
3351
3352 // This is an ESC char. Is this Esc sequence?
3353 // Could be bare Esc key. See if there are any
3354 // more chars to read after the ESC. This would
3355 // be a Function or Cursor Key sequence.
3356 FD_ZERO(&rfds);
3357 FD_SET(0, &rfds);
3358 tv.tv_sec = 0;
3359 tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000
3360
3361 // keep reading while there are input chars and room in buffer
3362 while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) {
3363 // read the rest of the ESC string
3364 i = read(0, (void *) (readbuffer + bufsiz), BUFSIZ - bufsiz);
3365 if (i > 0) {
3366 bufsiz += i;
3367 readbuffer[bufsiz] = '\0'; // Terminate the string
3368 }
3369 }
3370 // Maybe cursor or function key?
3371 for (cmdindex = 0; cmdindex < ESCCMDS_COUNT; cmdindex++) {
3372 cnt = strlen((char *) esccmds[cmdindex].seq);
3373 i = strncmp((char *) esccmds[cmdindex].seq, (char *) readbuffer, cnt);
3374 if (i == 0) {
3375 // is a Cursor key- put derived value back into Q
3376 readbuffer[0] = esccmds[cmdindex].val;
3377 // squeeze out the ESC sequence
3378 for (i = 1; i < cnt; i++) {
3379 memmove(readbuffer + 1, readbuffer + 2, BUFSIZ - 2);
3380 readbuffer[BUFSIZ - 1] = '\0';
3381 }
3382 break;
3383 }
3384 }
3385 ri1:
3386 c = readbuffer[0];
3387 // remove one char from Q
3388 memmove(readbuffer, readbuffer + 1, BUFSIZ - 1);
3389 readbuffer[BUFSIZ - 1] = '\0';
3390 (void) alarm(3); // we are done waiting for input, turn alarm ON
3391 return (c);
3392}
3393
3394//----- IO Routines --------------------------------------------
3395static Byte get_one_char()
3396{
3397 static Byte c;
3398
3399#ifdef BB_FEATURE_VI_DOT_CMD
3400 // ! adding2q && ioq == 0 read()
3401 // ! adding2q && ioq != 0 *ioq
3402 // adding2q *last_modifying_cmd= read()
3403 if (!adding2q) {
3404 // we are not adding to the q.
3405 // but, we may be reading from a q
3406 if (ioq == 0) {
3407 // there is no current q, read from STDIN
3408 c = readit(); // get the users input
3409 } else {
3410 // there is a queue to get chars from first
3411 c = *ioq++;
3412 if (c == '\0') {
3413 // the end of the q, read from STDIN
3414 free(ioq_start);
3415 ioq_start = ioq = 0;
3416 c = readit(); // get the users input
3417 }
3418 }
3419 } else {
3420 // adding STDIN chars to q
3421 c = readit(); // get the users input
3422 if (last_modifying_cmd != 0) {
3423 // add new char to q
3424 last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c;
3425 }
3426 }
3427#else /* BB_FEATURE_VI_DOT_CMD */
3428 c = readit(); // get the users input
3429#endif /* BB_FEATURE_VI_DOT_CMD */
3430 return (c); // return the char, where ever it came from
3431}
3432
3433static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
3434{
3435 Byte buf[BUFSIZ];
3436 Byte c;
3437 int i;
3438 static Byte *obufp = NULL;
3439
3440 strcpy((char *) buf, (char *) prompt);
3441 *status_buffer = '\0'; // clear the status buffer
3442 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
3443 clear_to_eol(); // clear the line
3444 write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt
3445
3446 for (i = strlen((char *) buf); i < BUFSIZ;) {
3447 c = get_one_char(); // read user input
3448 if (c == '\n' || c == '\r' || c == 27)
3449 break; // is this end of input
3450 if (c == erase_char) { // user wants to erase prev char
3451 i--; // backup to prev char
3452 buf[i] = '\0'; // erase the char
3453 buf[i + 1] = '\0'; // null terminate buffer
3454 write(1, " ", 3); // erase char on screen
3455 if (i <= 0) { // user backs up before b-o-l, exit
3456 break;
3457 }
3458 } else {
3459 buf[i] = c; // save char in buffer
3460 buf[i + 1] = '\0'; // make sure buffer is null terminated
3461 write(1, buf + i, 1); // echo the char back to user
3462 i++;
3463 }
3464 }
3465 refresh(FALSE);
3466 if (obufp != NULL)
3467 free(obufp);
3468 obufp = (Byte *) strdup((char *) buf);
3469 return (obufp);
3470}
3471
3472static int file_size(Byte * fn) // what is the byte size of "fn"
3473{
3474 struct stat st_buf;
3475 int cnt, sr;
3476
3477 if (fn == 0 || strlen(fn) <= 0)
3478 return (-1);
3479 cnt = -1;
3480 sr = stat((char *) fn, &st_buf); // see if file exists
3481 if (sr >= 0) {
3482 cnt = (int) st_buf.st_size;
3483 }
3484 return (cnt);
3485}
3486
3487static int file_insert(Byte * fn, Byte * p, int size)
3488{
3489 int fd, cnt;
3490
3491 cnt = -1;
3492#ifdef BB_FEATURE_VI_READONLY
3493 readonly = FALSE;
3494#endif /* BB_FEATURE_VI_READONLY */
3495 if (fn == 0 || strlen((char*) fn) <= 0) {
3496 psbs("No filename given");
3497 goto fi0;
3498 }
3499 if (size == 0) {
3500 // OK- this is just a no-op
3501 cnt = 0;
3502 goto fi0;
3503 }
3504 if (size < 0) {
3505 psbs("Trying to insert a negative number (%d) of characters", size);
3506 goto fi0;
3507 }
3508 if (p < text || p > end) {
3509 psbs("Trying to insert file outside of memory");
3510 goto fi0;
3511 }
3512
3513 // see if we can open the file
3514#ifdef BB_FEATURE_VI_READONLY
3515 if (vi_readonly == TRUE) goto fi1; // do not try write-mode
3516#endif
3517 fd = open((char *) fn, O_RDWR); // assume read & write
3518 if (fd < 0) {
3519 // could not open for writing- maybe file is read only
3520#ifdef BB_FEATURE_VI_READONLY
3521 fi1:
3522#endif
3523 fd = open((char *) fn, O_RDONLY); // try read-only
3524 if (fd < 0) {
3525 psbs("\"%s\" %s", fn, "could not open file");
3526 goto fi0;
3527 }
3528#ifdef BB_FEATURE_VI_READONLY
3529 // got the file- read-only
3530 readonly = TRUE;
3531#endif /* BB_FEATURE_VI_READONLY */
3532 }
3533 p = text_hole_make(p, size);
3534 cnt = read(fd, p, size);
3535 close(fd);
3536 if (cnt < 0) {
3537 cnt = -1;
3538 p = text_hole_delete(p, p + size - 1); // un-do buffer insert
3539 psbs("could not read file \"%s\"", fn);
3540 } else if (cnt < size) {
3541 // There was a partial read, shrink unused space text[]
3542 p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert
3543 psbs("could not read all of file \"%s\"", fn);
3544 }
3545 if (cnt >= size)
3546 file_modified = TRUE;
3547 fi0:
3548 return (cnt);
3549}
3550
3551static int file_write(Byte * fn, Byte * first, Byte * last)
3552{
3553 int fd, cnt, charcnt;
3554
3555 if (fn == 0) {
3556 psbs("No current filename");
3557 return (-1);
3558 }
3559 charcnt = 0;
3560 // FIXIT- use the correct umask()
3561 fd = open((char *) fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664);
3562 if (fd < 0)
3563 return (-1);
3564 cnt = last - first + 1;
3565 charcnt = write(fd, first, cnt);
3566 if (charcnt == cnt) {
3567 // good write
3568 //file_modified= FALSE; // the file has not been modified
3569 } else {
3570 charcnt = 0;
3571 }
3572 close(fd);
3573 return (charcnt);
3574}
3575
3576//----- Terminal Drawing ---------------------------------------
3577// The terminal is made up of 'rows' line of 'columns' columns.
3578// classicly this would be 24 x 80.
3579// screen coordinates
3580// 0,0 ... 0,79
3581// 1,0 ... 1,79
3582// . ... .
3583// . ... .
3584// 22,0 ... 22,79
3585// 23,0 ... 23,79 status line
3586//
3587
3588//----- Move the cursor to row x col (count from 0, not 1) -------
3589static void place_cursor(int row, int col, int opti)
3590{
3591 char cm1[BUFSIZ];
3592 char *cm;
3593 int l;
3594#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3595 char cm2[BUFSIZ];
3596 Byte *screenp;
3597 // char cm3[BUFSIZ];
3598 int Rrow= last_row;
3599#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3600
3601 memset(cm1, '\0', BUFSIZ - 1); // clear the buffer
3602
3603 if (row < 0) row = 0;
3604 if (row >= rows) row = rows - 1;
3605 if (col < 0) col = 0;
3606 if (col >= columns) col = columns - 1;
3607
3608 //----- 1. Try the standard terminal ESC sequence
3609 sprintf((char *) cm1, CMrc, row + 1, col + 1);
3610 cm= cm1;
3611 if (opti == FALSE) goto pc0;
3612
3613#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3614 //----- find the minimum # of chars to move cursor -------------
3615 //----- 2. Try moving with discreet chars (Newline, [back]space, ...)
3616 memset(cm2, '\0', BUFSIZ - 1); // clear the buffer
3617
3618 // move to the correct row
3619 while (row < Rrow) {
3620 // the cursor has to move up
3621 strcat(cm2, CMup);
3622 Rrow--;
3623 }
3624 while (row > Rrow) {
3625 // the cursor has to move down
3626 strcat(cm2, CMdown);
3627 Rrow++;
3628 }
3629
3630 // now move to the correct column
3631 strcat(cm2, "\r"); // start at col 0
3632 // just send out orignal source char to get to correct place
3633 screenp = &screen[row * columns]; // start of screen line
3634 strncat(cm2, screenp, col);
3635
3636 //----- 3. Try some other way of moving cursor
3637 //---------------------------------------------
3638
3639 // pick the shortest cursor motion to send out
3640 cm= cm1;
3641 if (strlen(cm2) < strlen(cm)) {
3642 cm= cm2;
3643 } /* else if (strlen(cm3) < strlen(cm)) {
3644 cm= cm3;
3645 } */
3646#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3647 pc0:
3648 l= strlen(cm);
3649 if (l) write(1, cm, l); // move the cursor
3650}
3651
3652//----- Erase from cursor to end of line -----------------------
3653static void clear_to_eol()
3654{
3655 write(1, Ceol, strlen(Ceol)); // Erase from cursor to end of line
3656}
3657
3658//----- Erase from cursor to end of screen -----------------------
3659static void clear_to_eos()
3660{
3661 write(1, Ceos, strlen(Ceos)); // Erase from cursor to end of screen
3662}
3663
3664//----- Start standout mode ------------------------------------
3665static void standout_start() // send "start reverse video" sequence
3666{
3667 write(1, SOs, strlen(SOs)); // Start reverse video mode
3668}
3669
3670//----- End standout mode --------------------------------------
3671static void standout_end() // send "end reverse video" sequence
3672{
3673 write(1, SOn, strlen(SOn)); // End reverse video mode
3674}
3675
3676//----- Flash the screen --------------------------------------
3677static void flash(int h)
3678{
3679 standout_start(); // send "start reverse video" sequence
3680 redraw(TRUE);
3681 (void) mysleep(h);
3682 standout_end(); // send "end reverse video" sequence
3683 redraw(TRUE);
3684}
3685
3686static void beep()
3687{
3688 write(1, bell, strlen(bell)); // send out a bell character
3689}
3690
3691static void indicate_error(char c)
3692{
3693#ifdef BB_FEATURE_VI_CRASHME
3694 if (crashme > 0)
3695 return; // generate a random command
3696#endif /* BB_FEATURE_VI_CRASHME */
3697 if (err_method == 0) {
3698 beep();
3699 } else {
3700 flash(10);
3701 }
3702}
3703
3704//----- Screen[] Routines --------------------------------------
3705//----- Erase the Screen[] memory ------------------------------
3706static void screen_erase()
3707{
3708 memset(screen, ' ', screensize); // clear new screen
3709}
3710
3711//----- Draw the status line at bottom of the screen -------------
3712static void show_status_line(void)
3713{
3714 static int last_cksum;
3715 int l, cnt, cksum;
3716
3717 cnt = strlen((char *) status_buffer);
3718 for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); }
3719 // don't write the status line unless it changes
3720 if (cnt > 0 && last_cksum != cksum) {
3721 last_cksum= cksum; // remember if we have seen this line
3722 place_cursor(rows - 1, 0, FALSE); // put cursor on status line
3723 write(1, status_buffer, cnt);
3724 clear_to_eol();
3725 place_cursor(crow, ccol, FALSE); // put cursor back in correct place
3726 }
3727}
3728
3729//----- format the status buffer, the bottom line of screen ------
3730// print status buffer, with STANDOUT mode
3731static void psbs(char *format, ...)
3732{
3733 va_list args;
3734
3735 va_start(args, format);
3736 strcpy((char *) status_buffer, SOs); // Terminal standout mode on
3737 vsprintf((char *) status_buffer + strlen((char *) status_buffer), format,
3738 args);
3739 strcat((char *) status_buffer, SOn); // Terminal standout mode off
3740 va_end(args);
3741
3742 return;
3743}
3744
3745// print status buffer
3746static void psb(char *format, ...)
3747{
3748 va_list args;
3749
3750 va_start(args, format);
3751 vsprintf((char *) status_buffer, format, args);
3752 va_end(args);
3753 return;
3754}
3755
3756static void ni(Byte * s) // display messages
3757{
3758 Byte buf[BUFSIZ];
3759
3760 print_literal(buf, s);
3761 psbs("\'%s\' is not implemented", buf);
3762}
3763
3764static void edit_status(void) // show file status on status line
3765{
3766 int cur, tot, percent;
3767
3768 cur = count_lines(text, dot);
3769 tot = count_lines(text, end - 1);
3770 // current line percent
3771 // ------------- ~~ ----------
3772 // total lines 100
3773 if (tot > 0) {
3774 percent = (100 * cur) / tot;
3775 } else {
3776 cur = tot = 0;
3777 percent = 100;
3778 }
3779 psb("\"%s\""
3780#ifdef BB_FEATURE_VI_READONLY
3781 "%s"
3782#endif /* BB_FEATURE_VI_READONLY */
3783 "%s line %d of %d --%d%%--",
3784 (cfn != 0 ? (char *) cfn : "No file"),
3785#ifdef BB_FEATURE_VI_READONLY
3786 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
3787#endif /* BB_FEATURE_VI_READONLY */
3788 (file_modified == TRUE ? " [modified]" : ""),
3789 cur, tot, percent);
3790}
3791
3792//----- Force refresh of all Lines -----------------------------
3793static void redraw(int full_screen)
3794{
3795 place_cursor(0, 0, FALSE); // put cursor in correct place
3796 clear_to_eos(); // tel terminal to erase display
3797 screen_erase(); // erase the internal screen buffer
3798 refresh(full_screen); // this will redraw the entire display
3799}
3800
3801//----- Format a text[] line into a buffer ---------------------
3802static void format_line(Byte *dest, Byte *src, int li)
3803{
3804 int co;
3805 Byte c;
3806
3807 for (co= 0; co < MAX_SCR_COLS; co++) {
3808 c= ' '; // assume blank
3809 if (li > 0 && co == 0) {
3810 c = '~'; // not first line, assume Tilde
3811 }
3812 // are there chars in text[] and have we gone past the end
3813 if (text < end && src < end) {
3814 c = *src++;
3815 }
3816 if (c == '\n')
3817 break;
3818 if (c < ' ' || c > '~') {
3819 if (c == '\t') {
3820 c = ' ';
3821 // co % 8 != 7
3822 for (; (co % tabstop) != (tabstop - 1); co++) {
3823 dest[co] = c;
3824 }
3825 } else {
3826 dest[co++] = '^';
3827 c |= '@'; // make it visible
3828 c &= 0x7f; // get rid of hi bit
3829 }
3830 }
3831 // the co++ is done here so that the column will
3832 // not be overwritten when we blank-out the rest of line
3833 dest[co] = c;
3834 if (src >= end)
3835 break;
3836 }
3837}
3838
3839//----- Refresh the changed screen lines -----------------------
3840// Copy the source line from text[] into the buffer and note
3841// if the current screenline is different from the new buffer.
3842// If they differ then that line needs redrawing on the terminal.
3843//
3844static void refresh(int full_screen)
3845{
3846 static int old_offset;
3847 int li, changed;
3848 Byte buf[MAX_SCR_COLS];
3849 Byte *tp, *sp; // pointer into text[] and screen[]
3850#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3851 int last_li= -2; // last line that changed- for optimizing cursor movement
3852#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3853
3854#ifdef BB_FEATURE_VI_WIN_RESIZE
3855 window_size_get(0);
3856#endif /* BB_FEATURE_VI_WIN_RESIZE */
3857 sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot")
3858 tp = screenbegin; // index into text[] of top line
3859
3860 // compare text[] to screen[] and mark screen[] lines that need updating
3861 for (li = 0; li < rows - 1; li++) {
3862 int cs, ce; // column start & end
3863 memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer
3864 buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer
3865 // format current text line into buf
3866 format_line(buf, tp, li);
3867
3868 // skip to the end of the current text[] line
3869 while (tp < end && *tp++ != '\n') /*no-op*/ ;
3870
3871 // see if there are any changes between vitual screen and buf
3872 changed = FALSE; // assume no change
3873 cs= 0;
3874 ce= columns-1;
3875 sp = &screen[li * columns]; // start of screen line
3876 if (full_screen == TRUE) {
3877 // force re-draw of every single column from 0 - columns-1
3878 goto re0;
3879 }
3880 // compare newly formatted buffer with virtual screen
3881 // look forward for first difference between buf and screen
3882 for ( ; cs <= ce; cs++) {
3883 if (buf[cs + offset] != sp[cs]) {
3884 changed = TRUE; // mark for redraw
3885 break;
3886 }
3887 }
3888
3889 // look backward for last difference between buf and screen
3890 for ( ; ce >= cs; ce--) {
3891 if (buf[ce + offset] != sp[ce]) {
3892 changed = TRUE; // mark for redraw
3893 break;
3894 }
3895 }
3896 // now, cs is index of first diff, and ce is index of last diff
3897
3898 // if horz offset has changed, force a redraw
3899 if (offset != old_offset) {
3900 re0:
3901 changed = TRUE;
3902 }
3903
3904 // make a sanity check of columns indexes
3905 if (cs < 0) cs= 0;
3906 if (ce > columns-1) ce= columns-1;
3907 if (cs > ce) { cs= 0; ce= columns-1; }
3908 // is there a change between vitual screen and buf
3909 if (changed == TRUE) {
3910 // copy changed part of buffer to virtual screen
3911 memmove(sp+cs, buf+(cs+offset), ce-cs+1);
3912
3913 // move cursor to column of first change
3914 if (offset != old_offset) {
3915 // opti_cur_move is still too stupid
3916 // to handle offsets correctly
3917 place_cursor(li, cs, FALSE);
3918 } else {
3919#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3920 // if this just the next line
3921 // try to optimize cursor movement
3922 // otherwise, use standard ESC sequence
3923 place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
3924 last_li= li;
3925#else /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3926 place_cursor(li, cs, FALSE); // use standard ESC sequence
3927#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3928 }
3929
3930 // write line out to terminal
3931 write(1, sp+cs, ce-cs+1);
3932#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3933 last_row = li;
3934#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3935 }
3936 }
3937
3938#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3939 place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE);
3940 last_row = crow;
3941#else
3942 place_cursor(crow, ccol, FALSE);
3943#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3944
3945 if (offset != old_offset)
3946 old_offset = offset;
3947}
diff --git a/watchdog.c b/watchdog.c
deleted file mode 100644
index f0b0ebd0e..000000000
--- a/watchdog.c
+++ /dev/null
@@ -1,49 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini watchdog implementation for busybox
4 *
5 * Copyright (C) 2000 spoon <spoon@ix.netcom.com>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23/* getopt not needed */
24
25#include <stdio.h>
26#include <fcntl.h>
27#include <unistd.h>
28#include <stdlib.h>
29#include "busybox.h"
30
31extern int watchdog_main(int argc, char **argv)
32{
33 int fd;
34
35 if (argc != 2) {
36 show_usage();
37 }
38
39 if ((fd=open(argv[1], O_WRONLY)) == -1) {
40 perror_msg_and_die(argv[1]);
41 }
42
43 while (1) {
44 sleep(30);
45 write(fd, "\0", 1);
46 }
47
48 return EXIT_FAILURE;
49}
diff --git a/wc.c b/wc.c
deleted file mode 100644
index 695e7e7d4..000000000
--- a/wc.c
+++ /dev/null
@@ -1,156 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini wc implementation for busybox
4 *
5 * Copyright (C) 2000 Edward Betts <edward@debian.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <getopt.h>
25#include <string.h>
26#include <stdlib.h>
27#include "busybox.h"
28
29static int total_lines, total_words, total_chars, max_length;
30static int print_lines, print_words, print_chars, print_length;
31
32static void print_counts(int lines, int words, int chars, int length,
33 const char *name)
34{
35 char const *space = "";
36
37 if (print_lines) {
38 printf("%7d", lines);
39 space = " ";
40 }
41 if (print_words) {
42 printf("%s%7d", space, words);
43 space = " ";
44 }
45 if (print_chars) {
46 printf("%s%7d", space, chars);
47 space = " ";
48 }
49 if (print_length)
50 printf("%s%7d", space, length);
51 if (*name)
52 printf(" %s", name);
53 putchar('\n');
54}
55
56static void wc_file(FILE * file, const char *name)
57{
58 int lines, words, chars, length;
59 int in_word = 0, linepos = 0;
60 int c;
61
62 lines = words = chars = length = 0;
63 while ((c = getc(file)) != EOF) {
64 chars++;
65 switch (c) {
66 case '\n':
67 lines++;
68 case '\r':
69 case '\f':
70 if (linepos > length)
71 length = linepos;
72 linepos = 0;
73 goto word_separator;
74 case '\t':
75 linepos += 8 - (linepos % 8);
76 goto word_separator;
77 case ' ':
78 linepos++;
79 case '\v':
80 word_separator:
81 if (in_word) {
82 in_word = 0;
83 words++;
84 }
85 break;
86 default:
87 linepos++;
88 in_word = 1;
89 break;
90 }
91 }
92 if (linepos > length)
93 length = linepos;
94 if (in_word)
95 words++;
96 print_counts(lines, words, chars, length, name);
97 total_lines += lines;
98 total_words += words;
99 total_chars += chars;
100 if (length > max_length)
101 max_length = length;
102 fclose(file);
103 fflush(stdout);
104}
105
106int wc_main(int argc, char **argv)
107{
108 FILE *file;
109 unsigned int num_files_counted = 0;
110 int opt, status = EXIT_SUCCESS;
111
112 total_lines = total_words = total_chars = max_length = 0;
113 print_lines = print_words = print_chars = print_length = 0;
114
115 while ((opt = getopt(argc, argv, "clLw")) > 0) {
116 switch (opt) {
117 case 'c':
118 print_chars = 1;
119 break;
120 case 'l':
121 print_lines = 1;
122 break;
123 case 'L':
124 print_length = 1;
125 break;
126 case 'w':
127 print_words = 1;
128 break;
129 default:
130 show_usage();
131 }
132 }
133
134 if (!print_lines && !print_words && !print_chars && !print_length)
135 print_lines = print_words = print_chars = 1;
136
137 if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) {
138 wc_file(stdin, "");
139 return EXIT_SUCCESS;
140 } else {
141 while (optind < argc) {
142 if ((file = wfopen(argv[optind], "r")) != NULL)
143 wc_file(file, argv[optind]);
144 else
145 status = EXIT_FAILURE;
146 num_files_counted++;
147 optind++;
148 }
149 }
150
151 if (num_files_counted > 1)
152 print_counts(total_lines, total_words, total_chars,
153 max_length, "total");
154
155 return status;
156}
diff --git a/wget.c b/wget.c
deleted file mode 100644
index 59373d1d9..000000000
--- a/wget.c
+++ /dev/null
@@ -1,834 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * wget - retrieve a file using HTTP or FTP
4 *
5 * Chip Rosenthal Covad Communications <chip@laserlink.net>
6 *
7 */
8
9#include <stdio.h>
10#include <errno.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <ctype.h>
14#include <string.h>
15#include <unistd.h>
16#include <signal.h>
17#include <sys/ioctl.h>
18
19#include <sys/time.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <netdb.h>
26
27#ifndef _GNU_SOURCE
28#define _GNU_SOURCE
29#endif
30#include <getopt.h>
31
32#include "busybox.h"
33
34/* Stupid libc5 doesn't define this... */
35#ifndef timersub
36#define timersub(a, b, result) \
37 do { \
38 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
39 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
40 if ((result)->tv_usec < 0) { \
41 --(result)->tv_sec; \
42 (result)->tv_usec += 1000000; \
43 } \
44 } while (0)
45#endif
46
47struct host_info {
48 char *host;
49 int port;
50 char *path;
51 int is_ftp;
52 char *user;
53};
54
55static void parse_url(char *url, struct host_info *h);
56static FILE *open_socket(char *host, int port);
57static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc);
58static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf);
59
60/* Globals (can be accessed from signal handlers */
61static off_t filesize = 0; /* content-length of the file */
62static int chunked = 0; /* chunked transfer encoding */
63#ifdef BB_FEATURE_WGET_STATUSBAR
64static void progressmeter(int flag);
65static char *curfile; /* Name of current file being transferred. */
66static struct timeval start; /* Time a transfer started. */
67static volatile unsigned long statbytes = 0; /* Number of bytes transferred so far. */
68/* For progressmeter() -- number of seconds before xfer considered "stalled" */
69static const int STALLTIME = 5;
70#endif
71
72static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue)
73{
74 if (output != stdout && do_continue==0) {
75 fclose(output);
76 unlink(fname_out);
77 }
78}
79
80/* Read NMEMB elements of SIZE bytes into PTR from STREAM. Returns the
81 * number of elements read, and a short count if an eof or non-interrupt
82 * error is encountered. */
83static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
84{
85 size_t ret = 0;
86
87 do {
88 clearerr(stream);
89 ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
90 } while (ret < nmemb && ferror(stream) && errno == EINTR);
91
92 return ret;
93}
94
95/* Write NMEMB elements of SIZE bytes from PTR to STREAM. Returns the
96 * number of elements written, and a short count if an eof or non-interrupt
97 * error is encountered. */
98static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
99{
100 size_t ret = 0;
101
102 do {
103 clearerr(stream);
104 ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
105 } while (ret < nmemb && ferror(stream) && errno == EINTR);
106
107 return ret;
108}
109
110/* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM.
111 * Returns S, or NULL if an eof or non-interrupt error is encountered. */
112static char *safe_fgets(char *s, int size, FILE *stream)
113{
114 char *ret;
115
116 do {
117 clearerr(stream);
118 ret = fgets(s, size, stream);
119 } while (ret == NULL && ferror(stream) && errno == EINTR);
120
121 return ret;
122}
123
124#define close_delete_and_die(s...) { \
125 close_and_delete_outfile(output, fname_out, do_continue); \
126 error_msg_and_die(s); }
127
128
129#ifdef BB_FEATURE_WGET_AUTHENTICATION
130/*
131 * Base64-encode character string
132 * oops... isn't something similar in uuencode.c?
133 * It would be better to use already existing code
134 */
135char *base64enc(char *p, char *buf, int len) {
136
137 char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
138 "0123456789+/";
139 char *s = buf;
140
141 while(*p) {
142 if (s >= buf+len-4)
143 error_msg_and_die("buffer overflow");
144 *(s++) = al[(*p >> 2) & 0x3F];
145 *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)];
146 *s = *(s+1) = '=';
147 *(s+2) = 0;
148 if (! *(++p)) break;
149 *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)];
150 if (! *(++p)) break;
151 *(s++) = al[*(p++) & 0x3F];
152 }
153
154 return buf;
155}
156#endif
157
158int wget_main(int argc, char **argv)
159{
160 int n, try=5, status;
161 int port;
162 char *proxy;
163 char *dir_prefix=NULL;
164 char *s, buf[512];
165 struct stat sbuf;
166 char extra_headers[1024];
167 char *extra_headers_ptr = extra_headers;
168 int extra_headers_left = sizeof(extra_headers);
169 int which_long_opt = 0, option_index = -1;
170 struct host_info server, target;
171
172 FILE *sfp = NULL; /* socket to web/ftp server */
173 FILE *dfp = NULL; /* socket to ftp server (data) */
174 char *fname_out = NULL; /* where to direct output (-O) */
175 int do_continue = 0; /* continue a prev transfer (-c) */
176 long beg_range = 0L; /* range at which continue begins */
177 int got_clen = 0; /* got content-length: from server */
178 FILE *output; /* socket to web server */
179 int quiet_flag = FALSE; /* Be verry, verry quiet... */
180
181#define LONG_HEADER 1
182 struct option long_options[] = {
183 { "continue", 0, NULL, 'c' },
184 { "quiet", 0, NULL, 'q' },
185 { "output-document", 1, NULL, 'O' },
186 { "header", 1, &which_long_opt, LONG_HEADER },
187 { 0, 0, 0, 0 }
188 };
189 /*
190 * Crack command line.
191 */
192 while ((n = getopt_long(argc, argv, "cqO:P:", long_options, &option_index)) != EOF) {
193 switch (n) {
194 case 'c':
195 ++do_continue;
196 break;
197 case 'P':
198 dir_prefix = optarg;
199 break;
200 case 'q':
201 quiet_flag = TRUE;
202 break;
203 case 'O':
204 /* can't set fname_out to NULL if outputting to stdout, because
205 * this gets interpreted as the auto-gen output filename
206 * case below - tausq@debian.org
207 */
208 fname_out = optarg;
209 break;
210 case 0:
211 switch (which_long_opt) {
212 case LONG_HEADER: {
213 int arglen = strlen(optarg);
214 if(extra_headers_left - arglen - 2 <= 0)
215 error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen);
216 strcpy(extra_headers_ptr, optarg);
217 extra_headers_ptr += arglen;
218 extra_headers_left -= ( arglen + 2 );
219 *extra_headers_ptr++ = '\r';
220 *extra_headers_ptr++ = '\n';
221 *(extra_headers_ptr + 1) = 0;
222 break;
223 }
224 }
225 break;
226 default:
227 show_usage();
228 }
229 }
230
231 if (argc - optind != 1)
232 show_usage();
233
234 parse_url(argv[optind], &target);
235 server.host = target.host;
236 server.port = target.port;
237
238 /*
239 * Use the proxy if necessary.
240 */
241 proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
242 if (proxy)
243 parse_url(xstrdup(proxy), &server);
244
245 /* Guess an output filename */
246 if (!fname_out) {
247 fname_out =
248#ifdef BB_FEATURE_WGET_STATUSBAR
249 curfile =
250#endif
251 get_last_path_component(target.path);
252 if (fname_out==NULL || strlen(fname_out)<1) {
253 fname_out =
254#ifdef BB_FEATURE_WGET_STATUSBAR
255 curfile =
256#endif
257 "index.html";
258 }
259 if (dir_prefix != NULL)
260 fname_out = concat_path_file(dir_prefix, fname_out);
261#ifdef BB_FEATURE_WGET_STATUSBAR
262 } else {
263 curfile = get_last_path_component(fname_out);
264#endif
265 }
266 if (do_continue && !fname_out)
267 error_msg_and_die("cannot specify continue (-c) without a filename (-O)");
268
269
270 /*
271 * Open the output file stream.
272 */
273 if (strcmp(fname_out, "-") == 0) {
274 output = stdout;
275 quiet_flag = TRUE;
276 } else {
277 output = xfopen(fname_out, (do_continue ? "a" : "w"));
278 }
279
280 /*
281 * Determine where to start transfer.
282 */
283 if (do_continue) {
284 if (fstat(fileno(output), &sbuf) < 0)
285 perror_msg_and_die("fstat()");
286 if (sbuf.st_size > 0)
287 beg_range = sbuf.st_size;
288 else
289 do_continue = 0;
290 }
291
292 if (proxy || !target.is_ftp) {
293 /*
294 * HTTP session
295 */
296 do {
297 if (! --try)
298 close_delete_and_die("too many redirections");
299
300 /*
301 * Open socket to http server
302 */
303 if (sfp) fclose(sfp);
304 sfp = open_socket(server.host, server.port);
305
306 /*
307 * Send HTTP request.
308 */
309 if (proxy) {
310 fprintf(sfp, "GET %stp://%s:%d/%s HTTP/1.1\r\n",
311 target.is_ftp ? "f" : "ht", target.host,
312 target.port, target.path);
313 } else {
314 fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
315 }
316
317 fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host);
318
319#ifdef BB_FEATURE_WGET_AUTHENTICATION
320 if (target.user) {
321 fprintf(sfp, "Authorization: Basic %s\r\n",
322 base64enc(target.user, buf, sizeof(buf)));
323 }
324 if (proxy && server.user) {
325 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
326 base64enc(server.user, buf, sizeof(buf)));
327 }
328#endif
329
330 if (do_continue)
331 fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range);
332 if(extra_headers_left < sizeof(extra_headers))
333 fputs(extra_headers,sfp);
334 fprintf(sfp,"Connection: close\r\n\r\n");
335
336 /*
337 * Retrieve HTTP response line and check for "200" status code.
338 */
339read_response: if (fgets(buf, sizeof(buf), sfp) == NULL)
340 close_delete_and_die("no response from server");
341
342 for (s = buf ; *s != '\0' && !isspace(*s) ; ++s)
343 ;
344 for ( ; isspace(*s) ; ++s)
345 ;
346 switch (status = atoi(s)) {
347 case 0:
348 case 100:
349 while (gethdr(buf, sizeof(buf), sfp, &n) != NULL);
350 goto read_response;
351 case 200:
352 if (do_continue && output != stdout)
353 output = freopen(fname_out, "w", output);
354 do_continue = 0;
355 break;
356 case 300: /* redirection */
357 case 301:
358 case 302:
359 case 303:
360 break;
361 case 206:
362 if (do_continue)
363 break;
364 /*FALLTHRU*/
365 default:
366 chomp(buf);
367 close_delete_and_die("server returned error %d: %s", atoi(s), buf);
368 }
369
370 /*
371 * Retrieve HTTP headers.
372 */
373 while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) {
374 if (strcasecmp(buf, "content-length") == 0) {
375 filesize = atol(s);
376 got_clen = 1;
377 continue;
378 }
379 if (strcasecmp(buf, "transfer-encoding") == 0) {
380 if (strcasecmp(s, "chunked") == 0) {
381 chunked = got_clen = 1;
382 } else {
383 close_delete_and_die("server wants to do %s transfer encoding", s);
384 }
385 }
386 if (strcasecmp(buf, "location") == 0) {
387 if (s[0] == '/')
388 target.path = xstrdup(s+1);
389 else {
390 parse_url(xstrdup(s), &target);
391 if (!proxy) {
392 server.host = target.host;
393 server.port = target.port;
394 }
395 }
396 }
397 }
398 } while(status >= 300);
399
400 dfp = sfp;
401 }
402 else
403 {
404 /*
405 * FTP session
406 */
407 if (! target.user)
408 target.user = xstrdup("anonymous:busybox@");
409
410 sfp = open_socket(server.host, server.port);
411 if (ftpcmd(NULL, NULL, sfp, buf) != 220)
412 close_delete_and_die("%s", buf+4);
413
414 /*
415 * Splitting username:password pair,
416 * trying to log in
417 */
418 s = strchr(target.user, ':');
419 if (s)
420 *(s++) = '\0';
421 switch(ftpcmd("USER ", target.user, sfp, buf)) {
422 case 230:
423 break;
424 case 331:
425 if (ftpcmd("PASS ", s, sfp, buf) == 230)
426 break;
427 /* FALLTHRU (failed login) */
428 default:
429 close_delete_and_die("ftp login: %s", buf+4);
430 }
431
432 ftpcmd("CDUP", NULL, sfp, buf);
433 ftpcmd("TYPE I", NULL, sfp, buf);
434
435 /*
436 * Querying file size
437 */
438 if (ftpcmd("SIZE /", target.path, sfp, buf) == 213) {
439 filesize = atol(buf+4);
440 got_clen = 1;
441 }
442
443 /*
444 * Entering passive mode
445 */
446 if (ftpcmd("PASV", NULL, sfp, buf) != 227)
447 close_delete_and_die("PASV: %s", buf+4);
448 s = strrchr(buf, ',');
449 *s = 0;
450 port = atoi(s+1);
451 s = strrchr(buf, ',');
452 port += atoi(s+1) * 256;
453 dfp = open_socket(server.host, port);
454
455 if (do_continue) {
456 sprintf(buf, "REST %ld", beg_range);
457 if (ftpcmd(buf, NULL, sfp, buf) != 350) {
458 if (output != stdout)
459 output = freopen(fname_out, "w", output);
460 do_continue = 0;
461 } else
462 filesize -= beg_range;
463 }
464
465 if (ftpcmd("RETR /", target.path, sfp, buf) > 150)
466 close_delete_and_die("RETR: %s", buf+4);
467
468 }
469
470
471 /*
472 * Retrieve file
473 */
474 if (chunked) {
475 fgets(buf, sizeof(buf), dfp);
476 filesize = strtol(buf, (char **) NULL, 16);
477 }
478#ifdef BB_FEATURE_WGET_STATUSBAR
479 if (quiet_flag==FALSE)
480 progressmeter(-1);
481#endif
482 do {
483 while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) {
484 safe_fwrite(buf, 1, n, output);
485#ifdef BB_FEATURE_WGET_STATUSBAR
486 statbytes+=n;
487#endif
488 if (got_clen)
489 filesize -= n;
490 }
491
492 if (chunked) {
493 safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
494 safe_fgets(buf, sizeof(buf), dfp);
495 filesize = strtol(buf, (char **) NULL, 16);
496 if (filesize==0) chunked = 0; /* all done! */
497 }
498
499 if (n == 0 && ferror(dfp))
500 perror_msg_and_die("network read error");
501 } while (chunked);
502#ifdef BB_FEATURE_WGET_STATUSBAR
503 if (quiet_flag==FALSE)
504 progressmeter(1);
505#endif
506 if (!proxy && target.is_ftp) {
507 fclose(dfp);
508 if (ftpcmd(NULL, NULL, sfp, buf) != 226)
509 error_msg_and_die("ftp error: %s", buf+4);
510 ftpcmd("QUIT", NULL, sfp, buf);
511 }
512 exit(EXIT_SUCCESS);
513}
514
515
516void parse_url(char *url, struct host_info *h)
517{
518 char *cp, *sp, *up;
519
520 if (strncmp(url, "http://", 7) == 0) {
521 h->port = 80;
522 h->host = url + 7;
523 h->is_ftp = 0;
524 } else if (strncmp(url, "ftp://", 6) == 0) {
525 h->port = 21;
526 h->host = url + 6;
527 h->is_ftp = 1;
528 } else
529 error_msg_and_die("not an http or ftp url: %s", url);
530
531 sp = strchr(h->host, '/');
532 if (sp != NULL) {
533 *sp++ = '\0';
534 h->path = sp;
535 } else
536 h->path = "";
537
538 up = strrchr(h->host, '@');
539 if (up != NULL) {
540 h->user = h->host;
541 *up++ = '\0';
542 h->host = up;
543 } else
544 h->user = NULL;
545
546 cp = strchr(h->host, ':');
547 if (cp != NULL) {
548 *cp++ = '\0';
549 h->port = atoi(cp);
550 }
551
552}
553
554
555FILE *open_socket(char *host, int port)
556{
557 struct sockaddr_in s_in;
558 struct hostent *hp;
559 int fd;
560 FILE *fp;
561
562 memset(&s_in, 0, sizeof(s_in));
563 s_in.sin_family = AF_INET;
564 hp = xgethostbyname(host);
565 memcpy(&s_in.sin_addr, hp->h_addr_list[0], hp->h_length);
566 s_in.sin_port = htons(port);
567
568 /*
569 * Get the server onto a stdio stream.
570 */
571 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
572 perror_msg_and_die("socket()");
573 if (connect(fd, (struct sockaddr *) &s_in, sizeof(s_in)) < 0)
574 perror_msg_and_die("connect(%s)", host);
575 if ((fp = fdopen(fd, "r+")) == NULL)
576 perror_msg_and_die("fdopen()");
577
578 return fp;
579}
580
581
582char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
583{
584 char *s, *hdrval;
585 int c;
586
587 *istrunc = 0;
588
589 /* retrieve header line */
590 if (fgets(buf, bufsiz, fp) == NULL)
591 return NULL;
592
593 /* see if we are at the end of the headers */
594 for (s = buf ; *s == '\r' ; ++s)
595 ;
596 if (s[0] == '\n')
597 return NULL;
598
599 /* convert the header name to lower case */
600 for (s = buf ; isalnum(*s) || *s == '-' ; ++s)
601 *s = tolower(*s);
602
603 /* verify we are at the end of the header name */
604 if (*s != ':')
605 error_msg_and_die("bad header line: %s", buf);
606
607 /* locate the start of the header value */
608 for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s)
609 ;
610 hdrval = s;
611
612 /* locate the end of header */
613 while (*s != '\0' && *s != '\r' && *s != '\n')
614 ++s;
615
616 /* end of header found */
617 if (*s != '\0') {
618 *s = '\0';
619 return hdrval;
620 }
621
622 /* Rats! The buffer isn't big enough to hold the entire header value. */
623 while (c = getc(fp), c != EOF && c != '\n')
624 ;
625 *istrunc = 1;
626 return hdrval;
627}
628
629static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf)
630{
631 char *p;
632
633 if (s1) {
634 if (!s2) s2="";
635 fprintf(fp, "%s%s\n", s1, s2);
636 fflush(fp);
637 }
638
639 do {
640 p = fgets(buf, 510, fp);
641 if (!p)
642 perror_msg_and_die("fgets()");
643 } while (! isdigit(buf[0]) || buf[3] != ' ');
644
645 return atoi(buf);
646}
647
648#ifdef BB_FEATURE_WGET_STATUSBAR
649/* Stuff below is from BSD rcp util.c, as added to openshh.
650 * Original copyright notice is retained at the end of this file.
651 *
652 */
653
654
655static int
656getttywidth(void)
657{
658 struct winsize winsize;
659
660 if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
661 return (winsize.ws_col ? winsize.ws_col : 80);
662 else
663 return (80);
664}
665
666static void
667updateprogressmeter(int ignore)
668{
669 int save_errno = errno;
670
671 progressmeter(0);
672 errno = save_errno;
673}
674
675static void
676alarmtimer(int wait)
677{
678 struct itimerval itv;
679
680 itv.it_value.tv_sec = wait;
681 itv.it_value.tv_usec = 0;
682 itv.it_interval = itv.it_value;
683 setitimer(ITIMER_REAL, &itv, NULL);
684}
685
686
687static void
688progressmeter(int flag)
689{
690 static const char prefixes[] = " KMGTP";
691 static struct timeval lastupdate;
692 static off_t lastsize, totalsize;
693 struct timeval now, td, wait;
694 off_t cursize, abbrevsize;
695 double elapsed;
696 int ratio, barlength, i, remaining;
697 char buf[256];
698
699 if (flag == -1) {
700 (void) gettimeofday(&start, (struct timezone *) 0);
701 lastupdate = start;
702 lastsize = 0;
703 totalsize = filesize; /* as filesize changes.. */
704 }
705
706 (void) gettimeofday(&now, (struct timezone *) 0);
707 cursize = statbytes;
708 if (totalsize != 0 && !chunked) {
709 ratio = 100.0 * cursize / totalsize;
710 ratio = MAX(ratio, 0);
711 ratio = MIN(ratio, 100);
712 } else
713 ratio = 100;
714
715 snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio);
716
717 barlength = getttywidth() - 51;
718 if (barlength > 0) {
719 i = barlength * ratio / 100;
720 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
721 "|%.*s%*s|", i,
722 "*****************************************************************************"
723 "*****************************************************************************",
724 barlength - i, "");
725 }
726 i = 0;
727 abbrevsize = cursize;
728 while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
729 i++;
730 abbrevsize >>= 10;
731 }
732 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5d %c%c ",
733 (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' :
734 'B');
735
736 timersub(&now, &lastupdate, &wait);
737 if (cursize > lastsize) {
738 lastupdate = now;
739 lastsize = cursize;
740 if (wait.tv_sec >= STALLTIME) {
741 start.tv_sec += wait.tv_sec;
742 start.tv_usec += wait.tv_usec;
743 }
744 wait.tv_sec = 0;
745 }
746 timersub(&now, &start, &td);
747 elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
748
749 if (wait.tv_sec >= STALLTIME) {
750 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
751 " - stalled -");
752 } else if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalsize || chunked) {
753 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
754 " --:-- ETA");
755 } else {
756 remaining = (int) (totalsize / (statbytes / elapsed) - elapsed);
757 i = remaining / 3600;
758 if (i)
759 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
760 "%2d:", i);
761 else
762 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
763 " ");
764 i = remaining % 3600;
765 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
766 "%02d:%02d ETA", i / 60, i % 60);
767 }
768 write(fileno(stderr), buf, strlen(buf));
769
770 if (flag == -1) {
771 struct sigaction sa;
772 sa.sa_handler = updateprogressmeter;
773 sigemptyset(&sa.sa_mask);
774 sa.sa_flags = SA_RESTART;
775 sigaction(SIGALRM, &sa, NULL);
776 alarmtimer(1);
777 } else if (flag == 1) {
778 alarmtimer(0);
779 statbytes = 0;
780 putc('\n', stderr);
781 }
782}
783#endif
784
785/* Original copyright notice which applies to the BB_FEATURE_WGET_STATUSBAR stuff,
786 * much of which was blatently stolen from openssh. */
787
788/*-
789 * Copyright (c) 1992, 1993
790 * The Regents of the University of California. All rights reserved.
791 *
792 * Redistribution and use in source and binary forms, with or without
793 * modification, are permitted provided that the following conditions
794 * are met:
795 * 1. Redistributions of source code must retain the above copyright
796 * notice, this list of conditions and the following disclaimer.
797 * 2. Redistributions in binary form must reproduce the above copyright
798 * notice, this list of conditions and the following disclaimer in the
799 * documentation and/or other materials provided with the distribution.
800 *
801 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
802 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
803 *
804 * 4. Neither the name of the University nor the names of its contributors
805 * may be used to endorse or promote products derived from this software
806 * without specific prior written permission.
807 *
808 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
809 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
810 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
811 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
812 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
813 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
814 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
815 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
816 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
817 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
818 * SUCH DAMAGE.
819 *
820 * $Id: wget.c,v 1.45 2001/07/19 22:28:01 andersen Exp $
821 */
822
823
824
825/*
826Local Variables:
827c-file-style: "linux"
828c-basic-offset: 4
829tab-width: 4
830End:
831*/
832
833
834
diff --git a/which.c b/which.c
deleted file mode 100644
index c460ffdd1..000000000
--- a/which.c
+++ /dev/null
@@ -1,80 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Which implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24/* getopt not needed */
25#include <string.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include "busybox.h"
29
30extern int which_main(int argc, char **argv)
31{
32 char *path_list, *path_n;
33 struct stat filestat;
34 int i, count=1, found, status = EXIT_SUCCESS;
35
36 if (argc <= 1 || **(argv + 1) == '-')
37 show_usage();
38 argc--;
39
40 path_list = getenv("PATH");
41 if (!path_list)
42 path_list = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin";
43
44 /* Replace colons with zeros in path_parsed and count them */
45 for(i=strlen(path_list); i > 0; i--)
46 if (path_list[i]==':') {
47 path_list[i]=0;
48 count++;
49 }
50
51 while(argc-- > 0) {
52 path_n = path_list;
53 argv++;
54 found = 0;
55 for (i = 0; i < count; i++) {
56 char *buf;
57 buf = concat_path_file(path_n, *argv);
58 if (stat (buf, &filestat) == 0
59 && filestat.st_mode & S_IXUSR)
60 {
61 puts(buf);
62 found = 1;
63 break;
64 }
65 free(buf);
66 path_n += (strlen(path_n) + 1);
67 }
68 if (!found)
69 status = EXIT_FAILURE;
70 }
71 return status;
72}
73
74/*
75Local Variables:
76c-file-style: "linux"
77c-basic-offset: 4
78tab-width: 4
79End:
80*/
diff --git a/whoami.c b/whoami.c
deleted file mode 100644
index c3b1140e6..000000000
--- a/whoami.c
+++ /dev/null
@@ -1,44 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini whoami implementation for busybox
4 *
5 * Copyright (C) 2000 Edward Betts <edward@debian.org>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23/* getopt not needed */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include "busybox.h"
29
30extern int whoami_main(int argc, char **argv)
31{
32 char user[9];
33 uid_t uid = geteuid();
34
35 if (argc > 1)
36 show_usage();
37
38 my_getpwuid(user, uid);
39 if (*user) {
40 puts(user);
41 return EXIT_SUCCESS;
42 }
43 error_msg_and_die("cannot find username for UID %u", (unsigned) uid);
44}
diff --git a/xargs.c b/xargs.c
deleted file mode 100644
index 48adae90a..000000000
--- a/xargs.c
+++ /dev/null
@@ -1,105 +0,0 @@
1/*
2 * Mini xargs implementation for busybox
3 *
4 * Copyright (C) 1999,2000,2001 by Lineo, inc.
5 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
6 * Remixed by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include "busybox.h"
28
29int xargs_main(int argc, char **argv)
30{
31 char *cmd_to_be_executed = NULL;
32 char *file_to_act_on = NULL;
33
34 /*
35 * No options are supported in this version of xargs; no getopt.
36 *
37 * Re: The missing -t flag: Most programs that produce output also print
38 * the filename, so xargs doesn't really need to do it again. Supporting
39 * the -t flag =greatly= bloats up the size of this app and the memory it
40 * uses because you have to buffer all the input file strings in memory. If
41 * you really want to see the filenames that xargs will act on, just run it
42 * once with no args and xargs will echo the filename. Simple.
43 */
44
45 /* Store the command to be executed (taken from the command line) */
46 if (argc == 1) {
47 /* default behavior is to echo all the filenames */
48 cmd_to_be_executed = xstrdup("/bin/echo ");
49 } else {
50 /* concatenate all the arguments passed to xargs together */
51 int i;
52 int len = 1; /* for the '\0' */
53 for (i = 1; i < argc; i++) {
54 len += strlen(argv[i]);
55 len += 1; /* for the space between the args */
56 cmd_to_be_executed = xrealloc(cmd_to_be_executed, len);
57 strcat(cmd_to_be_executed, argv[i]);
58 strcat(cmd_to_be_executed, " ");
59 }
60 }
61
62 /* Now, read in one line at a time from stdin, and store this
63 * line to be used later as an argument to the command */
64 while ((file_to_act_on = get_line_from_file(stdin)) !=NULL) {
65
66 FILE *cmd_output = NULL;
67 char *output_line = NULL;
68 char *execstr = NULL;
69
70 /* eat the newline off the filename. */
71 chomp(file_to_act_on);
72
73 /* eat blank lines */
74 if (strlen(file_to_act_on) == 0)
75 continue;
76
77 /* assemble the command and execute it */
78 execstr = xcalloc(strlen(cmd_to_be_executed) +
79 strlen(file_to_act_on) + 1, sizeof(char));
80 strcat(execstr, cmd_to_be_executed);
81 strcat(execstr, file_to_act_on);
82 cmd_output = popen(execstr, "r");
83 if (cmd_output == NULL)
84 perror_msg_and_die("popen");
85
86 /* harvest the output */
87 while ((output_line = get_line_from_file(cmd_output)) != NULL) {
88 fputs(output_line, stdout);
89 free(output_line);
90 }
91
92 /* clean up */
93 pclose(cmd_output);
94 free(execstr);
95 free(file_to_act_on);
96 }
97
98#ifdef BB_FEATURE_CLEAN_UP
99 free(cmd_to_be_executed);
100#endif
101
102 return 0;
103}
104
105/* vi: set sw=4 ts=4: */
diff --git a/yes.c b/yes.c
deleted file mode 100644
index 7d9596d0b..000000000
--- a/yes.c
+++ /dev/null
@@ -1,53 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini yes implementation for busybox
4 *
5 * Copyright (C) 2000 Edward Betts <edward@debian.org>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23/* getopt not needed */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include "busybox.h"
28
29extern int yes_main(int argc, char **argv)
30{
31 int i;
32
33 if (argc >= 2 && *argv[1] == '-')
34 show_usage();
35
36 if (argc == 1) {
37 while (1)
38 if (puts("y") == EOF) {
39 perror("yes");
40 return EXIT_FAILURE;
41 }
42 }
43
44 while (1)
45 for (i = 1; i < argc; i++)
46 if (fputs(argv[i], stdout) == EOF
47 || putchar(i == argc - 1 ? '\n' : ' ') == EOF) {
48 perror("yes");
49 return EXIT_FAILURE;
50 }
51
52 return EXIT_SUCCESS;
53}