Major build system updates...

-Erik
This commit is contained in:
Erik Andersen
2000-03-16 08:09:09 +00:00
parent a967e3c8f0
commit d75af99529
13 changed files with 2111 additions and 1891 deletions

View File

@ -1,4 +1,8 @@
0.43 0.43
* Busybox now includes a shell! It currently costs 7.5 k (plus an
additional 2.5 k if you compile in command line editing). Handles
job control, has the usual set of builtins, and does everything
except for handling programming statements (if, while, etc...)
* Busybox can now work perfectly when /proc is disabled, thereby * Busybox can now work perfectly when /proc is disabled, thereby
saving a bunch of memory (kernel /proc support is not thin). This saving a bunch of memory (kernel /proc support is not thin). This
is done by making use of some nice kernel patches I wrote up to is done by making use of some nice kernel patches I wrote up to
@ -11,6 +15,7 @@
with a ram disk. Contributed by Emanuele Caratti <wiz@iol.it> with a ram disk. Contributed by Emanuele Caratti <wiz@iol.it>
and then adjusted a bit by me. and then adjusted a bit by me.
* Added tr and dirname from John Lombardo <john@deltanet.com> * Added tr and dirname from John Lombardo <john@deltanet.com>
* Added echo and test (from me).
* tar wouldn't create directory entries that don't end in '/', * tar wouldn't create directory entries that don't end in '/',
now it does (thanks to Avery Pennarun <apenwarr@worldvisions.ca>) now it does (thanks to Avery Pennarun <apenwarr@worldvisions.ca>)
* Several fixes from Pavel Roskin <pavel_roskin@geocities.com>: * Several fixes from Pavel Roskin <pavel_roskin@geocities.com>:

View File

@ -34,282 +34,304 @@ int atexit(void (*__func) (void))
void *__libc_stack_end; void *__libc_stack_end;
#endif #endif
static const struct Applet applets[] = { static const struct Applet applets[] = {
#ifdef BB_BASENAME //usr/bin/basename #ifdef BB_BASENAME //usr/bin/basename
{"basename", basename_main}, {"basename", basename_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_BUSYBOX //bin #ifdef BB_BUSYBOX //bin
{"busybox", busybox_main}, {"busybox", busybox_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_BLOCK_DEVICE //sbin #ifdef BB_BLOCK_DEVICE //sbin
{"block_device", block_device_main}, {"block_device", block_device_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_CAT //bin #ifdef BB_CAT //bin
{"cat", cat_main}, {"cat", cat_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_CHMOD_CHOWN_CHGRP //bin #ifdef BB_CHMOD_CHOWN_CHGRP //bin
{"chmod", chmod_chown_chgrp_main}, {"chmod", chmod_chown_chgrp_main, _BB_DIR_BIN},
{"chown", chmod_chown_chgrp_main}, #endif
{"chgrp", chmod_chown_chgrp_main}, #ifdef BB_CHMOD_CHOWN_CHGRP //bin
{"chown", chmod_chown_chgrp_main, _BB_DIR_BIN},
#endif
#ifdef BB_CHMOD_CHOWN_CHGRP //bin
{"chgrp", chmod_chown_chgrp_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_CHROOT //sbin #ifdef BB_CHROOT //sbin
{"chroot", chroot_main}, {"chroot", chroot_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_CLEAR //usr/bin #ifdef BB_CLEAR //usr/bin
{"clear", clear_main}, {"clear", clear_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_CHVT //usr/bin #ifdef BB_CHVT //usr/bin
{"chvt", chvt_main}, {"chvt", chvt_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_CP_MV //bin #ifdef BB_CP_MV //bin
{"cp", cp_mv_main}, {"cp", cp_mv_main, _BB_DIR_BIN},
{"mv", cp_mv_main}, #endif
#ifdef BB_CP_MV //bin
{"mv", cp_mv_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DATE //bin #ifdef BB_DATE //bin
{"date", date_main}, {"date", date_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DD //bin #ifdef BB_DD //bin
{"dd", dd_main}, {"dd", dd_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DF //bin #ifdef BB_DF //bin
{"df", df_main}, {"df", df_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DIRNAME //usr/bin #ifdef BB_DIRNAME //usr/bin
{"dirname", dirname_main}, {"dirname", dirname_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_DMESG //bin #ifdef BB_DMESG //bin
{"dmesg", dmesg_main}, {"dmesg", dmesg_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DU //bin #ifdef BB_DU //bin
{"du", du_main}, {"du", du_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DUTMP //usr/sbin #ifdef BB_DUTMP //usr/sbin
{"dutmp", dutmp_main}, {"dutmp", dutmp_main, _BB_DIR_USR_SBIN},
#endif
#ifdef BB_ECHO //bin
{"echo", echo_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_FBSET //usr/sbin #ifdef BB_FBSET //usr/sbin
{"fbset", fbset_main}, {"fbset", fbset_main, _BB_DIR_USR_SBIN},
#endif #endif
#ifdef BB_FDFLUSH //bin #ifdef BB_FDFLUSH //bin
{"fdflush", fdflush_main}, {"fdflush", fdflush_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_FIND //usr/bin #ifdef BB_FIND //usr/bin
{"find", find_main}, {"find", find_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_FREE //usr/bin #ifdef BB_FREE //usr/bin
{"free", free_main}, {"free", free_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_FREERAMDISK //sbin #ifdef BB_FREERAMDISK //sbin
{"freeramdisk", freeramdisk_main}, {"freeramdisk", freeramdisk_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_DEALLOCVT //usr/bin #ifdef BB_DEALLOCVT //usr/bin
{"deallocvt", deallocvt_main}, {"deallocvt", deallocvt_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_FSCK_MINIX //sbin #ifdef BB_FSCK_MINIX //sbin
{"fsck.minix", fsck_minix_main}, {"fsck.minix", fsck_minix_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_MKFS_MINIX //sbin #ifdef BB_MKFS_MINIX //sbin
{"mkfs.minix", mkfs_minix_main}, {"mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_GREP //bin #ifdef BB_GREP //bin
{"grep", grep_main}, {"grep", grep_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_HALT //sbin #ifdef BB_HALT //sbin
{"halt", halt_main}, {"halt", halt_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_HEAD //bin #ifdef BB_HEAD //bin
{"head", head_main}, {"head", head_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_HOSTID //usr/bin #ifdef BB_HOSTID //usr/bin
{"hostid", hostid_main}, {"hostid", hostid_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_HOSTNAME //bin #ifdef BB_HOSTNAME //bin
{"hostname", hostname_main}, {"hostname", hostname_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_INIT //sbin #ifdef BB_INIT //sbin
{"init", init_main}, {"init", init_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_INSMOD //sbin #ifdef BB_INSMOD //sbin
{"insmod", insmod_main}, {"insmod", insmod_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_FEATURE_LINUXRC // #ifdef BB_FEATURE_LINUXRC //
{"linuxrc", init_main}, {"linuxrc", init_main, _BB_DIR_ROOT},
#endif #endif
#ifdef BB_KILL //bin #ifdef BB_KILL //bin
{"kill", kill_main}, {"kill", kill_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_KILLALL //usr/bin #ifdef BB_KILLALL //usr/bin
{"killall", kill_main}, {"killall", kill_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LENGTH //usr/bin #ifdef BB_LENGTH //usr/bin
{"length", length_main}, {"length", length_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LN //bin #ifdef BB_LN //bin
{"ln", ln_main}, {"ln", ln_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_LOADACM //usr/bin #ifdef BB_LOADACM //usr/bin
{"loadacm", loadacm_main}, {"loadacm", loadacm_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LOADFONT //usr/bin #ifdef BB_LOADFONT //usr/bin
{"loadfont", loadfont_main}, {"loadfont", loadfont_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LOADKMAP //sbin #ifdef BB_LOADKMAP //sbin
{"loadkmap", loadkmap_main}, {"loadkmap", loadkmap_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_LS //bin #ifdef BB_LS //bin
{"ls", ls_main}, {"ls", ls_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_LSMOD //sbin #ifdef BB_LSMOD //sbin
{"lsmod", lsmod_main}, {"lsmod", lsmod_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_MAKEDEVS //sbin #ifdef BB_MAKEDEVS //sbin
{"makedevs", makedevs_main}, {"makedevs", makedevs_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_MATH //usr/bin #ifdef BB_MATH //usr/bin
{"math", math_main}, {"math", math_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_MKDIR //bin #ifdef BB_MKDIR //bin
{"mkdir", mkdir_main}, {"mkdir", mkdir_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_MKFIFO //usr/bin #ifdef BB_MKFIFO //usr/bin
{"mkfifo", mkfifo_main}, {"mkfifo", mkfifo_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_MKNOD //bin #ifdef BB_MKNOD //bin
{"mknod", mknod_main}, {"mknod", mknod_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_MKSWAP //sbin #ifdef BB_MKSWAP //sbin
{"mkswap", mkswap_main}, {"mkswap", mkswap_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_MNC //usr/bin #ifdef BB_MNC //usr/bin
{"mnc", mnc_main}, {"mnc", mnc_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_MORE //bin #ifdef BB_MORE //bin
{"more", more_main}, {"more", more_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_MOUNT //bin #ifdef BB_MOUNT //bin
{"mount", mount_main}, {"mount", mount_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_MT //bin #ifdef BB_MT //bin
{"mt", mt_main}, {"mt", mt_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_NSLOOKUP //usr/bin #ifdef BB_NSLOOKUP //usr/bin
{"nslookup", nslookup_main}, {"nslookup", nslookup_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_PING //bin #ifdef BB_PING //bin
{"ping", ping_main}, {"ping", ping_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_POWEROFF //sbin #ifdef BB_POWEROFF //sbin
{"poweroff", poweroff_main}, {"poweroff", poweroff_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_PRINTF //usr/bin #ifdef BB_PRINTF //usr/bin
{"printf", printf_main}, {"printf", printf_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_PS //bin #ifdef BB_PS //bin
{"ps", ps_main}, {"ps", ps_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_PWD //bin #ifdef BB_PWD //bin
{"pwd", pwd_main}, {"pwd", pwd_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_REBOOT //sbin #ifdef BB_REBOOT //sbin
{"reboot", reboot_main}, {"reboot", reboot_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_RM //bin #ifdef BB_RM //bin
{"rm", rm_main}, {"rm", rm_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_RMDIR //bin #ifdef BB_RMDIR //bin
{"rmdir", rmdir_main}, {"rmdir", rmdir_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_RMMOD //sbin #ifdef BB_RMMOD //sbin
{"rmmod", rmmod_main}, {"rmmod", rmmod_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_SED //bin #ifdef BB_SED //bin
{"sed", sed_main}, {"sed", sed_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SH //bin #ifdef BB_SH //bin
{"sh", shell_main}, {"sh", shell_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SFDISK //sbin #ifdef BB_SFDISK //sbin
{"fdisk", sfdisk_main}, {"fdisk", sfdisk_main, _BB_DIR_SBIN},
{"sfdisk", sfdisk_main}, #ifdef BB_SFDISK //sbin
#endif
{"sfdisk", sfdisk_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_SLEEP //bin #ifdef BB_SLEEP //bin
{"sleep", sleep_main}, {"sleep", sleep_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SORT //bin #ifdef BB_SORT //bin
{"sort", sort_main}, {"sort", sort_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SYNC //bin #ifdef BB_SYNC //bin
{"sync", sync_main}, {"sync", sync_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SYSLOGD //sbin #ifdef BB_SYSLOGD //sbin
{"syslogd", syslogd_main}, {"syslogd", syslogd_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_LOGGER //usr/bin #ifdef BB_LOGGER //usr/bin
{"logger", logger_main}, {"logger", logger_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LOGNAME //usr/bin #ifdef BB_LOGNAME //usr/bin
{"logname", logname_main}, {"logname", logname_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_SWAPONOFF //sbin #ifdef BB_SWAPONOFF //sbin
{"swapon", swap_on_off_main}, {"swapon", swap_on_off_main, _BB_DIR_SBIN},
{"swapoff", swap_on_off_main}, #endif
#ifdef BB_SWAPONOFF //sbin
{"swapoff", swap_on_off_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_TAIL //usr/bin #ifdef BB_TAIL //usr/bin
{"tail", tail_main}, {"tail", tail_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_TAR //bin #ifdef BB_TAR //bin
{"tar", tar_main}, {"tar", tar_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_TELNET //usr/bin #ifdef BB_TELNET //usr/bin
{"telnet", telnet_main}, {"telnet", telnet_main, _BB_DIR_USR_BIN},
#endif
#ifdef BB_TEST //usr/bin
{"[", test_main, _BB_DIR_USR_BIN},
#endif
#ifdef BB_TEST //usr/bin
{"test", test_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_TEE //bin #ifdef BB_TEE //bin
{"tee", tee_main}, {"tee", tee_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_TOUCH //usr/bin #ifdef BB_TOUCH //usr/bin
{"touch", touch_main}, {"touch", touch_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_TR //usr/bin #ifdef BB_TR //usr/bin
{"tr", tr_main}, {"tr", tr_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_TRUE_FALSE //bin #ifdef BB_TRUE_FALSE //bin
{"true", true_main}, {"true", true_main, _BB_DIR_BIN},
{"false", false_main}, #endif
#ifdef BB_TRUE_FALSE //bin
{"false", false_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_TTY //usr/bin #ifdef BB_TTY //usr/bin
{"tty", tty_main}, {"tty", tty_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_UMOUNT //bin #ifdef BB_UMOUNT //bin
{"umount", umount_main}, {"umount", umount_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_UNAME //bin #ifdef BB_UNAME //bin
{"uname", uname_main}, {"uname", uname_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_UPTIME //usr/bin #ifdef BB_UPTIME //usr/bin
{"uptime", uptime_main}, {"uptime", uptime_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_UNIQ //bin #ifdef BB_UNIQ //bin
{"uniq", uniq_main}, {"uniq", uniq_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_UPDATE //sbin #ifdef BB_UPDATE //sbin
{"update", update_main}, {"update", update_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_WC //usr/bin #ifdef BB_WC //usr/bin
{"wc", wc_main}, {"wc", wc_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_WHOAMI //usr/bin #ifdef BB_WHOAMI //usr/bin
{"whoami", whoami_main}, {"whoami", whoami_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_YES //usr/bin #ifdef BB_YES //usr/bin
{"yes", yes_main}, {"yes", yes_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_GUNZIP //bin #ifdef BB_GUNZIP //bin
{"zcat", gunzip_main}, {"zcat", gunzip_main, _BB_DIR_BIN},
{"gunzip", gunzip_main}, #endif
#ifdef BB_GUNZIP //bin
{"gunzip", gunzip_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_GZIP //bin #ifdef BB_GZIP //bin
{"gzip", gzip_main}, {"gzip", gzip_main, _BB_DIR_BIN},
#endif #endif
{0} {0}
}; };
@ -318,11 +340,11 @@ static const struct Applet applets[] = {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char *s = argv[0]; char *s;
char *name = argv[0]; char *name;
const struct Applet *a = applets; const struct Applet *a = applets;
while (*s != '\0') { for (s = name = argv[0]; *s != '\0';) {
if (*s++ == '/') if (*s++ == '/')
name = s; name = s;
} }

View File

@ -4,12 +4,16 @@
DF="busybox.def.h" DF="busybox.def.h"
MF="busybox.c" MF="busybox.c"
LIST="$(sed -n '/^#define/{s/^#define //p;}' $DF)" LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)"
for def in ${LIST}; do for def in ${LIST}; do
i=`sed -n 's/^#ifdef \<'$def'\>.*\/\/\(.*$\)/\/\1\//gp' $MF` i=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*\(_BB_DIR_[A-Z_]*\).*$/\2\/\1/gp; }' $MF`
j=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*/\1/gp; }' $MF` for j in $i; do
for k in $j; do if [ -z $j ] ; then
echo $i$k continue;
done fi;
echo $j | sed -e 's/_BB_DIR_ROOT//g;s/_BB_DIR_BIN/\/bin/g;' \
-e 's/_BB_DIR_SBIN/\/sbin/g;s/_BB_DIR_USR_BIN/\/usr\/bin/g;' \
-e 's/_BB_DIR_USR_SBIN/\/usr\/sbin/g;'
done;
done done

View File

@ -1,4 +1,3 @@
#!/bin/sh #!/bin/sh
ls -1 `sed -n '/^#define/{s/.*BB_// ; s/$/.c/p; }' busybox.def.h | \ sed -n -e 's/^#define.*BB_FEATURE.*$//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;' \
tr [:upper:] [:lower:]` 2> /dev/null | sed -e 's/\.c$/\.o/g' -e '/^#define/{s/.*bb_//;s/$/.o/p;}' busybox.def.h

222
busybox.c
View File

@ -34,282 +34,304 @@ int atexit(void (*__func) (void))
void *__libc_stack_end; void *__libc_stack_end;
#endif #endif
static const struct Applet applets[] = { static const struct Applet applets[] = {
#ifdef BB_BASENAME //usr/bin/basename #ifdef BB_BASENAME //usr/bin/basename
{"basename", basename_main}, {"basename", basename_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_BUSYBOX //bin #ifdef BB_BUSYBOX //bin
{"busybox", busybox_main}, {"busybox", busybox_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_BLOCK_DEVICE //sbin #ifdef BB_BLOCK_DEVICE //sbin
{"block_device", block_device_main}, {"block_device", block_device_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_CAT //bin #ifdef BB_CAT //bin
{"cat", cat_main}, {"cat", cat_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_CHMOD_CHOWN_CHGRP //bin #ifdef BB_CHMOD_CHOWN_CHGRP //bin
{"chmod", chmod_chown_chgrp_main}, {"chmod", chmod_chown_chgrp_main, _BB_DIR_BIN},
{"chown", chmod_chown_chgrp_main}, #endif
{"chgrp", chmod_chown_chgrp_main}, #ifdef BB_CHMOD_CHOWN_CHGRP //bin
{"chown", chmod_chown_chgrp_main, _BB_DIR_BIN},
#endif
#ifdef BB_CHMOD_CHOWN_CHGRP //bin
{"chgrp", chmod_chown_chgrp_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_CHROOT //sbin #ifdef BB_CHROOT //sbin
{"chroot", chroot_main}, {"chroot", chroot_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_CLEAR //usr/bin #ifdef BB_CLEAR //usr/bin
{"clear", clear_main}, {"clear", clear_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_CHVT //usr/bin #ifdef BB_CHVT //usr/bin
{"chvt", chvt_main}, {"chvt", chvt_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_CP_MV //bin #ifdef BB_CP_MV //bin
{"cp", cp_mv_main}, {"cp", cp_mv_main, _BB_DIR_BIN},
{"mv", cp_mv_main}, #endif
#ifdef BB_CP_MV //bin
{"mv", cp_mv_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DATE //bin #ifdef BB_DATE //bin
{"date", date_main}, {"date", date_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DD //bin #ifdef BB_DD //bin
{"dd", dd_main}, {"dd", dd_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DF //bin #ifdef BB_DF //bin
{"df", df_main}, {"df", df_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DIRNAME //usr/bin #ifdef BB_DIRNAME //usr/bin
{"dirname", dirname_main}, {"dirname", dirname_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_DMESG //bin #ifdef BB_DMESG //bin
{"dmesg", dmesg_main}, {"dmesg", dmesg_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DU //bin #ifdef BB_DU //bin
{"du", du_main}, {"du", du_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_DUTMP //usr/sbin #ifdef BB_DUTMP //usr/sbin
{"dutmp", dutmp_main}, {"dutmp", dutmp_main, _BB_DIR_USR_SBIN},
#endif
#ifdef BB_ECHO //bin
{"echo", echo_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_FBSET //usr/sbin #ifdef BB_FBSET //usr/sbin
{"fbset", fbset_main}, {"fbset", fbset_main, _BB_DIR_USR_SBIN},
#endif #endif
#ifdef BB_FDFLUSH //bin #ifdef BB_FDFLUSH //bin
{"fdflush", fdflush_main}, {"fdflush", fdflush_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_FIND //usr/bin #ifdef BB_FIND //usr/bin
{"find", find_main}, {"find", find_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_FREE //usr/bin #ifdef BB_FREE //usr/bin
{"free", free_main}, {"free", free_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_FREERAMDISK //sbin #ifdef BB_FREERAMDISK //sbin
{"freeramdisk", freeramdisk_main}, {"freeramdisk", freeramdisk_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_DEALLOCVT //usr/bin #ifdef BB_DEALLOCVT //usr/bin
{"deallocvt", deallocvt_main}, {"deallocvt", deallocvt_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_FSCK_MINIX //sbin #ifdef BB_FSCK_MINIX //sbin
{"fsck.minix", fsck_minix_main}, {"fsck.minix", fsck_minix_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_MKFS_MINIX //sbin #ifdef BB_MKFS_MINIX //sbin
{"mkfs.minix", mkfs_minix_main}, {"mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_GREP //bin #ifdef BB_GREP //bin
{"grep", grep_main}, {"grep", grep_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_HALT //sbin #ifdef BB_HALT //sbin
{"halt", halt_main}, {"halt", halt_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_HEAD //bin #ifdef BB_HEAD //bin
{"head", head_main}, {"head", head_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_HOSTID //usr/bin #ifdef BB_HOSTID //usr/bin
{"hostid", hostid_main}, {"hostid", hostid_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_HOSTNAME //bin #ifdef BB_HOSTNAME //bin
{"hostname", hostname_main}, {"hostname", hostname_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_INIT //sbin #ifdef BB_INIT //sbin
{"init", init_main}, {"init", init_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_INSMOD //sbin #ifdef BB_INSMOD //sbin
{"insmod", insmod_main}, {"insmod", insmod_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_FEATURE_LINUXRC // #ifdef BB_FEATURE_LINUXRC //
{"linuxrc", init_main}, {"linuxrc", init_main, _BB_DIR_ROOT},
#endif #endif
#ifdef BB_KILL //bin #ifdef BB_KILL //bin
{"kill", kill_main}, {"kill", kill_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_KILLALL //usr/bin #ifdef BB_KILLALL //usr/bin
{"killall", kill_main}, {"killall", kill_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LENGTH //usr/bin #ifdef BB_LENGTH //usr/bin
{"length", length_main}, {"length", length_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LN //bin #ifdef BB_LN //bin
{"ln", ln_main}, {"ln", ln_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_LOADACM //usr/bin #ifdef BB_LOADACM //usr/bin
{"loadacm", loadacm_main}, {"loadacm", loadacm_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LOADFONT //usr/bin #ifdef BB_LOADFONT //usr/bin
{"loadfont", loadfont_main}, {"loadfont", loadfont_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LOADKMAP //sbin #ifdef BB_LOADKMAP //sbin
{"loadkmap", loadkmap_main}, {"loadkmap", loadkmap_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_LS //bin #ifdef BB_LS //bin
{"ls", ls_main}, {"ls", ls_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_LSMOD //sbin #ifdef BB_LSMOD //sbin
{"lsmod", lsmod_main}, {"lsmod", lsmod_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_MAKEDEVS //sbin #ifdef BB_MAKEDEVS //sbin
{"makedevs", makedevs_main}, {"makedevs", makedevs_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_MATH //usr/bin #ifdef BB_MATH //usr/bin
{"math", math_main}, {"math", math_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_MKDIR //bin #ifdef BB_MKDIR //bin
{"mkdir", mkdir_main}, {"mkdir", mkdir_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_MKFIFO //usr/bin #ifdef BB_MKFIFO //usr/bin
{"mkfifo", mkfifo_main}, {"mkfifo", mkfifo_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_MKNOD //bin #ifdef BB_MKNOD //bin
{"mknod", mknod_main}, {"mknod", mknod_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_MKSWAP //sbin #ifdef BB_MKSWAP //sbin
{"mkswap", mkswap_main}, {"mkswap", mkswap_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_MNC //usr/bin #ifdef BB_MNC //usr/bin
{"mnc", mnc_main}, {"mnc", mnc_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_MORE //bin #ifdef BB_MORE //bin
{"more", more_main}, {"more", more_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_MOUNT //bin #ifdef BB_MOUNT //bin
{"mount", mount_main}, {"mount", mount_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_MT //bin #ifdef BB_MT //bin
{"mt", mt_main}, {"mt", mt_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_NSLOOKUP //usr/bin #ifdef BB_NSLOOKUP //usr/bin
{"nslookup", nslookup_main}, {"nslookup", nslookup_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_PING //bin #ifdef BB_PING //bin
{"ping", ping_main}, {"ping", ping_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_POWEROFF //sbin #ifdef BB_POWEROFF //sbin
{"poweroff", poweroff_main}, {"poweroff", poweroff_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_PRINTF //usr/bin #ifdef BB_PRINTF //usr/bin
{"printf", printf_main}, {"printf", printf_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_PS //bin #ifdef BB_PS //bin
{"ps", ps_main}, {"ps", ps_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_PWD //bin #ifdef BB_PWD //bin
{"pwd", pwd_main}, {"pwd", pwd_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_REBOOT //sbin #ifdef BB_REBOOT //sbin
{"reboot", reboot_main}, {"reboot", reboot_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_RM //bin #ifdef BB_RM //bin
{"rm", rm_main}, {"rm", rm_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_RMDIR //bin #ifdef BB_RMDIR //bin
{"rmdir", rmdir_main}, {"rmdir", rmdir_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_RMMOD //sbin #ifdef BB_RMMOD //sbin
{"rmmod", rmmod_main}, {"rmmod", rmmod_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_SED //bin #ifdef BB_SED //bin
{"sed", sed_main}, {"sed", sed_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SH //bin #ifdef BB_SH //bin
{"sh", shell_main}, {"sh", shell_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SFDISK //sbin #ifdef BB_SFDISK //sbin
{"fdisk", sfdisk_main}, {"fdisk", sfdisk_main, _BB_DIR_SBIN},
{"sfdisk", sfdisk_main}, #ifdef BB_SFDISK //sbin
#endif
{"sfdisk", sfdisk_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_SLEEP //bin #ifdef BB_SLEEP //bin
{"sleep", sleep_main}, {"sleep", sleep_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SORT //bin #ifdef BB_SORT //bin
{"sort", sort_main}, {"sort", sort_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SYNC //bin #ifdef BB_SYNC //bin
{"sync", sync_main}, {"sync", sync_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_SYSLOGD //sbin #ifdef BB_SYSLOGD //sbin
{"syslogd", syslogd_main}, {"syslogd", syslogd_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_LOGGER //usr/bin #ifdef BB_LOGGER //usr/bin
{"logger", logger_main}, {"logger", logger_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_LOGNAME //usr/bin #ifdef BB_LOGNAME //usr/bin
{"logname", logname_main}, {"logname", logname_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_SWAPONOFF //sbin #ifdef BB_SWAPONOFF //sbin
{"swapon", swap_on_off_main}, {"swapon", swap_on_off_main, _BB_DIR_SBIN},
{"swapoff", swap_on_off_main}, #endif
#ifdef BB_SWAPONOFF //sbin
{"swapoff", swap_on_off_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_TAIL //usr/bin #ifdef BB_TAIL //usr/bin
{"tail", tail_main}, {"tail", tail_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_TAR //bin #ifdef BB_TAR //bin
{"tar", tar_main}, {"tar", tar_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_TELNET //usr/bin #ifdef BB_TELNET //usr/bin
{"telnet", telnet_main}, {"telnet", telnet_main, _BB_DIR_USR_BIN},
#endif
#ifdef BB_TEST //usr/bin
{"[", test_main, _BB_DIR_USR_BIN},
#endif
#ifdef BB_TEST //usr/bin
{"test", test_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_TEE //bin #ifdef BB_TEE //bin
{"tee", tee_main}, {"tee", tee_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_TOUCH //usr/bin #ifdef BB_TOUCH //usr/bin
{"touch", touch_main}, {"touch", touch_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_TR //usr/bin #ifdef BB_TR //usr/bin
{"tr", tr_main}, {"tr", tr_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_TRUE_FALSE //bin #ifdef BB_TRUE_FALSE //bin
{"true", true_main}, {"true", true_main, _BB_DIR_BIN},
{"false", false_main}, #endif
#ifdef BB_TRUE_FALSE //bin
{"false", false_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_TTY //usr/bin #ifdef BB_TTY //usr/bin
{"tty", tty_main}, {"tty", tty_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_UMOUNT //bin #ifdef BB_UMOUNT //bin
{"umount", umount_main}, {"umount", umount_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_UNAME //bin #ifdef BB_UNAME //bin
{"uname", uname_main}, {"uname", uname_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_UPTIME //usr/bin #ifdef BB_UPTIME //usr/bin
{"uptime", uptime_main}, {"uptime", uptime_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_UNIQ //bin #ifdef BB_UNIQ //bin
{"uniq", uniq_main}, {"uniq", uniq_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_UPDATE //sbin #ifdef BB_UPDATE //sbin
{"update", update_main}, {"update", update_main, _BB_DIR_SBIN},
#endif #endif
#ifdef BB_WC //usr/bin #ifdef BB_WC //usr/bin
{"wc", wc_main}, {"wc", wc_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_WHOAMI //usr/bin #ifdef BB_WHOAMI //usr/bin
{"whoami", whoami_main}, {"whoami", whoami_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_YES //usr/bin #ifdef BB_YES //usr/bin
{"yes", yes_main}, {"yes", yes_main, _BB_DIR_USR_BIN},
#endif #endif
#ifdef BB_GUNZIP //bin #ifdef BB_GUNZIP //bin
{"zcat", gunzip_main}, {"zcat", gunzip_main, _BB_DIR_BIN},
{"gunzip", gunzip_main}, #endif
#ifdef BB_GUNZIP //bin
{"gunzip", gunzip_main, _BB_DIR_BIN},
#endif #endif
#ifdef BB_GZIP //bin #ifdef BB_GZIP //bin
{"gzip", gzip_main}, {"gzip", gzip_main, _BB_DIR_BIN},
#endif #endif
{0} {0}
}; };
@ -318,11 +340,11 @@ static const struct Applet applets[] = {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char *s = argv[0]; char *s;
char *name = argv[0]; char *name;
const struct Applet *a = applets; const struct Applet *a = applets;
while (*s != '\0') { for (s = name = argv[0]; *s != '\0';) {
if (*s++ == '/') if (*s++ == '/')
name = s; name = s;
} }

View File

@ -22,13 +22,14 @@
#define BB_DMESG #define BB_DMESG
//#define BB_DUTMP //#define BB_DUTMP
#define BB_DU #define BB_DU
#define BB_FBSET #define BB_ECHO
//#define BB_FBSET
//#define BB_FDFLUSH //#define BB_FDFLUSH
#define BB_FIND #define BB_FIND
#define BB_FREE #define BB_FREE
#define BB_FREERAMDISK //#define BB_FREERAMDISK
#define BB_FSCK_MINIX //#define BB_FSCK_MINIX
#define BB_GREP //#define BB_GREP
#define BB_GUNZIP #define BB_GUNZIP
#define BB_GZIP #define BB_GZIP
//#define BB_HALT //#define BB_HALT
@ -36,12 +37,9 @@
//#define BB_HOSTID //#define BB_HOSTID
#define BB_HOSTNAME #define BB_HOSTNAME
#define BB_INIT #define BB_INIT
// Don't turn BB_INSMOD on. It doesn't work. // Don't bother turning BB_INSMOD on. It doesn't work.
//#define BB_INSMOD //#define BB_INSMOD
#define BB_KILL #define BB_KILL
#ifdef BB_KILL
#define BB_KILLALL
#endif
#define BB_KLOGD #define BB_KLOGD
//#define BB_LENGTH //#define BB_LENGTH
#define BB_LN #define BB_LN
@ -53,7 +51,7 @@
#define BB_LS #define BB_LS
//#define BB_LSMOD //#define BB_LSMOD
//#define BB_MAKEDEVS //#define BB_MAKEDEVS
#define BB_MKFS_MINIX //#define BB_MKFS_MINIX
//#define BB_MATH //#define BB_MATH
#define BB_MKDIR #define BB_MKDIR
//#define BB_MKFIFO //#define BB_MKFIFO
@ -62,7 +60,7 @@
//#define BB_MNC //#define BB_MNC
#define BB_MORE #define BB_MORE
#define BB_MOUNT #define BB_MOUNT
#define BB_NFSMOUNT //#define BB_NFSMOUNT
//#define BB_MT //#define BB_MT
#define BB_NSLOOKUP #define BB_NSLOOKUP
#define BB_PING #define BB_PING
@ -71,7 +69,6 @@
#define BB_PS #define BB_PS
#define BB_PWD #define BB_PWD
#define BB_REBOOT #define BB_REBOOT
#define BB_REGEXP
#define BB_RM #define BB_RM
#define BB_RMDIR #define BB_RMDIR
//#define BB_RMMOD //#define BB_RMMOD
@ -86,6 +83,7 @@
#define BB_TAIL #define BB_TAIL
#define BB_TAR #define BB_TAR
#define BB_TEE #define BB_TEE
#define BB_TEST
// Don't turn BB_TELNET on. It doesn't work. // Don't turn BB_TELNET on. It doesn't work.
#define BB_TELNET #define BB_TELNET
#define BB_TOUCH #define BB_TOUCH
@ -104,7 +102,7 @@
// //
// //
// //
// // ---------------------------------------------------------
// This is where feature definitions go. Generally speaking, // This is where feature definitions go. Generally speaking,
// turning this stuff off makes things a bit smaller (and less // turning this stuff off makes things a bit smaller (and less
// pretty/useful). // pretty/useful).
@ -117,10 +115,10 @@
// You can't use this and USE_PROCFS at the same time... // You can't use this and USE_PROCFS at the same time...
//#define BB_FEATURE_USE_DEVPS_PATCH //#define BB_FEATURE_USE_DEVPS_PATCH
// //
//
// enable features that use the /proc filesystem (apps that // enable features that use the /proc filesystem (apps that
// break without this will tell you on compile)... // break without this will tell you on compile)...
// You can't use this and DEVPS_N_DEVMTAB at the same time... // You can't use this and BB_FEATURE_USE_DEVPS_PATCH
// at the same time...
#define BB_FEATURE_USE_PROCFS #define BB_FEATURE_USE_PROCFS
// //
// Use termios to manipulate the screen ('more' is prettier with this on) // Use termios to manipulate the screen ('more' is prettier with this on)
@ -140,14 +138,13 @@
// //
// Change ping implementation -- simplified, featureless, but really small. // Change ping implementation -- simplified, featureless, but really small.
//#define BB_SIMPLE_PING //#define BB_SIMPLE_PING
//// //
// Make init use a simplified /etc/inittab file (recommended). // Make init use a simplified /etc/inittab file (recommended).
#define BB_FEATURE_USE_INITTAB #define BB_FEATURE_USE_INITTAB
// //
//Enable init being called as /linuxrc //Enable init being called as /linuxrc
//#define BB_FEATURE_LINUXRC //#define BB_FEATURE_LINUXRC
// //
//
//Simple tail implementation (2k vs 6k for the full one). Still //Simple tail implementation (2k vs 6k for the full one). Still
//provides 'tail -f' support -- but for only one file at a time. //provides 'tail -f' support -- but for only one file at a time.
#define BB_FEATURE_SIMPLE_TAIL #define BB_FEATURE_SIMPLE_TAIL
@ -156,9 +153,7 @@
#define BB_FEATURE_MOUNT_LOOP #define BB_FEATURE_MOUNT_LOOP
// //
// Enable support for a real /etc/mtab file instead of /proc/mounts // Enable support for a real /etc/mtab file instead of /proc/mounts
#ifdef BB_MOUNT //#define BB_FEATURE_MOUNT_MTAB_SUPPORT
//#define BB_MTAB
#endif
// //
// //
// Enable support for remounting filesystems // Enable support for remounting filesystems
@ -173,10 +168,41 @@
// Allow init to permenently chroot, and umount the old root fs // Allow init to permenently chroot, and umount the old root fs
// just like an initrd does. Requires a kernel patch by Werner Almesberger. // just like an initrd does. Requires a kernel patch by Werner Almesberger.
// ftp://icaftp.epfl.ch/pub/people/almesber/misc/umount-root-*.tar.gz // ftp://icaftp.epfl.ch/pub/people/almesber/misc/umount-root-*.tar.gz
#ifdef BB_MOUNT
//#define BB_FEATURE_INIT_CHROOT //#define BB_FEATURE_INIT_CHROOT
#endif
// //
//Make sure nothing is printed to the console on boot //Make sure nothing is printed to the console on boot
#define BB_FEATURE_EXTRA_QUIET #define BB_FEATURE_EXTRA_QUIET
//
// Enable full regular expressions. This adds about
// 4k. When this is off, things that would normally
// use regualr expressions (like grep) will just use
// normal strings.
#define BB_FEATURE_FULL_REGULAR_EXPRESSIONS
//
//
// Enable command line editing in the shell
#define BB_FEATURE_SH_COMMAND_EDITING
//
//
// End of Features List
//
//
//
//
//
//
//---------------------------------------------------
// Nothing beyond this point should ever be touched by
// mere mortals so leave this stuff alone.
#ifdef BB_FEATURE_MOUNT_MTAB_SUPPORT
#define BB_MTAB
#endif
//
#ifdef BB_FEATURE_FULL_REGULAR_EXPRESSIONS
#define BB_REGEXP
#endif
//
#ifdef BB_FEATURE_SH_COMMAND_EDITING
#define BB_CMDEDIT
#endif
//

View File

@ -4,12 +4,16 @@
DF="busybox.def.h" DF="busybox.def.h"
MF="busybox.c" MF="busybox.c"
LIST="$(sed -n '/^#define/{s/^#define //p;}' $DF)" LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)"
for def in ${LIST}; do for def in ${LIST}; do
i=`sed -n 's/^#ifdef \<'$def'\>.*\/\/\(.*$\)/\/\1\//gp' $MF` i=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*\(_BB_DIR_[A-Z_]*\).*$/\2\/\1/gp; }' $MF`
j=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*/\1/gp; }' $MF` for j in $i; do
for k in $j; do if [ -z $j ] ; then
echo $i$k continue;
done fi;
echo $j | sed -e 's/_BB_DIR_ROOT//g;s/_BB_DIR_BIN/\/bin/g;' \
-e 's/_BB_DIR_SBIN/\/sbin/g;s/_BB_DIR_USR_BIN/\/usr\/bin/g;' \
-e 's/_BB_DIR_USR_SBIN/\/usr\/sbin/g;'
done;
done done

View File

@ -1,4 +1,3 @@
#!/bin/sh #!/bin/sh
ls -1 `sed -n '/^#define/{s/.*BB_// ; s/$/.c/p; }' busybox.def.h | \ sed -n -e 's/^#define.*BB_FEATURE.*$//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;' \
tr [:upper:] [:lower:]` 2> /dev/null | sed -e 's/\.c$/\.o/g' -e '/^#define/{s/.*bb_//;s/$/.o/p;}' busybox.def.h

View File

@ -51,10 +51,18 @@
#define isOctal(ch) (((ch) >= '0') && ((ch) <= '7')) #define isOctal(ch) (((ch) >= '0') && ((ch) <= '7'))
#define isWildCard(ch) (((ch) == '*') || ((ch) == '?') || ((ch) == '[')) #define isWildCard(ch) (((ch) == '*') || ((ch) == '?') || ((ch) == '['))
enum Location {
_BB_DIR_ROOT = 0,
_BB_DIR_BIN,
_BB_DIR_SBIN,
_BB_DIR_USR_BIN,
_BB_DIR_USR_SBIN
};
struct Applet { struct Applet {
const char* name; const char* name;
int (*main)(int argc, char** argv); int (*main)(int argc, char** argv);
enum Location location;
}; };
extern int basename_main(int argc, char **argv); extern int basename_main(int argc, char **argv);
@ -74,6 +82,7 @@ extern int df_main(int argc, char** argv);
extern int dmesg_main(int argc, char** argv); extern int dmesg_main(int argc, char** argv);
extern int du_main(int argc, char** argv); extern int du_main(int argc, char** argv);
extern int dutmp_main(int argc, char** argv); extern int dutmp_main(int argc, char** argv);
extern int echo_main(int argc, char** argv);
extern int false_main(int argc, char** argv); extern int false_main(int argc, char** argv);
extern int fbset_main(int argc, char** argv); extern int fbset_main(int argc, char** argv);
extern int fdisk_main(int argc, char** argv); extern int fdisk_main(int argc, char** argv);
@ -134,6 +143,7 @@ extern int syslogd_main(int argc, char **argv);
extern int tail_main(int argc, char** argv); extern int tail_main(int argc, char** argv);
extern int tar_main(int argc, char** argv); extern int tar_main(int argc, char** argv);
extern int tee_main(int argc, char** argv); extern int tee_main(int argc, char** argv);
extern int test_main(int argc, char** argv);
extern int telnet_main(int argc, char** argv); extern int telnet_main(int argc, char** argv);
extern int touch_main(int argc, char** argv); extern int touch_main(int argc, char** argv);
extern int tr_main(int argc, char** argv); extern int tr_main(int argc, char** argv);

273
lash.c
View File

@ -39,28 +39,32 @@
#include <unistd.h> #include <unistd.h>
#define MAX_COMMAND_LEN 250 /* max length of a single command #ifdef BB_FEATURE_SH_COMMAND_EDITING
string */ #include "cmdedit.h"
#endif
#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND };
enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
REDIRECT_APPEND };
struct jobSet { struct jobSet {
struct job * head; /* head of list of running jobs */ struct job *head; /* head of list of running jobs */
struct job * fg; /* current foreground job */ struct job *fg; /* current foreground job */
}; };
struct redirectionSpecifier { struct redirectionSpecifier {
enum redirectionType type; /* type of redirection */ enum redirectionType type; /* type of redirection */
int fd; /* file descriptor being redirected */ int fd; /* file descriptor being redirected */
char * filename; /* file to redirect fd to */ char *filename; /* file to redirect fd to */
}; };
struct childProgram { struct childProgram {
pid_t pid; /* 0 if exited */ pid_t pid; /* 0 if exited */
char ** argv; /* program name and arguments */ char **argv; /* program name and arguments */
int numRedirections; /* elements in redirection array */ int numRedirections; /* elements in redirection array */
struct redirectionSpecifier * redirections; /* I/O redirections */ struct redirectionSpecifier *redirections; /* I/O redirections */
glob_t globResult; /* result of parameter globbing */ glob_t globResult; /* result of parameter globbing */
int freeGlob; /* should we globfree(&globResult)? */ int freeGlob; /* should we globfree(&globResult)? */
int isStopped; /* is the program currently running? */ int isStopped; /* is the program currently running? */
@ -70,11 +74,11 @@ struct job {
int jobId; /* job number */ int jobId; /* job number */
int numProgs; /* total number of programs in job */ int numProgs; /* total number of programs in job */
int runningProgs; /* number of programs running */ int runningProgs; /* number of programs running */
char * text; /* name of job */ char *text; /* name of job */
char * cmdBuf; /* buffer various argv's point into */ char *cmdBuf; /* buffer various argv's point into */
pid_t pgrp; /* process group ID for the job */ pid_t pgrp; /* process group ID for the job */
struct childProgram * progs; /* array of programs in job */ struct childProgram *progs; /* array of programs in job */
struct job * next; /* to track background commands */ struct job *next; /* to track background commands */
int stoppedProgs; /* number of programs alive, but stopped */ int stoppedProgs; /* number of programs alive, but stopped */
}; };
@ -86,22 +90,22 @@ struct builtInCommand {
}; };
/* Some function prototypes */ /* Some function prototypes */
static int shell_cd(struct job* cmd, struct jobSet* junk); static int shell_cd(struct job *cmd, struct jobSet *junk);
static int shell_env(struct job* dummy, struct jobSet* junk); static int shell_env(struct job *dummy, struct jobSet *junk);
static int shell_exit(struct job* cmd, struct jobSet* junk); static int shell_exit(struct job *cmd, struct jobSet *junk);
static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
static int shell_help(struct job* cmd, struct jobSet* junk); static int shell_help(struct job *cmd, struct jobSet *junk);
static int shell_jobs(struct job* dummy, struct jobSet* jobList); static int shell_jobs(struct job *dummy, struct jobSet *jobList);
static int shell_pwd(struct job* dummy, struct jobSet* junk); static int shell_pwd(struct job *dummy, struct jobSet *junk);
static int shell_set(struct job* cmd, struct jobSet* junk); static int shell_set(struct job *cmd, struct jobSet *junk);
static int shell_source(struct job* cmd, struct jobSet* jobList); static int shell_source(struct job *cmd, struct jobSet *jobList);
static int shell_unset(struct job* cmd, struct jobSet* junk); static int shell_unset(struct job *cmd, struct jobSet *junk);
static void checkJobs(struct jobSet * jobList); static void checkJobs(struct jobSet *jobList);
static int getCommand(FILE * source, char * command); static int getCommand(FILE * source, char *command);
static int parseCommand(char ** commandPtr, struct job * job, int * isBg); static int parseCommand(char **commandPtr, struct job *job, int *isBg);
static int setupRedirections(struct childProgram * prog); static int setupRedirections(struct childProgram *prog);
static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); static int runCommand(struct job newJob, struct jobSet *jobList, int inBg);
static int busy_loop(FILE * input); static int busy_loop(FILE * input);
@ -109,6 +113,7 @@ static int busy_loop(FILE * input);
static struct builtInCommand bltins[] = { static struct builtInCommand bltins[] = {
{"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg}, {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg},
{"cd", "Change working directory", "cd [dir]", shell_cd}, {"cd", "Change working directory", "cd [dir]", shell_cd},
//{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo},
{"env", "Print all environment variables", "env", shell_env}, {"env", "Print all environment variables", "env", shell_env},
{"exit", "Exit from shell()", "exit", shell_exit}, {"exit", "Exit from shell()", "exit", shell_exit},
{"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
@ -116,23 +121,23 @@ static struct builtInCommand bltins[] = {
{"pwd", "Print current directory", "pwd", shell_pwd}, {"pwd", "Print current directory", "pwd", shell_pwd},
{"set", "Set environment variable", "set [VAR=value]", shell_set}, {"set", "Set environment variable", "set [VAR=value]", shell_set},
{"unset", "Unset environment variable", "unset VAR", shell_unset}, {"unset", "Unset environment variable", "unset VAR", shell_unset},
//{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo}, {".", "Source-in and run commands in a file", ". filename",
{".", "Source-in and run commands in a file", ". filename", shell_source}, shell_source},
{"help", "List shell built-in commands", "help", shell_help}, {"help", "List shell built-in commands", "help", shell_help},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
static const char shell_usage[] = static const char shell_usage[] =
"sh [FILE]...\n\n" "sh [FILE]...\n\n" "The BusyBox command interpreter (shell).\n\n";
"The BusyBox command interpreter (shell).\n\n";
static char cwd[1024]; static char cwd[1024];
static char *prompt = "# "; static char *prompt = "# ";
/* built-in 'cd <path>' handler */ /* built-in 'cd <path>' handler */
static int shell_cd(struct job* cmd, struct jobSet* junk) static int shell_cd(struct job *cmd, struct jobSet *junk)
{ {
char *newdir; char *newdir;
if (!cmd->progs[0].argv[1] == 1) if (!cmd->progs[0].argv[1] == 1)
@ -149,18 +154,18 @@ static int shell_cd(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'env' handler */ /* built-in 'env' handler */
static int shell_env(struct job* dummy, struct jobSet* junk) static int shell_env(struct job *dummy, struct jobSet *junk)
{ {
char **e; char **e;
for (e = environ ; *e ; e++) { for (e = environ; *e; e++) {
fprintf(stdout, "%s\n", *e); fprintf(stdout, "%s\n", *e);
} }
return (0); return (0);
} }
/* built-in 'exit' handler */ /* built-in 'exit' handler */
static int shell_exit(struct job* cmd, struct jobSet* junk) static int shell_exit(struct job *cmd, struct jobSet *junk)
{ {
if (!cmd->progs[0].argv[1] == 1) if (!cmd->progs[0].argv[1] == 1)
exit TRUE; exit TRUE;
@ -169,25 +174,29 @@ static int shell_exit(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'fg' and 'bg' handler */ /* built-in 'fg' and 'bg' handler */
static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
{ {
int i, jobNum; int i, jobNum;
struct job* job; struct job *job;
if (!jobList->head) {
if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
fprintf(stderr, "%s: exactly one argument is expected\n", fprintf(stderr, "%s: exactly one argument is expected\n",
cmd->progs[0].argv[0]); cmd->progs[0].argv[0]);
return FALSE; return FALSE;
} }
if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) {
fprintf(stderr, "%s: bad argument '%s'\n", fprintf(stderr, "%s: bad argument '%s'\n",
cmd->progs[0].argv[0], cmd->progs[0].argv[1]); cmd->progs[0].argv[0], cmd->progs[0].argv[1]);
return FALSE; return FALSE;
} }
} else {
job = jobList->head;
}
for (job = jobList->head; job; job = job->next) for (job = jobList->head; job; job = job->next)
if (job->jobId == jobNum) break; if (job->jobId == jobNum)
break;
if (!job) { if (!job) {
fprintf(stderr, "%s: unknown job %d\n", fprintf(stderr, "%s: unknown job %d\n",
@ -215,13 +224,13 @@ static int shell_fg_bg(struct job* cmd, struct jobSet* jobList)
} }
/* built-in 'help' handler */ /* built-in 'help' handler */
static int shell_help(struct job* cmd, struct jobSet* junk) static int shell_help(struct job *cmd, struct jobSet *junk)
{ {
struct builtInCommand *x; struct builtInCommand *x;
fprintf(stdout, "\nBuilt-in commands:\n"); fprintf(stdout, "\nBuilt-in commands:\n");
fprintf(stdout, "-------------------\n"); fprintf(stdout, "-------------------\n");
for ( x=bltins; x->cmd; x++) { for (x = bltins; x->cmd; x++) {
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
} }
fprintf(stdout, "\n\n"); fprintf(stdout, "\n\n");
@ -229,25 +238,24 @@ static int shell_help(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'jobs' handler */ /* built-in 'jobs' handler */
static int shell_jobs(struct job* dummy, struct jobSet* jobList) static int shell_jobs(struct job *dummy, struct jobSet *jobList)
{ {
struct job * job; struct job *job;
char * statusString; char *statusString;
for (job = jobList->head; job; job = job->next) { for (job = jobList->head; job; job = job->next) {
if (job->runningProgs == job->stoppedProgs) if (job->runningProgs == job->stoppedProgs)
statusString = "Stopped"; statusString = "Stopped";
else else
statusString = "Running"; statusString = "Running";
printf(JOB_STATUS_FORMAT, job->jobId, statusString, printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text);
job->text);
} }
return TRUE; return TRUE;
} }
/* built-in 'pwd' handler */ /* built-in 'pwd' handler */
static int shell_pwd(struct job* dummy, struct jobSet* junk) static int shell_pwd(struct job *dummy, struct jobSet *junk)
{ {
getcwd(cwd, sizeof(cwd)); getcwd(cwd, sizeof(cwd));
fprintf(stdout, "%s\n", cwd); fprintf(stdout, "%s\n", cwd);
@ -255,7 +263,7 @@ static int shell_pwd(struct job* dummy, struct jobSet* junk)
} }
/* built-in 'set VAR=value' handler */ /* built-in 'set VAR=value' handler */
static int shell_set(struct job* cmd, struct jobSet* junk) static int shell_set(struct job *cmd, struct jobSet *junk)
{ {
int res; int res;
@ -269,7 +277,7 @@ static int shell_set(struct job* cmd, struct jobSet* junk)
} }
/* Built-in '.' handler (read-in and execute commands from file) */ /* Built-in '.' handler (read-in and execute commands from file) */
static int shell_source(struct job* cmd, struct jobSet* junk) static int shell_source(struct job *cmd, struct jobSet *junk)
{ {
FILE *input; FILE *input;
int status; int status;
@ -279,7 +287,8 @@ static int shell_source(struct job* cmd, struct jobSet* junk)
input = fopen(cmd->progs[0].argv[1], "r"); input = fopen(cmd->progs[0].argv[1], "r");
if (!input) { if (!input) {
fprintf(stdout, "Couldn't open file '%s'\n", cmd->progs[0].argv[1]); fprintf(stdout, "Couldn't open file '%s'\n",
cmd->progs[0].argv[1]);
return FALSE; return FALSE;
} }
@ -289,7 +298,7 @@ static int shell_source(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'unset VAR' handler */ /* built-in 'unset VAR' handler */
static int shell_unset(struct job* cmd, struct jobSet* junk) static int shell_unset(struct job *cmd, struct jobSet *junk)
{ {
if (!cmd->progs[0].argv[1] == 1) { if (!cmd->progs[0].argv[1] == 1) {
fprintf(stdout, "unset: parameter required.\n"); fprintf(stdout, "unset: parameter required.\n");
@ -300,31 +309,35 @@ static int shell_unset(struct job* cmd, struct jobSet* junk)
} }
/* free up all memory from a job */ /* free up all memory from a job */
static void freeJob(struct job * cmd) static void freeJob(struct job *cmd)
{ {
int i; int i;
for (i = 0; i < cmd->numProgs; i++) { for (i = 0; i < cmd->numProgs; i++) {
free(cmd->progs[i].argv); free(cmd->progs[i].argv);
if (cmd->progs[i].redirections) free(cmd->progs[i].redirections); if (cmd->progs[i].redirections)
if (cmd->progs[i].freeGlob) globfree(&cmd->progs[i].globResult); free(cmd->progs[i].redirections);
if (cmd->progs[i].freeGlob)
globfree(&cmd->progs[i].globResult);
} }
free(cmd->progs); free(cmd->progs);
if (cmd->text) free(cmd->text); if (cmd->text)
free(cmd->text);
free(cmd->cmdBuf); free(cmd->cmdBuf);
} }
/* remove a job from the jobList */ /* remove a job from the jobList */
static void removeJob(struct jobSet * jobList, struct job * job) static void removeJob(struct jobSet *jobList, struct job *job)
{ {
struct job * prevJob; struct job *prevJob;
freeJob(job); freeJob(job);
if (job == jobList->head) { if (job == jobList->head) {
jobList->head = job->next; jobList->head = job->next;
} else { } else {
prevJob = jobList->head; prevJob = jobList->head;
while (prevJob->next != job) prevJob = prevJob->next; while (prevJob->next != job)
prevJob = prevJob->next;
prevJob->next = job->next; prevJob->next = job->next;
} }
@ -333,20 +346,20 @@ static void removeJob(struct jobSet * jobList, struct job * job)
/* Checks to see if any background processes have exited -- if they /* Checks to see if any background processes have exited -- if they
have, figure out why and see if a job has completed */ have, figure out why and see if a job has completed */
static void checkJobs(struct jobSet * jobList) static void checkJobs(struct jobSet *jobList)
{ {
struct job * job; struct job *job;
pid_t childpid; pid_t childpid;
int status; int status;
int progNum=0; int progNum = 0;
while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
for (job = jobList->head; job; job = job->next) { for (job = jobList->head; job; job = job->next) {
progNum = 0; progNum = 0;
while (progNum < job->numProgs && while (progNum < job->numProgs &&
job->progs[progNum].pid != childpid) job->progs[progNum].pid != childpid) progNum++;
progNum++; if (progNum < job->numProgs)
if (progNum < job->numProgs) break; break;
} }
if (WIFEXITED(status) || WIFSIGNALED(status)) { if (WIFEXITED(status) || WIFSIGNALED(status)) {
@ -364,7 +377,8 @@ static void checkJobs(struct jobSet * jobList)
job->progs[progNum].isStopped = 1; job->progs[progNum].isStopped = 1;
if (job->stoppedProgs == job->numProgs) { if (job->stoppedProgs == job->numProgs) {
printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", job->text); printf(JOB_STATUS_FORMAT, job->jobId, "Stopped",
job->text);
} }
} }
} }
@ -373,15 +387,20 @@ static void checkJobs(struct jobSet * jobList)
perror("waitpid"); perror("waitpid");
} }
static int getCommand(FILE * source, char * command) static int getCommand(FILE * source, char *command)
{ {
if (source == stdin) { if (source == stdin) {
fprintf(stdout, "%s %s", cwd, prompt); fprintf(stdout, "BBSHELL %s %s", cwd, prompt);
fflush(stdout); fflush(stdout);
#ifdef BB_FEATURE_SH_COMMAND_EDITING
cmdedit_read_input(fileno(stdin), fileno(stdout), command);
return 0;
#endif
} }
if (!fgets(command, MAX_COMMAND_LEN, source)) { if (!fgets(command, BUFSIZ - 2, source)) {
if (source == stdin) printf("\n"); if (source == stdin)
printf("\n");
return 1; return 1;
} }
@ -391,15 +410,15 @@ static int getCommand(FILE * source, char * command)
return 0; return 0;
} }
static void globLastArgument(struct childProgram * prog, int * argcPtr, static void globLastArgument(struct childProgram *prog, int *argcPtr,
int * argcAllocedPtr) int *argcAllocedPtr)
{ {
int argc = *argcPtr; int argc = *argcPtr;
int argcAlloced = *argcAllocedPtr; int argcAlloced = *argcAllocedPtr;
int rc; int rc;
int flags; int flags;
int i; int i;
char * src, * dst; char *src, *dst;
if (argc > 1) { /* cmd->globResult is already initialized */ if (argc > 1) { /* cmd->globResult is already initialized */
flags = GLOB_APPEND; flags = GLOB_APPEND;
@ -421,13 +440,15 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
/* we need to remove whatever \ quoting is still present */ /* we need to remove whatever \ quoting is still present */
src = dst = prog->argv[argc - 1]; src = dst = prog->argv[argc - 1];
while (*src) { while (*src) {
if (*src != '\\') *dst++ = *src; if (*src != '\\')
*dst++ = *src;
src++; src++;
} }
*dst = '\0'; *dst = '\0';
} else if (!rc) { } else if (!rc) {
argcAlloced += (prog->globResult.gl_pathc - i); argcAlloced += (prog->globResult.gl_pathc - i);
prog->argv = realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); prog->argv =
realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
argc += (prog->globResult.gl_pathc - i - 1); argc += (prog->globResult.gl_pathc - i - 1);
@ -442,24 +463,25 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
the beginning of the next command (if the original command had more the beginning of the next command (if the original command had more
then one job associated with it) or NULL if no more commands are then one job associated with it) or NULL if no more commands are
present. */ present. */
static int parseCommand(char ** commandPtr, struct job * job, int * isBg) static int parseCommand(char **commandPtr, struct job *job, int *isBg)
{ {
char * command; char *command;
char * returnCommand = NULL; char *returnCommand = NULL;
char * src, * buf, * chptr; char *src, *buf, *chptr;
int argc = 0; int argc = 0;
int done = 0; int done = 0;
int argvAlloced; int argvAlloced;
int i; int i;
char quote = '\0'; char quote = '\0';
int count; int count;
struct childProgram * prog; struct childProgram *prog;
/* skip leading white space */ /* skip leading white space */
while (**commandPtr && isspace(**commandPtr)) (*commandPtr)++; while (**commandPtr && isspace(**commandPtr))
(*commandPtr)++;
/* this handles empty lines or leading '#' characters */ /* this handles empty lines or leading '#' characters */
if (!**commandPtr || (**commandPtr=='#')) { if (!**commandPtr || (**commandPtr == '#')) {
job->numProgs = 0; job->numProgs = 0;
*commandPtr = NULL; *commandPtr = NULL;
return 0; return 0;
@ -503,10 +525,10 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
} }
/* in shell, "\'" should yield \' */ /* in shell, "\'" should yield \' */
if (*src != quote) *buf++ = '\\'; if (*src != quote)
} else if (*src == '*' || *src == '?' || *src == '[' ||
*src == ']')
*buf++ = '\\'; *buf++ = '\\';
} else if (*src == '*' || *src == '?' || *src == '[' ||
*src == ']') *buf++ = '\\';
*buf++ = *src; *buf++ = *src;
} else if (isspace(*src)) { } else if (isspace(*src)) {
if (*prog->argv[argc]) { if (*prog->argv[argc]) {
@ -515,13 +537,15 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
if ((argc + 1) == argvAlloced) { if ((argc + 1) == argvAlloced) {
argvAlloced += 5; argvAlloced += 5;
prog->argv = realloc(prog->argv, prog->argv = realloc(prog->argv,
sizeof(*prog->argv) * argvAlloced); sizeof(*prog->argv) *
argvAlloced);
} }
prog->argv[argc] = buf; prog->argv[argc] = buf;
globLastArgument(prog, &argc, &argvAlloced); globLastArgument(prog, &argc, &argvAlloced);
} }
} else switch (*src) { } else
switch (*src) {
case '"': case '"':
case '\'': case '\'':
quote = *src; quote = *src;
@ -535,13 +559,15 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
case '<': case '<':
i = prog->numRedirections++; i = prog->numRedirections++;
prog->redirections = realloc(prog->redirections, prog->redirections = realloc(prog->redirections,
sizeof(*prog->redirections) * (i + 1)); sizeof(*prog->redirections) *
(i + 1));
prog->redirections[i].fd = -1; prog->redirections[i].fd = -1;
if (buf != prog->argv[argc]) { if (buf != prog->argv[argc]) {
/* the stuff before this character may be the file number /* the stuff before this character may be the file number
being redirected */ being redirected */
prog->redirections[i].fd = strtol(prog->argv[argc], &chptr, 10); prog->redirections[i].fd =
strtol(prog->argv[argc], &chptr, 10);
if (*chptr && *prog->argv[argc]) { if (*chptr && *prog->argv[argc]) {
buf++, argc++; buf++, argc++;
@ -558,7 +584,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
if (*src++ == '>') { if (*src++ == '>') {
if (*src == '>') if (*src == '>')
prog->redirections[i].type = REDIRECT_APPEND, src++; prog->redirections[i].type =
REDIRECT_APPEND, src++;
else else
prog->redirections[i].type = REDIRECT_OVERWRITE; prog->redirections[i].type = REDIRECT_OVERWRITE;
} else { } else {
@ -567,7 +594,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
/* This isn't POSIX sh compliant. Oh well. */ /* This isn't POSIX sh compliant. Oh well. */
chptr = src; chptr = src;
while (isspace(*chptr)) chptr++; while (isspace(*chptr))
chptr++;
if (!*chptr) { if (!*chptr) {
fprintf(stderr, "file name expected after %c\n", *src); fprintf(stderr, "file name expected after %c\n", *src);
@ -585,7 +613,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
case '|': /* pipe */ case '|': /* pipe */
/* finish this command */ /* finish this command */
if (*prog->argv[argc]) argc++; if (*prog->argv[argc])
argc++;
if (!argc) { if (!argc) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe\n");
freeJob(job); freeJob(job);
@ -608,7 +637,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
prog->argv[0] = ++buf; prog->argv[0] = ++buf;
src++; src++;
while (*src && isspace(*src)) src++; while (*src && isspace(*src))
src++;
if (!*src) { if (!*src) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe\n");
@ -632,8 +662,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
fprintf(stderr, "character expected after \\\n"); fprintf(stderr, "character expected after \\\n");
return 1; return 1;
} }
if (*src == '*' || *src == '[' || *src == ']' || *src == '?') if (*src == '*' || *src == '[' || *src == ']'
*buf++ = '\\'; || *src == '?') *buf++ = '\\';
/* fallthrough */ /* fallthrough */
default: default:
*buf++ = *src; *buf++ = *src;
@ -669,10 +699,9 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
return 0; return 0;
} }
static int runCommand(struct job newJob, struct jobSet * jobList, static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
int inBg)
{ {
struct job * job; struct job *job;
int i; int i;
int nextin, nextout; int nextin, nextout;
int pipefds[2]; /* pipefd[0] is for reading */ int pipefds[2]; /* pipefd[0] is for reading */
@ -680,9 +709,9 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
/* handle built-ins here -- we don't fork() so we can't background /* handle built-ins here -- we don't fork() so we can't background
these very easily */ these very easily */
for( x=bltins ; x->cmd ; x++) { for (x = bltins; x->cmd; x++) {
if (!strcmp(newJob.progs[0].argv[0], x->cmd)) { if (!strcmp(newJob.progs[0].argv[0], x->cmd)) {
return(x->function(&newJob, jobList)); return (x->function(&newJob, jobList));
} }
} }
@ -712,7 +741,7 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
setupRedirections(newJob.progs + i); setupRedirections(newJob.progs + i);
execvp(newJob.progs[i].argv[0], newJob.progs[i].argv); execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);
fatalError( "sh: %s: %s\n", newJob.progs[i].argv[0], fatalError("sh: %s: %s\n", newJob.progs[i].argv[0],
strerror(errno)); strerror(errno));
} }
@ -720,8 +749,10 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
first process in this pipe */ first process in this pipe */
setpgid(newJob.progs[i].pid, newJob.progs[0].pid); setpgid(newJob.progs[i].pid, newJob.progs[0].pid);
if (nextin != 0) close(nextin); if (nextin != 0)
if (nextout != 1) close(nextout); close(nextin);
if (nextout != 1)
close(nextout);
/* If there isn't another process, nextin is garbage /* If there isn't another process, nextin is garbage
but it doesn't matter */ but it doesn't matter */
@ -768,12 +799,12 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
return 0; return 0;
} }
static int setupRedirections(struct childProgram * prog) static int setupRedirections(struct childProgram *prog)
{ {
int i; int i;
int openfd; int openfd;
int mode=O_RDONLY; int mode = O_RDONLY;
struct redirectionSpecifier * redir = prog->redirections; struct redirectionSpecifier *redir = prog->redirections;
for (i = 0; i < prog->numRedirections; i++, redir++) { for (i = 0; i < prog->numRedirections; i++, redir++) {
switch (redir->type) { switch (redir->type) {
@ -809,14 +840,16 @@ static int setupRedirections(struct childProgram * prog)
static int busy_loop(FILE * input) static int busy_loop(FILE * input)
{ {
char command[MAX_COMMAND_LEN + 1]; char *command;
char * nextCommand = NULL; char *nextCommand = NULL;
struct jobSet jobList = { NULL, NULL }; struct jobSet jobList = { NULL, NULL };
struct job newJob; struct job newJob;
int i; int i;
int status; int status;
int inBg; int inBg;
command = (char*) calloc(BUFSIZ, sizeof(char));
/* don't pay any attention to this signal; it just confuses /* don't pay any attention to this signal; it just confuses
things and isn't really meant for shells anyway */ things and isn't really meant for shells anyway */
signal(SIGTTOU, SIG_IGN); signal(SIGTTOU, SIG_IGN);
@ -829,7 +862,8 @@ static int busy_loop(FILE * input)
checkJobs(&jobList); checkJobs(&jobList);
if (!nextCommand) { if (!nextCommand) {
if (getCommand(input, command)) break; if (getCommand(input, command))
break;
nextCommand = command; nextCommand = command;
} }
@ -879,17 +913,18 @@ static int busy_loop(FILE * input)
} }
} }
} }
free( command);
return 0; return 0;
} }
int shell_main(int argc, char ** argv) int shell_main(int argc, char **argv)
{ {
FILE * input = stdin; FILE *input = stdin;
if (argc > 2) { if (argc > 2) {
usage( shell_usage); usage(shell_usage);
} }
/* initialize the cwd */ /* initialize the cwd */
getcwd(cwd, sizeof(cwd)); getcwd(cwd, sizeof(cwd));
@ -900,16 +935,24 @@ int shell_main(int argc, char ** argv)
//} //}
if (argc < 2) { if (argc < 2) {
fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER,
fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); BB_BT);
fprintf(stdout,
"Enter 'help' for a list of built-in commands.\n\n");
} else { } else {
input = fopen(argv[1], "r"); input = fopen(argv[1], "r");
if (!input) if (!input)
fatalError("A: Couldn't open file '%s': %s\n", argv[1], strerror(errno)); fatalError("A: Couldn't open file '%s': %s\n", argv[1],
strerror(errno));
// else // else
// fatalError("Got it.\n"); // fatalError("Got it.\n");
//exit(shell_source(argv[1])); //exit(shell_source(argv[1]));
/* Set terminal IO to canonical mode, and save old term settings. */
#ifdef BB_FEATURE_SH_COMMAND_EDITING
cmdedit_init();
#endif
} }
return (busy_loop( input)); return (busy_loop(input));
} }

273
sh.c
View File

@ -39,28 +39,32 @@
#include <unistd.h> #include <unistd.h>
#define MAX_COMMAND_LEN 250 /* max length of a single command #ifdef BB_FEATURE_SH_COMMAND_EDITING
string */ #include "cmdedit.h"
#endif
#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND };
enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
REDIRECT_APPEND };
struct jobSet { struct jobSet {
struct job * head; /* head of list of running jobs */ struct job *head; /* head of list of running jobs */
struct job * fg; /* current foreground job */ struct job *fg; /* current foreground job */
}; };
struct redirectionSpecifier { struct redirectionSpecifier {
enum redirectionType type; /* type of redirection */ enum redirectionType type; /* type of redirection */
int fd; /* file descriptor being redirected */ int fd; /* file descriptor being redirected */
char * filename; /* file to redirect fd to */ char *filename; /* file to redirect fd to */
}; };
struct childProgram { struct childProgram {
pid_t pid; /* 0 if exited */ pid_t pid; /* 0 if exited */
char ** argv; /* program name and arguments */ char **argv; /* program name and arguments */
int numRedirections; /* elements in redirection array */ int numRedirections; /* elements in redirection array */
struct redirectionSpecifier * redirections; /* I/O redirections */ struct redirectionSpecifier *redirections; /* I/O redirections */
glob_t globResult; /* result of parameter globbing */ glob_t globResult; /* result of parameter globbing */
int freeGlob; /* should we globfree(&globResult)? */ int freeGlob; /* should we globfree(&globResult)? */
int isStopped; /* is the program currently running? */ int isStopped; /* is the program currently running? */
@ -70,11 +74,11 @@ struct job {
int jobId; /* job number */ int jobId; /* job number */
int numProgs; /* total number of programs in job */ int numProgs; /* total number of programs in job */
int runningProgs; /* number of programs running */ int runningProgs; /* number of programs running */
char * text; /* name of job */ char *text; /* name of job */
char * cmdBuf; /* buffer various argv's point into */ char *cmdBuf; /* buffer various argv's point into */
pid_t pgrp; /* process group ID for the job */ pid_t pgrp; /* process group ID for the job */
struct childProgram * progs; /* array of programs in job */ struct childProgram *progs; /* array of programs in job */
struct job * next; /* to track background commands */ struct job *next; /* to track background commands */
int stoppedProgs; /* number of programs alive, but stopped */ int stoppedProgs; /* number of programs alive, but stopped */
}; };
@ -86,22 +90,22 @@ struct builtInCommand {
}; };
/* Some function prototypes */ /* Some function prototypes */
static int shell_cd(struct job* cmd, struct jobSet* junk); static int shell_cd(struct job *cmd, struct jobSet *junk);
static int shell_env(struct job* dummy, struct jobSet* junk); static int shell_env(struct job *dummy, struct jobSet *junk);
static int shell_exit(struct job* cmd, struct jobSet* junk); static int shell_exit(struct job *cmd, struct jobSet *junk);
static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
static int shell_help(struct job* cmd, struct jobSet* junk); static int shell_help(struct job *cmd, struct jobSet *junk);
static int shell_jobs(struct job* dummy, struct jobSet* jobList); static int shell_jobs(struct job *dummy, struct jobSet *jobList);
static int shell_pwd(struct job* dummy, struct jobSet* junk); static int shell_pwd(struct job *dummy, struct jobSet *junk);
static int shell_set(struct job* cmd, struct jobSet* junk); static int shell_set(struct job *cmd, struct jobSet *junk);
static int shell_source(struct job* cmd, struct jobSet* jobList); static int shell_source(struct job *cmd, struct jobSet *jobList);
static int shell_unset(struct job* cmd, struct jobSet* junk); static int shell_unset(struct job *cmd, struct jobSet *junk);
static void checkJobs(struct jobSet * jobList); static void checkJobs(struct jobSet *jobList);
static int getCommand(FILE * source, char * command); static int getCommand(FILE * source, char *command);
static int parseCommand(char ** commandPtr, struct job * job, int * isBg); static int parseCommand(char **commandPtr, struct job *job, int *isBg);
static int setupRedirections(struct childProgram * prog); static int setupRedirections(struct childProgram *prog);
static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); static int runCommand(struct job newJob, struct jobSet *jobList, int inBg);
static int busy_loop(FILE * input); static int busy_loop(FILE * input);
@ -109,6 +113,7 @@ static int busy_loop(FILE * input);
static struct builtInCommand bltins[] = { static struct builtInCommand bltins[] = {
{"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg}, {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg},
{"cd", "Change working directory", "cd [dir]", shell_cd}, {"cd", "Change working directory", "cd [dir]", shell_cd},
//{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo},
{"env", "Print all environment variables", "env", shell_env}, {"env", "Print all environment variables", "env", shell_env},
{"exit", "Exit from shell()", "exit", shell_exit}, {"exit", "Exit from shell()", "exit", shell_exit},
{"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
@ -116,23 +121,23 @@ static struct builtInCommand bltins[] = {
{"pwd", "Print current directory", "pwd", shell_pwd}, {"pwd", "Print current directory", "pwd", shell_pwd},
{"set", "Set environment variable", "set [VAR=value]", shell_set}, {"set", "Set environment variable", "set [VAR=value]", shell_set},
{"unset", "Unset environment variable", "unset VAR", shell_unset}, {"unset", "Unset environment variable", "unset VAR", shell_unset},
//{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo}, {".", "Source-in and run commands in a file", ". filename",
{".", "Source-in and run commands in a file", ". filename", shell_source}, shell_source},
{"help", "List shell built-in commands", "help", shell_help}, {"help", "List shell built-in commands", "help", shell_help},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
static const char shell_usage[] = static const char shell_usage[] =
"sh [FILE]...\n\n" "sh [FILE]...\n\n" "The BusyBox command interpreter (shell).\n\n";
"The BusyBox command interpreter (shell).\n\n";
static char cwd[1024]; static char cwd[1024];
static char *prompt = "# "; static char *prompt = "# ";
/* built-in 'cd <path>' handler */ /* built-in 'cd <path>' handler */
static int shell_cd(struct job* cmd, struct jobSet* junk) static int shell_cd(struct job *cmd, struct jobSet *junk)
{ {
char *newdir; char *newdir;
if (!cmd->progs[0].argv[1] == 1) if (!cmd->progs[0].argv[1] == 1)
@ -149,18 +154,18 @@ static int shell_cd(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'env' handler */ /* built-in 'env' handler */
static int shell_env(struct job* dummy, struct jobSet* junk) static int shell_env(struct job *dummy, struct jobSet *junk)
{ {
char **e; char **e;
for (e = environ ; *e ; e++) { for (e = environ; *e; e++) {
fprintf(stdout, "%s\n", *e); fprintf(stdout, "%s\n", *e);
} }
return (0); return (0);
} }
/* built-in 'exit' handler */ /* built-in 'exit' handler */
static int shell_exit(struct job* cmd, struct jobSet* junk) static int shell_exit(struct job *cmd, struct jobSet *junk)
{ {
if (!cmd->progs[0].argv[1] == 1) if (!cmd->progs[0].argv[1] == 1)
exit TRUE; exit TRUE;
@ -169,25 +174,29 @@ static int shell_exit(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'fg' and 'bg' handler */ /* built-in 'fg' and 'bg' handler */
static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
{ {
int i, jobNum; int i, jobNum;
struct job* job; struct job *job;
if (!jobList->head) {
if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
fprintf(stderr, "%s: exactly one argument is expected\n", fprintf(stderr, "%s: exactly one argument is expected\n",
cmd->progs[0].argv[0]); cmd->progs[0].argv[0]);
return FALSE; return FALSE;
} }
if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) {
fprintf(stderr, "%s: bad argument '%s'\n", fprintf(stderr, "%s: bad argument '%s'\n",
cmd->progs[0].argv[0], cmd->progs[0].argv[1]); cmd->progs[0].argv[0], cmd->progs[0].argv[1]);
return FALSE; return FALSE;
} }
} else {
job = jobList->head;
}
for (job = jobList->head; job; job = job->next) for (job = jobList->head; job; job = job->next)
if (job->jobId == jobNum) break; if (job->jobId == jobNum)
break;
if (!job) { if (!job) {
fprintf(stderr, "%s: unknown job %d\n", fprintf(stderr, "%s: unknown job %d\n",
@ -215,13 +224,13 @@ static int shell_fg_bg(struct job* cmd, struct jobSet* jobList)
} }
/* built-in 'help' handler */ /* built-in 'help' handler */
static int shell_help(struct job* cmd, struct jobSet* junk) static int shell_help(struct job *cmd, struct jobSet *junk)
{ {
struct builtInCommand *x; struct builtInCommand *x;
fprintf(stdout, "\nBuilt-in commands:\n"); fprintf(stdout, "\nBuilt-in commands:\n");
fprintf(stdout, "-------------------\n"); fprintf(stdout, "-------------------\n");
for ( x=bltins; x->cmd; x++) { for (x = bltins; x->cmd; x++) {
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
} }
fprintf(stdout, "\n\n"); fprintf(stdout, "\n\n");
@ -229,25 +238,24 @@ static int shell_help(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'jobs' handler */ /* built-in 'jobs' handler */
static int shell_jobs(struct job* dummy, struct jobSet* jobList) static int shell_jobs(struct job *dummy, struct jobSet *jobList)
{ {
struct job * job; struct job *job;
char * statusString; char *statusString;
for (job = jobList->head; job; job = job->next) { for (job = jobList->head; job; job = job->next) {
if (job->runningProgs == job->stoppedProgs) if (job->runningProgs == job->stoppedProgs)
statusString = "Stopped"; statusString = "Stopped";
else else
statusString = "Running"; statusString = "Running";
printf(JOB_STATUS_FORMAT, job->jobId, statusString, printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text);
job->text);
} }
return TRUE; return TRUE;
} }
/* built-in 'pwd' handler */ /* built-in 'pwd' handler */
static int shell_pwd(struct job* dummy, struct jobSet* junk) static int shell_pwd(struct job *dummy, struct jobSet *junk)
{ {
getcwd(cwd, sizeof(cwd)); getcwd(cwd, sizeof(cwd));
fprintf(stdout, "%s\n", cwd); fprintf(stdout, "%s\n", cwd);
@ -255,7 +263,7 @@ static int shell_pwd(struct job* dummy, struct jobSet* junk)
} }
/* built-in 'set VAR=value' handler */ /* built-in 'set VAR=value' handler */
static int shell_set(struct job* cmd, struct jobSet* junk) static int shell_set(struct job *cmd, struct jobSet *junk)
{ {
int res; int res;
@ -269,7 +277,7 @@ static int shell_set(struct job* cmd, struct jobSet* junk)
} }
/* Built-in '.' handler (read-in and execute commands from file) */ /* Built-in '.' handler (read-in and execute commands from file) */
static int shell_source(struct job* cmd, struct jobSet* junk) static int shell_source(struct job *cmd, struct jobSet *junk)
{ {
FILE *input; FILE *input;
int status; int status;
@ -279,7 +287,8 @@ static int shell_source(struct job* cmd, struct jobSet* junk)
input = fopen(cmd->progs[0].argv[1], "r"); input = fopen(cmd->progs[0].argv[1], "r");
if (!input) { if (!input) {
fprintf(stdout, "Couldn't open file '%s'\n", cmd->progs[0].argv[1]); fprintf(stdout, "Couldn't open file '%s'\n",
cmd->progs[0].argv[1]);
return FALSE; return FALSE;
} }
@ -289,7 +298,7 @@ static int shell_source(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'unset VAR' handler */ /* built-in 'unset VAR' handler */
static int shell_unset(struct job* cmd, struct jobSet* junk) static int shell_unset(struct job *cmd, struct jobSet *junk)
{ {
if (!cmd->progs[0].argv[1] == 1) { if (!cmd->progs[0].argv[1] == 1) {
fprintf(stdout, "unset: parameter required.\n"); fprintf(stdout, "unset: parameter required.\n");
@ -300,31 +309,35 @@ static int shell_unset(struct job* cmd, struct jobSet* junk)
} }
/* free up all memory from a job */ /* free up all memory from a job */
static void freeJob(struct job * cmd) static void freeJob(struct job *cmd)
{ {
int i; int i;
for (i = 0; i < cmd->numProgs; i++) { for (i = 0; i < cmd->numProgs; i++) {
free(cmd->progs[i].argv); free(cmd->progs[i].argv);
if (cmd->progs[i].redirections) free(cmd->progs[i].redirections); if (cmd->progs[i].redirections)
if (cmd->progs[i].freeGlob) globfree(&cmd->progs[i].globResult); free(cmd->progs[i].redirections);
if (cmd->progs[i].freeGlob)
globfree(&cmd->progs[i].globResult);
} }
free(cmd->progs); free(cmd->progs);
if (cmd->text) free(cmd->text); if (cmd->text)
free(cmd->text);
free(cmd->cmdBuf); free(cmd->cmdBuf);
} }
/* remove a job from the jobList */ /* remove a job from the jobList */
static void removeJob(struct jobSet * jobList, struct job * job) static void removeJob(struct jobSet *jobList, struct job *job)
{ {
struct job * prevJob; struct job *prevJob;
freeJob(job); freeJob(job);
if (job == jobList->head) { if (job == jobList->head) {
jobList->head = job->next; jobList->head = job->next;
} else { } else {
prevJob = jobList->head; prevJob = jobList->head;
while (prevJob->next != job) prevJob = prevJob->next; while (prevJob->next != job)
prevJob = prevJob->next;
prevJob->next = job->next; prevJob->next = job->next;
} }
@ -333,20 +346,20 @@ static void removeJob(struct jobSet * jobList, struct job * job)
/* Checks to see if any background processes have exited -- if they /* Checks to see if any background processes have exited -- if they
have, figure out why and see if a job has completed */ have, figure out why and see if a job has completed */
static void checkJobs(struct jobSet * jobList) static void checkJobs(struct jobSet *jobList)
{ {
struct job * job; struct job *job;
pid_t childpid; pid_t childpid;
int status; int status;
int progNum=0; int progNum = 0;
while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
for (job = jobList->head; job; job = job->next) { for (job = jobList->head; job; job = job->next) {
progNum = 0; progNum = 0;
while (progNum < job->numProgs && while (progNum < job->numProgs &&
job->progs[progNum].pid != childpid) job->progs[progNum].pid != childpid) progNum++;
progNum++; if (progNum < job->numProgs)
if (progNum < job->numProgs) break; break;
} }
if (WIFEXITED(status) || WIFSIGNALED(status)) { if (WIFEXITED(status) || WIFSIGNALED(status)) {
@ -364,7 +377,8 @@ static void checkJobs(struct jobSet * jobList)
job->progs[progNum].isStopped = 1; job->progs[progNum].isStopped = 1;
if (job->stoppedProgs == job->numProgs) { if (job->stoppedProgs == job->numProgs) {
printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", job->text); printf(JOB_STATUS_FORMAT, job->jobId, "Stopped",
job->text);
} }
} }
} }
@ -373,15 +387,20 @@ static void checkJobs(struct jobSet * jobList)
perror("waitpid"); perror("waitpid");
} }
static int getCommand(FILE * source, char * command) static int getCommand(FILE * source, char *command)
{ {
if (source == stdin) { if (source == stdin) {
fprintf(stdout, "%s %s", cwd, prompt); fprintf(stdout, "BBSHELL %s %s", cwd, prompt);
fflush(stdout); fflush(stdout);
#ifdef BB_FEATURE_SH_COMMAND_EDITING
cmdedit_read_input(fileno(stdin), fileno(stdout), command);
return 0;
#endif
} }
if (!fgets(command, MAX_COMMAND_LEN, source)) { if (!fgets(command, BUFSIZ - 2, source)) {
if (source == stdin) printf("\n"); if (source == stdin)
printf("\n");
return 1; return 1;
} }
@ -391,15 +410,15 @@ static int getCommand(FILE * source, char * command)
return 0; return 0;
} }
static void globLastArgument(struct childProgram * prog, int * argcPtr, static void globLastArgument(struct childProgram *prog, int *argcPtr,
int * argcAllocedPtr) int *argcAllocedPtr)
{ {
int argc = *argcPtr; int argc = *argcPtr;
int argcAlloced = *argcAllocedPtr; int argcAlloced = *argcAllocedPtr;
int rc; int rc;
int flags; int flags;
int i; int i;
char * src, * dst; char *src, *dst;
if (argc > 1) { /* cmd->globResult is already initialized */ if (argc > 1) { /* cmd->globResult is already initialized */
flags = GLOB_APPEND; flags = GLOB_APPEND;
@ -421,13 +440,15 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
/* we need to remove whatever \ quoting is still present */ /* we need to remove whatever \ quoting is still present */
src = dst = prog->argv[argc - 1]; src = dst = prog->argv[argc - 1];
while (*src) { while (*src) {
if (*src != '\\') *dst++ = *src; if (*src != '\\')
*dst++ = *src;
src++; src++;
} }
*dst = '\0'; *dst = '\0';
} else if (!rc) { } else if (!rc) {
argcAlloced += (prog->globResult.gl_pathc - i); argcAlloced += (prog->globResult.gl_pathc - i);
prog->argv = realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); prog->argv =
realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
argc += (prog->globResult.gl_pathc - i - 1); argc += (prog->globResult.gl_pathc - i - 1);
@ -442,24 +463,25 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
the beginning of the next command (if the original command had more the beginning of the next command (if the original command had more
then one job associated with it) or NULL if no more commands are then one job associated with it) or NULL if no more commands are
present. */ present. */
static int parseCommand(char ** commandPtr, struct job * job, int * isBg) static int parseCommand(char **commandPtr, struct job *job, int *isBg)
{ {
char * command; char *command;
char * returnCommand = NULL; char *returnCommand = NULL;
char * src, * buf, * chptr; char *src, *buf, *chptr;
int argc = 0; int argc = 0;
int done = 0; int done = 0;
int argvAlloced; int argvAlloced;
int i; int i;
char quote = '\0'; char quote = '\0';
int count; int count;
struct childProgram * prog; struct childProgram *prog;
/* skip leading white space */ /* skip leading white space */
while (**commandPtr && isspace(**commandPtr)) (*commandPtr)++; while (**commandPtr && isspace(**commandPtr))
(*commandPtr)++;
/* this handles empty lines or leading '#' characters */ /* this handles empty lines or leading '#' characters */
if (!**commandPtr || (**commandPtr=='#')) { if (!**commandPtr || (**commandPtr == '#')) {
job->numProgs = 0; job->numProgs = 0;
*commandPtr = NULL; *commandPtr = NULL;
return 0; return 0;
@ -503,10 +525,10 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
} }
/* in shell, "\'" should yield \' */ /* in shell, "\'" should yield \' */
if (*src != quote) *buf++ = '\\'; if (*src != quote)
} else if (*src == '*' || *src == '?' || *src == '[' ||
*src == ']')
*buf++ = '\\'; *buf++ = '\\';
} else if (*src == '*' || *src == '?' || *src == '[' ||
*src == ']') *buf++ = '\\';
*buf++ = *src; *buf++ = *src;
} else if (isspace(*src)) { } else if (isspace(*src)) {
if (*prog->argv[argc]) { if (*prog->argv[argc]) {
@ -515,13 +537,15 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
if ((argc + 1) == argvAlloced) { if ((argc + 1) == argvAlloced) {
argvAlloced += 5; argvAlloced += 5;
prog->argv = realloc(prog->argv, prog->argv = realloc(prog->argv,
sizeof(*prog->argv) * argvAlloced); sizeof(*prog->argv) *
argvAlloced);
} }
prog->argv[argc] = buf; prog->argv[argc] = buf;
globLastArgument(prog, &argc, &argvAlloced); globLastArgument(prog, &argc, &argvAlloced);
} }
} else switch (*src) { } else
switch (*src) {
case '"': case '"':
case '\'': case '\'':
quote = *src; quote = *src;
@ -535,13 +559,15 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
case '<': case '<':
i = prog->numRedirections++; i = prog->numRedirections++;
prog->redirections = realloc(prog->redirections, prog->redirections = realloc(prog->redirections,
sizeof(*prog->redirections) * (i + 1)); sizeof(*prog->redirections) *
(i + 1));
prog->redirections[i].fd = -1; prog->redirections[i].fd = -1;
if (buf != prog->argv[argc]) { if (buf != prog->argv[argc]) {
/* the stuff before this character may be the file number /* the stuff before this character may be the file number
being redirected */ being redirected */
prog->redirections[i].fd = strtol(prog->argv[argc], &chptr, 10); prog->redirections[i].fd =
strtol(prog->argv[argc], &chptr, 10);
if (*chptr && *prog->argv[argc]) { if (*chptr && *prog->argv[argc]) {
buf++, argc++; buf++, argc++;
@ -558,7 +584,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
if (*src++ == '>') { if (*src++ == '>') {
if (*src == '>') if (*src == '>')
prog->redirections[i].type = REDIRECT_APPEND, src++; prog->redirections[i].type =
REDIRECT_APPEND, src++;
else else
prog->redirections[i].type = REDIRECT_OVERWRITE; prog->redirections[i].type = REDIRECT_OVERWRITE;
} else { } else {
@ -567,7 +594,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
/* This isn't POSIX sh compliant. Oh well. */ /* This isn't POSIX sh compliant. Oh well. */
chptr = src; chptr = src;
while (isspace(*chptr)) chptr++; while (isspace(*chptr))
chptr++;
if (!*chptr) { if (!*chptr) {
fprintf(stderr, "file name expected after %c\n", *src); fprintf(stderr, "file name expected after %c\n", *src);
@ -585,7 +613,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
case '|': /* pipe */ case '|': /* pipe */
/* finish this command */ /* finish this command */
if (*prog->argv[argc]) argc++; if (*prog->argv[argc])
argc++;
if (!argc) { if (!argc) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe\n");
freeJob(job); freeJob(job);
@ -608,7 +637,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
prog->argv[0] = ++buf; prog->argv[0] = ++buf;
src++; src++;
while (*src && isspace(*src)) src++; while (*src && isspace(*src))
src++;
if (!*src) { if (!*src) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe\n");
@ -632,8 +662,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
fprintf(stderr, "character expected after \\\n"); fprintf(stderr, "character expected after \\\n");
return 1; return 1;
} }
if (*src == '*' || *src == '[' || *src == ']' || *src == '?') if (*src == '*' || *src == '[' || *src == ']'
*buf++ = '\\'; || *src == '?') *buf++ = '\\';
/* fallthrough */ /* fallthrough */
default: default:
*buf++ = *src; *buf++ = *src;
@ -669,10 +699,9 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
return 0; return 0;
} }
static int runCommand(struct job newJob, struct jobSet * jobList, static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
int inBg)
{ {
struct job * job; struct job *job;
int i; int i;
int nextin, nextout; int nextin, nextout;
int pipefds[2]; /* pipefd[0] is for reading */ int pipefds[2]; /* pipefd[0] is for reading */
@ -680,9 +709,9 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
/* handle built-ins here -- we don't fork() so we can't background /* handle built-ins here -- we don't fork() so we can't background
these very easily */ these very easily */
for( x=bltins ; x->cmd ; x++) { for (x = bltins; x->cmd; x++) {
if (!strcmp(newJob.progs[0].argv[0], x->cmd)) { if (!strcmp(newJob.progs[0].argv[0], x->cmd)) {
return(x->function(&newJob, jobList)); return (x->function(&newJob, jobList));
} }
} }
@ -712,7 +741,7 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
setupRedirections(newJob.progs + i); setupRedirections(newJob.progs + i);
execvp(newJob.progs[i].argv[0], newJob.progs[i].argv); execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);
fatalError( "sh: %s: %s\n", newJob.progs[i].argv[0], fatalError("sh: %s: %s\n", newJob.progs[i].argv[0],
strerror(errno)); strerror(errno));
} }
@ -720,8 +749,10 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
first process in this pipe */ first process in this pipe */
setpgid(newJob.progs[i].pid, newJob.progs[0].pid); setpgid(newJob.progs[i].pid, newJob.progs[0].pid);
if (nextin != 0) close(nextin); if (nextin != 0)
if (nextout != 1) close(nextout); close(nextin);
if (nextout != 1)
close(nextout);
/* If there isn't another process, nextin is garbage /* If there isn't another process, nextin is garbage
but it doesn't matter */ but it doesn't matter */
@ -768,12 +799,12 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
return 0; return 0;
} }
static int setupRedirections(struct childProgram * prog) static int setupRedirections(struct childProgram *prog)
{ {
int i; int i;
int openfd; int openfd;
int mode=O_RDONLY; int mode = O_RDONLY;
struct redirectionSpecifier * redir = prog->redirections; struct redirectionSpecifier *redir = prog->redirections;
for (i = 0; i < prog->numRedirections; i++, redir++) { for (i = 0; i < prog->numRedirections; i++, redir++) {
switch (redir->type) { switch (redir->type) {
@ -809,14 +840,16 @@ static int setupRedirections(struct childProgram * prog)
static int busy_loop(FILE * input) static int busy_loop(FILE * input)
{ {
char command[MAX_COMMAND_LEN + 1]; char *command;
char * nextCommand = NULL; char *nextCommand = NULL;
struct jobSet jobList = { NULL, NULL }; struct jobSet jobList = { NULL, NULL };
struct job newJob; struct job newJob;
int i; int i;
int status; int status;
int inBg; int inBg;
command = (char*) calloc(BUFSIZ, sizeof(char));
/* don't pay any attention to this signal; it just confuses /* don't pay any attention to this signal; it just confuses
things and isn't really meant for shells anyway */ things and isn't really meant for shells anyway */
signal(SIGTTOU, SIG_IGN); signal(SIGTTOU, SIG_IGN);
@ -829,7 +862,8 @@ static int busy_loop(FILE * input)
checkJobs(&jobList); checkJobs(&jobList);
if (!nextCommand) { if (!nextCommand) {
if (getCommand(input, command)) break; if (getCommand(input, command))
break;
nextCommand = command; nextCommand = command;
} }
@ -879,17 +913,18 @@ static int busy_loop(FILE * input)
} }
} }
} }
free( command);
return 0; return 0;
} }
int shell_main(int argc, char ** argv) int shell_main(int argc, char **argv)
{ {
FILE * input = stdin; FILE *input = stdin;
if (argc > 2) { if (argc > 2) {
usage( shell_usage); usage(shell_usage);
} }
/* initialize the cwd */ /* initialize the cwd */
getcwd(cwd, sizeof(cwd)); getcwd(cwd, sizeof(cwd));
@ -900,16 +935,24 @@ int shell_main(int argc, char ** argv)
//} //}
if (argc < 2) { if (argc < 2) {
fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER,
fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); BB_BT);
fprintf(stdout,
"Enter 'help' for a list of built-in commands.\n\n");
} else { } else {
input = fopen(argv[1], "r"); input = fopen(argv[1], "r");
if (!input) if (!input)
fatalError("A: Couldn't open file '%s': %s\n", argv[1], strerror(errno)); fatalError("A: Couldn't open file '%s': %s\n", argv[1],
strerror(errno));
// else // else
// fatalError("Got it.\n"); // fatalError("Got it.\n");
//exit(shell_source(argv[1])); //exit(shell_source(argv[1]));
/* Set terminal IO to canonical mode, and save old term settings. */
#ifdef BB_FEATURE_SH_COMMAND_EDITING
cmdedit_init();
#endif
} }
return (busy_loop( input)); return (busy_loop(input));
} }

View File

@ -39,28 +39,32 @@
#include <unistd.h> #include <unistd.h>
#define MAX_COMMAND_LEN 250 /* max length of a single command #ifdef BB_FEATURE_SH_COMMAND_EDITING
string */ #include "cmdedit.h"
#endif
#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND };
enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
REDIRECT_APPEND };
struct jobSet { struct jobSet {
struct job * head; /* head of list of running jobs */ struct job *head; /* head of list of running jobs */
struct job * fg; /* current foreground job */ struct job *fg; /* current foreground job */
}; };
struct redirectionSpecifier { struct redirectionSpecifier {
enum redirectionType type; /* type of redirection */ enum redirectionType type; /* type of redirection */
int fd; /* file descriptor being redirected */ int fd; /* file descriptor being redirected */
char * filename; /* file to redirect fd to */ char *filename; /* file to redirect fd to */
}; };
struct childProgram { struct childProgram {
pid_t pid; /* 0 if exited */ pid_t pid; /* 0 if exited */
char ** argv; /* program name and arguments */ char **argv; /* program name and arguments */
int numRedirections; /* elements in redirection array */ int numRedirections; /* elements in redirection array */
struct redirectionSpecifier * redirections; /* I/O redirections */ struct redirectionSpecifier *redirections; /* I/O redirections */
glob_t globResult; /* result of parameter globbing */ glob_t globResult; /* result of parameter globbing */
int freeGlob; /* should we globfree(&globResult)? */ int freeGlob; /* should we globfree(&globResult)? */
int isStopped; /* is the program currently running? */ int isStopped; /* is the program currently running? */
@ -70,11 +74,11 @@ struct job {
int jobId; /* job number */ int jobId; /* job number */
int numProgs; /* total number of programs in job */ int numProgs; /* total number of programs in job */
int runningProgs; /* number of programs running */ int runningProgs; /* number of programs running */
char * text; /* name of job */ char *text; /* name of job */
char * cmdBuf; /* buffer various argv's point into */ char *cmdBuf; /* buffer various argv's point into */
pid_t pgrp; /* process group ID for the job */ pid_t pgrp; /* process group ID for the job */
struct childProgram * progs; /* array of programs in job */ struct childProgram *progs; /* array of programs in job */
struct job * next; /* to track background commands */ struct job *next; /* to track background commands */
int stoppedProgs; /* number of programs alive, but stopped */ int stoppedProgs; /* number of programs alive, but stopped */
}; };
@ -86,22 +90,22 @@ struct builtInCommand {
}; };
/* Some function prototypes */ /* Some function prototypes */
static int shell_cd(struct job* cmd, struct jobSet* junk); static int shell_cd(struct job *cmd, struct jobSet *junk);
static int shell_env(struct job* dummy, struct jobSet* junk); static int shell_env(struct job *dummy, struct jobSet *junk);
static int shell_exit(struct job* cmd, struct jobSet* junk); static int shell_exit(struct job *cmd, struct jobSet *junk);
static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
static int shell_help(struct job* cmd, struct jobSet* junk); static int shell_help(struct job *cmd, struct jobSet *junk);
static int shell_jobs(struct job* dummy, struct jobSet* jobList); static int shell_jobs(struct job *dummy, struct jobSet *jobList);
static int shell_pwd(struct job* dummy, struct jobSet* junk); static int shell_pwd(struct job *dummy, struct jobSet *junk);
static int shell_set(struct job* cmd, struct jobSet* junk); static int shell_set(struct job *cmd, struct jobSet *junk);
static int shell_source(struct job* cmd, struct jobSet* jobList); static int shell_source(struct job *cmd, struct jobSet *jobList);
static int shell_unset(struct job* cmd, struct jobSet* junk); static int shell_unset(struct job *cmd, struct jobSet *junk);
static void checkJobs(struct jobSet * jobList); static void checkJobs(struct jobSet *jobList);
static int getCommand(FILE * source, char * command); static int getCommand(FILE * source, char *command);
static int parseCommand(char ** commandPtr, struct job * job, int * isBg); static int parseCommand(char **commandPtr, struct job *job, int *isBg);
static int setupRedirections(struct childProgram * prog); static int setupRedirections(struct childProgram *prog);
static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); static int runCommand(struct job newJob, struct jobSet *jobList, int inBg);
static int busy_loop(FILE * input); static int busy_loop(FILE * input);
@ -109,6 +113,7 @@ static int busy_loop(FILE * input);
static struct builtInCommand bltins[] = { static struct builtInCommand bltins[] = {
{"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg}, {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg},
{"cd", "Change working directory", "cd [dir]", shell_cd}, {"cd", "Change working directory", "cd [dir]", shell_cd},
//{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo},
{"env", "Print all environment variables", "env", shell_env}, {"env", "Print all environment variables", "env", shell_env},
{"exit", "Exit from shell()", "exit", shell_exit}, {"exit", "Exit from shell()", "exit", shell_exit},
{"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
@ -116,23 +121,23 @@ static struct builtInCommand bltins[] = {
{"pwd", "Print current directory", "pwd", shell_pwd}, {"pwd", "Print current directory", "pwd", shell_pwd},
{"set", "Set environment variable", "set [VAR=value]", shell_set}, {"set", "Set environment variable", "set [VAR=value]", shell_set},
{"unset", "Unset environment variable", "unset VAR", shell_unset}, {"unset", "Unset environment variable", "unset VAR", shell_unset},
//{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo}, {".", "Source-in and run commands in a file", ". filename",
{".", "Source-in and run commands in a file", ". filename", shell_source}, shell_source},
{"help", "List shell built-in commands", "help", shell_help}, {"help", "List shell built-in commands", "help", shell_help},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
static const char shell_usage[] = static const char shell_usage[] =
"sh [FILE]...\n\n" "sh [FILE]...\n\n" "The BusyBox command interpreter (shell).\n\n";
"The BusyBox command interpreter (shell).\n\n";
static char cwd[1024]; static char cwd[1024];
static char *prompt = "# "; static char *prompt = "# ";
/* built-in 'cd <path>' handler */ /* built-in 'cd <path>' handler */
static int shell_cd(struct job* cmd, struct jobSet* junk) static int shell_cd(struct job *cmd, struct jobSet *junk)
{ {
char *newdir; char *newdir;
if (!cmd->progs[0].argv[1] == 1) if (!cmd->progs[0].argv[1] == 1)
@ -149,18 +154,18 @@ static int shell_cd(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'env' handler */ /* built-in 'env' handler */
static int shell_env(struct job* dummy, struct jobSet* junk) static int shell_env(struct job *dummy, struct jobSet *junk)
{ {
char **e; char **e;
for (e = environ ; *e ; e++) { for (e = environ; *e; e++) {
fprintf(stdout, "%s\n", *e); fprintf(stdout, "%s\n", *e);
} }
return (0); return (0);
} }
/* built-in 'exit' handler */ /* built-in 'exit' handler */
static int shell_exit(struct job* cmd, struct jobSet* junk) static int shell_exit(struct job *cmd, struct jobSet *junk)
{ {
if (!cmd->progs[0].argv[1] == 1) if (!cmd->progs[0].argv[1] == 1)
exit TRUE; exit TRUE;
@ -169,25 +174,29 @@ static int shell_exit(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'fg' and 'bg' handler */ /* built-in 'fg' and 'bg' handler */
static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
{ {
int i, jobNum; int i, jobNum;
struct job* job; struct job *job;
if (!jobList->head) {
if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
fprintf(stderr, "%s: exactly one argument is expected\n", fprintf(stderr, "%s: exactly one argument is expected\n",
cmd->progs[0].argv[0]); cmd->progs[0].argv[0]);
return FALSE; return FALSE;
} }
if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) {
fprintf(stderr, "%s: bad argument '%s'\n", fprintf(stderr, "%s: bad argument '%s'\n",
cmd->progs[0].argv[0], cmd->progs[0].argv[1]); cmd->progs[0].argv[0], cmd->progs[0].argv[1]);
return FALSE; return FALSE;
} }
} else {
job = jobList->head;
}
for (job = jobList->head; job; job = job->next) for (job = jobList->head; job; job = job->next)
if (job->jobId == jobNum) break; if (job->jobId == jobNum)
break;
if (!job) { if (!job) {
fprintf(stderr, "%s: unknown job %d\n", fprintf(stderr, "%s: unknown job %d\n",
@ -215,13 +224,13 @@ static int shell_fg_bg(struct job* cmd, struct jobSet* jobList)
} }
/* built-in 'help' handler */ /* built-in 'help' handler */
static int shell_help(struct job* cmd, struct jobSet* junk) static int shell_help(struct job *cmd, struct jobSet *junk)
{ {
struct builtInCommand *x; struct builtInCommand *x;
fprintf(stdout, "\nBuilt-in commands:\n"); fprintf(stdout, "\nBuilt-in commands:\n");
fprintf(stdout, "-------------------\n"); fprintf(stdout, "-------------------\n");
for ( x=bltins; x->cmd; x++) { for (x = bltins; x->cmd; x++) {
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
} }
fprintf(stdout, "\n\n"); fprintf(stdout, "\n\n");
@ -229,25 +238,24 @@ static int shell_help(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'jobs' handler */ /* built-in 'jobs' handler */
static int shell_jobs(struct job* dummy, struct jobSet* jobList) static int shell_jobs(struct job *dummy, struct jobSet *jobList)
{ {
struct job * job; struct job *job;
char * statusString; char *statusString;
for (job = jobList->head; job; job = job->next) { for (job = jobList->head; job; job = job->next) {
if (job->runningProgs == job->stoppedProgs) if (job->runningProgs == job->stoppedProgs)
statusString = "Stopped"; statusString = "Stopped";
else else
statusString = "Running"; statusString = "Running";
printf(JOB_STATUS_FORMAT, job->jobId, statusString, printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text);
job->text);
} }
return TRUE; return TRUE;
} }
/* built-in 'pwd' handler */ /* built-in 'pwd' handler */
static int shell_pwd(struct job* dummy, struct jobSet* junk) static int shell_pwd(struct job *dummy, struct jobSet *junk)
{ {
getcwd(cwd, sizeof(cwd)); getcwd(cwd, sizeof(cwd));
fprintf(stdout, "%s\n", cwd); fprintf(stdout, "%s\n", cwd);
@ -255,7 +263,7 @@ static int shell_pwd(struct job* dummy, struct jobSet* junk)
} }
/* built-in 'set VAR=value' handler */ /* built-in 'set VAR=value' handler */
static int shell_set(struct job* cmd, struct jobSet* junk) static int shell_set(struct job *cmd, struct jobSet *junk)
{ {
int res; int res;
@ -269,7 +277,7 @@ static int shell_set(struct job* cmd, struct jobSet* junk)
} }
/* Built-in '.' handler (read-in and execute commands from file) */ /* Built-in '.' handler (read-in and execute commands from file) */
static int shell_source(struct job* cmd, struct jobSet* junk) static int shell_source(struct job *cmd, struct jobSet *junk)
{ {
FILE *input; FILE *input;
int status; int status;
@ -279,7 +287,8 @@ static int shell_source(struct job* cmd, struct jobSet* junk)
input = fopen(cmd->progs[0].argv[1], "r"); input = fopen(cmd->progs[0].argv[1], "r");
if (!input) { if (!input) {
fprintf(stdout, "Couldn't open file '%s'\n", cmd->progs[0].argv[1]); fprintf(stdout, "Couldn't open file '%s'\n",
cmd->progs[0].argv[1]);
return FALSE; return FALSE;
} }
@ -289,7 +298,7 @@ static int shell_source(struct job* cmd, struct jobSet* junk)
} }
/* built-in 'unset VAR' handler */ /* built-in 'unset VAR' handler */
static int shell_unset(struct job* cmd, struct jobSet* junk) static int shell_unset(struct job *cmd, struct jobSet *junk)
{ {
if (!cmd->progs[0].argv[1] == 1) { if (!cmd->progs[0].argv[1] == 1) {
fprintf(stdout, "unset: parameter required.\n"); fprintf(stdout, "unset: parameter required.\n");
@ -300,31 +309,35 @@ static int shell_unset(struct job* cmd, struct jobSet* junk)
} }
/* free up all memory from a job */ /* free up all memory from a job */
static void freeJob(struct job * cmd) static void freeJob(struct job *cmd)
{ {
int i; int i;
for (i = 0; i < cmd->numProgs; i++) { for (i = 0; i < cmd->numProgs; i++) {
free(cmd->progs[i].argv); free(cmd->progs[i].argv);
if (cmd->progs[i].redirections) free(cmd->progs[i].redirections); if (cmd->progs[i].redirections)
if (cmd->progs[i].freeGlob) globfree(&cmd->progs[i].globResult); free(cmd->progs[i].redirections);
if (cmd->progs[i].freeGlob)
globfree(&cmd->progs[i].globResult);
} }
free(cmd->progs); free(cmd->progs);
if (cmd->text) free(cmd->text); if (cmd->text)
free(cmd->text);
free(cmd->cmdBuf); free(cmd->cmdBuf);
} }
/* remove a job from the jobList */ /* remove a job from the jobList */
static void removeJob(struct jobSet * jobList, struct job * job) static void removeJob(struct jobSet *jobList, struct job *job)
{ {
struct job * prevJob; struct job *prevJob;
freeJob(job); freeJob(job);
if (job == jobList->head) { if (job == jobList->head) {
jobList->head = job->next; jobList->head = job->next;
} else { } else {
prevJob = jobList->head; prevJob = jobList->head;
while (prevJob->next != job) prevJob = prevJob->next; while (prevJob->next != job)
prevJob = prevJob->next;
prevJob->next = job->next; prevJob->next = job->next;
} }
@ -333,20 +346,20 @@ static void removeJob(struct jobSet * jobList, struct job * job)
/* Checks to see if any background processes have exited -- if they /* Checks to see if any background processes have exited -- if they
have, figure out why and see if a job has completed */ have, figure out why and see if a job has completed */
static void checkJobs(struct jobSet * jobList) static void checkJobs(struct jobSet *jobList)
{ {
struct job * job; struct job *job;
pid_t childpid; pid_t childpid;
int status; int status;
int progNum=0; int progNum = 0;
while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
for (job = jobList->head; job; job = job->next) { for (job = jobList->head; job; job = job->next) {
progNum = 0; progNum = 0;
while (progNum < job->numProgs && while (progNum < job->numProgs &&
job->progs[progNum].pid != childpid) job->progs[progNum].pid != childpid) progNum++;
progNum++; if (progNum < job->numProgs)
if (progNum < job->numProgs) break; break;
} }
if (WIFEXITED(status) || WIFSIGNALED(status)) { if (WIFEXITED(status) || WIFSIGNALED(status)) {
@ -364,7 +377,8 @@ static void checkJobs(struct jobSet * jobList)
job->progs[progNum].isStopped = 1; job->progs[progNum].isStopped = 1;
if (job->stoppedProgs == job->numProgs) { if (job->stoppedProgs == job->numProgs) {
printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", job->text); printf(JOB_STATUS_FORMAT, job->jobId, "Stopped",
job->text);
} }
} }
} }
@ -373,15 +387,20 @@ static void checkJobs(struct jobSet * jobList)
perror("waitpid"); perror("waitpid");
} }
static int getCommand(FILE * source, char * command) static int getCommand(FILE * source, char *command)
{ {
if (source == stdin) { if (source == stdin) {
fprintf(stdout, "%s %s", cwd, prompt); fprintf(stdout, "BBSHELL %s %s", cwd, prompt);
fflush(stdout); fflush(stdout);
#ifdef BB_FEATURE_SH_COMMAND_EDITING
cmdedit_read_input(fileno(stdin), fileno(stdout), command);
return 0;
#endif
} }
if (!fgets(command, MAX_COMMAND_LEN, source)) { if (!fgets(command, BUFSIZ - 2, source)) {
if (source == stdin) printf("\n"); if (source == stdin)
printf("\n");
return 1; return 1;
} }
@ -391,15 +410,15 @@ static int getCommand(FILE * source, char * command)
return 0; return 0;
} }
static void globLastArgument(struct childProgram * prog, int * argcPtr, static void globLastArgument(struct childProgram *prog, int *argcPtr,
int * argcAllocedPtr) int *argcAllocedPtr)
{ {
int argc = *argcPtr; int argc = *argcPtr;
int argcAlloced = *argcAllocedPtr; int argcAlloced = *argcAllocedPtr;
int rc; int rc;
int flags; int flags;
int i; int i;
char * src, * dst; char *src, *dst;
if (argc > 1) { /* cmd->globResult is already initialized */ if (argc > 1) { /* cmd->globResult is already initialized */
flags = GLOB_APPEND; flags = GLOB_APPEND;
@ -421,13 +440,15 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
/* we need to remove whatever \ quoting is still present */ /* we need to remove whatever \ quoting is still present */
src = dst = prog->argv[argc - 1]; src = dst = prog->argv[argc - 1];
while (*src) { while (*src) {
if (*src != '\\') *dst++ = *src; if (*src != '\\')
*dst++ = *src;
src++; src++;
} }
*dst = '\0'; *dst = '\0';
} else if (!rc) { } else if (!rc) {
argcAlloced += (prog->globResult.gl_pathc - i); argcAlloced += (prog->globResult.gl_pathc - i);
prog->argv = realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); prog->argv =
realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
argc += (prog->globResult.gl_pathc - i - 1); argc += (prog->globResult.gl_pathc - i - 1);
@ -442,24 +463,25 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
the beginning of the next command (if the original command had more the beginning of the next command (if the original command had more
then one job associated with it) or NULL if no more commands are then one job associated with it) or NULL if no more commands are
present. */ present. */
static int parseCommand(char ** commandPtr, struct job * job, int * isBg) static int parseCommand(char **commandPtr, struct job *job, int *isBg)
{ {
char * command; char *command;
char * returnCommand = NULL; char *returnCommand = NULL;
char * src, * buf, * chptr; char *src, *buf, *chptr;
int argc = 0; int argc = 0;
int done = 0; int done = 0;
int argvAlloced; int argvAlloced;
int i; int i;
char quote = '\0'; char quote = '\0';
int count; int count;
struct childProgram * prog; struct childProgram *prog;
/* skip leading white space */ /* skip leading white space */
while (**commandPtr && isspace(**commandPtr)) (*commandPtr)++; while (**commandPtr && isspace(**commandPtr))
(*commandPtr)++;
/* this handles empty lines or leading '#' characters */ /* this handles empty lines or leading '#' characters */
if (!**commandPtr || (**commandPtr=='#')) { if (!**commandPtr || (**commandPtr == '#')) {
job->numProgs = 0; job->numProgs = 0;
*commandPtr = NULL; *commandPtr = NULL;
return 0; return 0;
@ -503,10 +525,10 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
} }
/* in shell, "\'" should yield \' */ /* in shell, "\'" should yield \' */
if (*src != quote) *buf++ = '\\'; if (*src != quote)
} else if (*src == '*' || *src == '?' || *src == '[' ||
*src == ']')
*buf++ = '\\'; *buf++ = '\\';
} else if (*src == '*' || *src == '?' || *src == '[' ||
*src == ']') *buf++ = '\\';
*buf++ = *src; *buf++ = *src;
} else if (isspace(*src)) { } else if (isspace(*src)) {
if (*prog->argv[argc]) { if (*prog->argv[argc]) {
@ -515,13 +537,15 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
if ((argc + 1) == argvAlloced) { if ((argc + 1) == argvAlloced) {
argvAlloced += 5; argvAlloced += 5;
prog->argv = realloc(prog->argv, prog->argv = realloc(prog->argv,
sizeof(*prog->argv) * argvAlloced); sizeof(*prog->argv) *
argvAlloced);
} }
prog->argv[argc] = buf; prog->argv[argc] = buf;
globLastArgument(prog, &argc, &argvAlloced); globLastArgument(prog, &argc, &argvAlloced);
} }
} else switch (*src) { } else
switch (*src) {
case '"': case '"':
case '\'': case '\'':
quote = *src; quote = *src;
@ -535,13 +559,15 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
case '<': case '<':
i = prog->numRedirections++; i = prog->numRedirections++;
prog->redirections = realloc(prog->redirections, prog->redirections = realloc(prog->redirections,
sizeof(*prog->redirections) * (i + 1)); sizeof(*prog->redirections) *
(i + 1));
prog->redirections[i].fd = -1; prog->redirections[i].fd = -1;
if (buf != prog->argv[argc]) { if (buf != prog->argv[argc]) {
/* the stuff before this character may be the file number /* the stuff before this character may be the file number
being redirected */ being redirected */
prog->redirections[i].fd = strtol(prog->argv[argc], &chptr, 10); prog->redirections[i].fd =
strtol(prog->argv[argc], &chptr, 10);
if (*chptr && *prog->argv[argc]) { if (*chptr && *prog->argv[argc]) {
buf++, argc++; buf++, argc++;
@ -558,7 +584,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
if (*src++ == '>') { if (*src++ == '>') {
if (*src == '>') if (*src == '>')
prog->redirections[i].type = REDIRECT_APPEND, src++; prog->redirections[i].type =
REDIRECT_APPEND, src++;
else else
prog->redirections[i].type = REDIRECT_OVERWRITE; prog->redirections[i].type = REDIRECT_OVERWRITE;
} else { } else {
@ -567,7 +594,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
/* This isn't POSIX sh compliant. Oh well. */ /* This isn't POSIX sh compliant. Oh well. */
chptr = src; chptr = src;
while (isspace(*chptr)) chptr++; while (isspace(*chptr))
chptr++;
if (!*chptr) { if (!*chptr) {
fprintf(stderr, "file name expected after %c\n", *src); fprintf(stderr, "file name expected after %c\n", *src);
@ -585,7 +613,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
case '|': /* pipe */ case '|': /* pipe */
/* finish this command */ /* finish this command */
if (*prog->argv[argc]) argc++; if (*prog->argv[argc])
argc++;
if (!argc) { if (!argc) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe\n");
freeJob(job); freeJob(job);
@ -608,7 +637,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
prog->argv[0] = ++buf; prog->argv[0] = ++buf;
src++; src++;
while (*src && isspace(*src)) src++; while (*src && isspace(*src))
src++;
if (!*src) { if (!*src) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe\n");
@ -632,8 +662,8 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
fprintf(stderr, "character expected after \\\n"); fprintf(stderr, "character expected after \\\n");
return 1; return 1;
} }
if (*src == '*' || *src == '[' || *src == ']' || *src == '?') if (*src == '*' || *src == '[' || *src == ']'
*buf++ = '\\'; || *src == '?') *buf++ = '\\';
/* fallthrough */ /* fallthrough */
default: default:
*buf++ = *src; *buf++ = *src;
@ -669,10 +699,9 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
return 0; return 0;
} }
static int runCommand(struct job newJob, struct jobSet * jobList, static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
int inBg)
{ {
struct job * job; struct job *job;
int i; int i;
int nextin, nextout; int nextin, nextout;
int pipefds[2]; /* pipefd[0] is for reading */ int pipefds[2]; /* pipefd[0] is for reading */
@ -680,9 +709,9 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
/* handle built-ins here -- we don't fork() so we can't background /* handle built-ins here -- we don't fork() so we can't background
these very easily */ these very easily */
for( x=bltins ; x->cmd ; x++) { for (x = bltins; x->cmd; x++) {
if (!strcmp(newJob.progs[0].argv[0], x->cmd)) { if (!strcmp(newJob.progs[0].argv[0], x->cmd)) {
return(x->function(&newJob, jobList)); return (x->function(&newJob, jobList));
} }
} }
@ -712,7 +741,7 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
setupRedirections(newJob.progs + i); setupRedirections(newJob.progs + i);
execvp(newJob.progs[i].argv[0], newJob.progs[i].argv); execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);
fatalError( "sh: %s: %s\n", newJob.progs[i].argv[0], fatalError("sh: %s: %s\n", newJob.progs[i].argv[0],
strerror(errno)); strerror(errno));
} }
@ -720,8 +749,10 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
first process in this pipe */ first process in this pipe */
setpgid(newJob.progs[i].pid, newJob.progs[0].pid); setpgid(newJob.progs[i].pid, newJob.progs[0].pid);
if (nextin != 0) close(nextin); if (nextin != 0)
if (nextout != 1) close(nextout); close(nextin);
if (nextout != 1)
close(nextout);
/* If there isn't another process, nextin is garbage /* If there isn't another process, nextin is garbage
but it doesn't matter */ but it doesn't matter */
@ -768,12 +799,12 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
return 0; return 0;
} }
static int setupRedirections(struct childProgram * prog) static int setupRedirections(struct childProgram *prog)
{ {
int i; int i;
int openfd; int openfd;
int mode=O_RDONLY; int mode = O_RDONLY;
struct redirectionSpecifier * redir = prog->redirections; struct redirectionSpecifier *redir = prog->redirections;
for (i = 0; i < prog->numRedirections; i++, redir++) { for (i = 0; i < prog->numRedirections; i++, redir++) {
switch (redir->type) { switch (redir->type) {
@ -809,14 +840,16 @@ static int setupRedirections(struct childProgram * prog)
static int busy_loop(FILE * input) static int busy_loop(FILE * input)
{ {
char command[MAX_COMMAND_LEN + 1]; char *command;
char * nextCommand = NULL; char *nextCommand = NULL;
struct jobSet jobList = { NULL, NULL }; struct jobSet jobList = { NULL, NULL };
struct job newJob; struct job newJob;
int i; int i;
int status; int status;
int inBg; int inBg;
command = (char*) calloc(BUFSIZ, sizeof(char));
/* don't pay any attention to this signal; it just confuses /* don't pay any attention to this signal; it just confuses
things and isn't really meant for shells anyway */ things and isn't really meant for shells anyway */
signal(SIGTTOU, SIG_IGN); signal(SIGTTOU, SIG_IGN);
@ -829,7 +862,8 @@ static int busy_loop(FILE * input)
checkJobs(&jobList); checkJobs(&jobList);
if (!nextCommand) { if (!nextCommand) {
if (getCommand(input, command)) break; if (getCommand(input, command))
break;
nextCommand = command; nextCommand = command;
} }
@ -879,17 +913,18 @@ static int busy_loop(FILE * input)
} }
} }
} }
free( command);
return 0; return 0;
} }
int shell_main(int argc, char ** argv) int shell_main(int argc, char **argv)
{ {
FILE * input = stdin; FILE *input = stdin;
if (argc > 2) { if (argc > 2) {
usage( shell_usage); usage(shell_usage);
} }
/* initialize the cwd */ /* initialize the cwd */
getcwd(cwd, sizeof(cwd)); getcwd(cwd, sizeof(cwd));
@ -900,16 +935,24 @@ int shell_main(int argc, char ** argv)
//} //}
if (argc < 2) { if (argc < 2) {
fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER,
fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); BB_BT);
fprintf(stdout,
"Enter 'help' for a list of built-in commands.\n\n");
} else { } else {
input = fopen(argv[1], "r"); input = fopen(argv[1], "r");
if (!input) if (!input)
fatalError("A: Couldn't open file '%s': %s\n", argv[1], strerror(errno)); fatalError("A: Couldn't open file '%s': %s\n", argv[1],
strerror(errno));
// else // else
// fatalError("Got it.\n"); // fatalError("Got it.\n");
//exit(shell_source(argv[1])); //exit(shell_source(argv[1]));
/* Set terminal IO to canonical mode, and save old term settings. */
#ifdef BB_FEATURE_SH_COMMAND_EDITING
cmdedit_init();
#endif
} }
return (busy_loop( input)); return (busy_loop(input));
} }

View File

@ -1247,7 +1247,7 @@ extern int device_open(char *device, int mode)
#endif /* BB_INIT BB_SYSLOGD */ #endif /* BB_INIT BB_SYSLOGD */
#if defined BB_KILLALL || defined BB_FEATURE_LINUXRC && ( defined BB_HALT || defined BB_REBOOT || defined BB_POWEROFF ) #if defined BB_FEATURE_LINUXRC && ( defined BB_HALT || defined BB_REBOOT || defined BB_POWEROFF )
#ifdef BB_FEATURE_USE_DEVPS_PATCH #ifdef BB_FEATURE_USE_DEVPS_PATCH
#include <linux/devps.h> #include <linux/devps.h>
@ -1363,7 +1363,7 @@ extern pid_t findPidByName( char* pidName)
return 0; return 0;
} }
#endif /* BB_FEATURE_USE_DEVPS_PATCH */ #endif /* BB_FEATURE_USE_DEVPS_PATCH */
#endif /* BB_INIT || BB_HALT || BB_REBOOT || BB_KILLALL || BB_POWEROFF */ #endif /* BB_INIT || BB_HALT || BB_REBOOT || BB_POWEROFF */
#if defined BB_GUNZIP \ #if defined BB_GUNZIP \
|| defined BB_GZIP \ || defined BB_GZIP \