aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Andersen <andersen@codepoet.org>2000-03-16 08:09:09 +0000
committerErik Andersen <andersen@codepoet.org>2000-03-16 08:09:09 +0000
commitd75af99529879e6cd38164fd110732052a9cdda4 (patch)
tree3a6e672d0b0d5104cc3c33f65b20fdaacd365c2e
parenta967e3c8f004d9d613e2f531a3bf7869f2e68b90 (diff)
downloadbusybox-w32-d75af99529879e6cd38164fd110732052a9cdda4.tar.gz
busybox-w32-d75af99529879e6cd38164fd110732052a9cdda4.tar.bz2
busybox-w32-d75af99529879e6cd38164fd110732052a9cdda4.zip
Major build system updates...
-Erik
-rw-r--r--Changelog5
-rw-r--r--applets/busybox.c222
-rwxr-xr-xapplets/busybox.mkll16
-rwxr-xr-xapplets/busybox.sh5
-rw-r--r--busybox.c222
-rw-r--r--busybox.def.h74
-rwxr-xr-xbusybox.mkll16
-rwxr-xr-xbusybox.sh5
-rw-r--r--internal.h10
-rw-r--r--lash.c1255
-rw-r--r--sh.c1255
-rw-r--r--shell/lash.c1255
-rw-r--r--utility.c4
13 files changed, 2282 insertions, 2062 deletions
diff --git a/Changelog b/Changelog
index c6493f8a3..d81207c9d 100644
--- a/Changelog
+++ b/Changelog
@@ -1,4 +1,8 @@
10.43 10.43
2 * Busybox now includes a shell! It currently costs 7.5 k (plus an
3 additional 2.5 k if you compile in command line editing). Handles
4 job control, has the usual set of builtins, and does everything
5 except for handling programming statements (if, while, etc...)
2 * Busybox can now work perfectly when /proc is disabled, thereby 6 * Busybox can now work perfectly when /proc is disabled, thereby
3 saving a bunch of memory (kernel /proc support is not thin). This 7 saving a bunch of memory (kernel /proc support is not thin). This
4 is done by making use of some nice kernel patches I wrote up to 8 is done by making use of some nice kernel patches I wrote up to
@@ -11,6 +15,7 @@
11 with a ram disk. Contributed by Emanuele Caratti <wiz@iol.it> 15 with a ram disk. Contributed by Emanuele Caratti <wiz@iol.it>
12 and then adjusted a bit by me. 16 and then adjusted a bit by me.
13 * Added tr and dirname from John Lombardo <john@deltanet.com> 17 * Added tr and dirname from John Lombardo <john@deltanet.com>
18 * Added echo and test (from me).
14 * tar wouldn't create directory entries that don't end in '/', 19 * tar wouldn't create directory entries that don't end in '/',
15 now it does (thanks to Avery Pennarun <apenwarr@worldvisions.ca>) 20 now it does (thanks to Avery Pennarun <apenwarr@worldvisions.ca>)
16 * Several fixes from Pavel Roskin <pavel_roskin@geocities.com>: 21 * Several fixes from Pavel Roskin <pavel_roskin@geocities.com>:
diff --git a/applets/busybox.c b/applets/busybox.c
index 9aa46eaae..7582647d5 100644
--- a/applets/busybox.c
+++ b/applets/busybox.c
@@ -34,282 +34,304 @@ int atexit(void (*__func) (void))
34void *__libc_stack_end; 34void *__libc_stack_end;
35#endif 35#endif
36 36
37
38static const struct Applet applets[] = { 37static const struct Applet applets[] = {
39 38
40#ifdef BB_BASENAME //usr/bin/basename 39#ifdef BB_BASENAME //usr/bin/basename
41 {"basename", basename_main}, 40 {"basename", basename_main, _BB_DIR_USR_BIN},
42#endif 41#endif
43#ifdef BB_BUSYBOX //bin 42#ifdef BB_BUSYBOX //bin
44 {"busybox", busybox_main}, 43 {"busybox", busybox_main, _BB_DIR_BIN},
45#endif 44#endif
46#ifdef BB_BLOCK_DEVICE //sbin 45#ifdef BB_BLOCK_DEVICE //sbin
47 {"block_device", block_device_main}, 46 {"block_device", block_device_main, _BB_DIR_SBIN},
48#endif 47#endif
49#ifdef BB_CAT //bin 48#ifdef BB_CAT //bin
50 {"cat", cat_main}, 49 {"cat", cat_main, _BB_DIR_BIN},
50#endif
51#ifdef BB_CHMOD_CHOWN_CHGRP //bin
52 {"chmod", chmod_chown_chgrp_main, _BB_DIR_BIN},
53#endif
54#ifdef BB_CHMOD_CHOWN_CHGRP //bin
55 {"chown", chmod_chown_chgrp_main, _BB_DIR_BIN},
51#endif 56#endif
52#ifdef BB_CHMOD_CHOWN_CHGRP //bin 57#ifdef BB_CHMOD_CHOWN_CHGRP //bin
53 {"chmod", chmod_chown_chgrp_main}, 58 {"chgrp", chmod_chown_chgrp_main, _BB_DIR_BIN},
54 {"chown", chmod_chown_chgrp_main},
55 {"chgrp", chmod_chown_chgrp_main},
56#endif 59#endif
57#ifdef BB_CHROOT //sbin 60#ifdef BB_CHROOT //sbin
58 {"chroot", chroot_main}, 61 {"chroot", chroot_main, _BB_DIR_SBIN},
59#endif 62#endif
60#ifdef BB_CLEAR //usr/bin 63#ifdef BB_CLEAR //usr/bin
61 {"clear", clear_main}, 64 {"clear", clear_main, _BB_DIR_USR_BIN},
62#endif 65#endif
63#ifdef BB_CHVT //usr/bin 66#ifdef BB_CHVT //usr/bin
64 {"chvt", chvt_main}, 67 {"chvt", chvt_main, _BB_DIR_USR_BIN},
65#endif 68#endif
66#ifdef BB_CP_MV //bin 69#ifdef BB_CP_MV //bin
67 {"cp", cp_mv_main}, 70 {"cp", cp_mv_main, _BB_DIR_BIN},
68 {"mv", cp_mv_main}, 71#endif
72#ifdef BB_CP_MV //bin
73 {"mv", cp_mv_main, _BB_DIR_BIN},
69#endif 74#endif
70#ifdef BB_DATE //bin 75#ifdef BB_DATE //bin
71 {"date", date_main}, 76 {"date", date_main, _BB_DIR_BIN},
72#endif 77#endif
73#ifdef BB_DD //bin 78#ifdef BB_DD //bin
74 {"dd", dd_main}, 79 {"dd", dd_main, _BB_DIR_BIN},
75#endif 80#endif
76#ifdef BB_DF //bin 81#ifdef BB_DF //bin
77 {"df", df_main}, 82 {"df", df_main, _BB_DIR_BIN},
78#endif 83#endif
79#ifdef BB_DIRNAME //usr/bin 84#ifdef BB_DIRNAME //usr/bin
80 {"dirname", dirname_main}, 85 {"dirname", dirname_main, _BB_DIR_USR_BIN},
81#endif 86#endif
82#ifdef BB_DMESG //bin 87#ifdef BB_DMESG //bin
83 {"dmesg", dmesg_main}, 88 {"dmesg", dmesg_main, _BB_DIR_BIN},
84#endif 89#endif
85#ifdef BB_DU //bin 90#ifdef BB_DU //bin
86 {"du", du_main}, 91 {"du", du_main, _BB_DIR_BIN},
87#endif 92#endif
88#ifdef BB_DUTMP //usr/sbin 93#ifdef BB_DUTMP //usr/sbin
89 {"dutmp", dutmp_main}, 94 {"dutmp", dutmp_main, _BB_DIR_USR_SBIN},
95#endif
96#ifdef BB_ECHO //bin
97 {"echo", echo_main, _BB_DIR_BIN},
90#endif 98#endif
91#ifdef BB_FBSET //usr/sbin 99#ifdef BB_FBSET //usr/sbin
92 {"fbset", fbset_main}, 100 {"fbset", fbset_main, _BB_DIR_USR_SBIN},
93#endif 101#endif
94#ifdef BB_FDFLUSH //bin 102#ifdef BB_FDFLUSH //bin
95 {"fdflush", fdflush_main}, 103 {"fdflush", fdflush_main, _BB_DIR_BIN},
96#endif 104#endif
97#ifdef BB_FIND //usr/bin 105#ifdef BB_FIND //usr/bin
98 {"find", find_main}, 106 {"find", find_main, _BB_DIR_USR_BIN},
99#endif 107#endif
100#ifdef BB_FREE //usr/bin 108#ifdef BB_FREE //usr/bin
101 {"free", free_main}, 109 {"free", free_main, _BB_DIR_USR_BIN},
102#endif 110#endif
103#ifdef BB_FREERAMDISK //sbin 111#ifdef BB_FREERAMDISK //sbin
104 {"freeramdisk", freeramdisk_main}, 112 {"freeramdisk", freeramdisk_main, _BB_DIR_SBIN},
105#endif 113#endif
106#ifdef BB_DEALLOCVT //usr/bin 114#ifdef BB_DEALLOCVT //usr/bin
107 {"deallocvt", deallocvt_main}, 115 {"deallocvt", deallocvt_main, _BB_DIR_USR_BIN},
108#endif 116#endif
109#ifdef BB_FSCK_MINIX //sbin 117#ifdef BB_FSCK_MINIX //sbin
110 {"fsck.minix", fsck_minix_main}, 118 {"fsck.minix", fsck_minix_main, _BB_DIR_SBIN},
111#endif 119#endif
112#ifdef BB_MKFS_MINIX //sbin 120#ifdef BB_MKFS_MINIX //sbin
113 {"mkfs.minix", mkfs_minix_main}, 121 {"mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN},
114#endif 122#endif
115#ifdef BB_GREP //bin 123#ifdef BB_GREP //bin
116 {"grep", grep_main}, 124 {"grep", grep_main, _BB_DIR_BIN},
117#endif 125#endif
118#ifdef BB_HALT //sbin 126#ifdef BB_HALT //sbin
119 {"halt", halt_main}, 127 {"halt", halt_main, _BB_DIR_SBIN},
120#endif 128#endif
121#ifdef BB_HEAD //bin 129#ifdef BB_HEAD //bin
122 {"head", head_main}, 130 {"head", head_main, _BB_DIR_BIN},
123#endif 131#endif
124#ifdef BB_HOSTID //usr/bin 132#ifdef BB_HOSTID //usr/bin
125 {"hostid", hostid_main}, 133 {"hostid", hostid_main, _BB_DIR_USR_BIN},
126#endif 134#endif
127#ifdef BB_HOSTNAME //bin 135#ifdef BB_HOSTNAME //bin
128 {"hostname", hostname_main}, 136 {"hostname", hostname_main, _BB_DIR_BIN},
129#endif 137#endif
130#ifdef BB_INIT //sbin 138#ifdef BB_INIT //sbin
131 {"init", init_main}, 139 {"init", init_main, _BB_DIR_SBIN},
132#endif 140#endif
133#ifdef BB_INSMOD //sbin 141#ifdef BB_INSMOD //sbin
134 {"insmod", insmod_main}, 142 {"insmod", insmod_main, _BB_DIR_SBIN},
135#endif 143#endif
136#ifdef BB_FEATURE_LINUXRC // 144#ifdef BB_FEATURE_LINUXRC //
137 {"linuxrc", init_main}, 145 {"linuxrc", init_main, _BB_DIR_ROOT},
138#endif 146#endif
139#ifdef BB_KILL //bin 147#ifdef BB_KILL //bin
140 {"kill", kill_main}, 148 {"kill", kill_main, _BB_DIR_BIN},
141#endif 149#endif
142#ifdef BB_KILLALL //usr/bin 150#ifdef BB_KILLALL //usr/bin
143 {"killall", kill_main}, 151 {"killall", kill_main, _BB_DIR_USR_BIN},
144#endif 152#endif
145#ifdef BB_LENGTH //usr/bin 153#ifdef BB_LENGTH //usr/bin
146 {"length", length_main}, 154 {"length", length_main, _BB_DIR_USR_BIN},
147#endif 155#endif
148#ifdef BB_LN //bin 156#ifdef BB_LN //bin
149 {"ln", ln_main}, 157 {"ln", ln_main, _BB_DIR_BIN},
150#endif 158#endif
151#ifdef BB_LOADACM //usr/bin 159#ifdef BB_LOADACM //usr/bin
152 {"loadacm", loadacm_main}, 160 {"loadacm", loadacm_main, _BB_DIR_USR_BIN},
153#endif 161#endif
154#ifdef BB_LOADFONT //usr/bin 162#ifdef BB_LOADFONT //usr/bin
155 {"loadfont", loadfont_main}, 163 {"loadfont", loadfont_main, _BB_DIR_USR_BIN},
156#endif 164#endif
157#ifdef BB_LOADKMAP //sbin 165#ifdef BB_LOADKMAP //sbin
158 {"loadkmap", loadkmap_main}, 166 {"loadkmap", loadkmap_main, _BB_DIR_SBIN},
159#endif 167#endif
160#ifdef BB_LS //bin 168#ifdef BB_LS //bin
161 {"ls", ls_main}, 169 {"ls", ls_main, _BB_DIR_BIN},
162#endif 170#endif
163#ifdef BB_LSMOD //sbin 171#ifdef BB_LSMOD //sbin
164 {"lsmod", lsmod_main}, 172 {"lsmod", lsmod_main, _BB_DIR_SBIN},
165#endif 173#endif
166#ifdef BB_MAKEDEVS //sbin 174#ifdef BB_MAKEDEVS //sbin
167 {"makedevs", makedevs_main}, 175 {"makedevs", makedevs_main, _BB_DIR_SBIN},
168#endif 176#endif
169#ifdef BB_MATH //usr/bin 177#ifdef BB_MATH //usr/bin
170 {"math", math_main}, 178 {"math", math_main, _BB_DIR_USR_BIN},
171#endif 179#endif
172#ifdef BB_MKDIR //bin 180#ifdef BB_MKDIR //bin
173 {"mkdir", mkdir_main}, 181 {"mkdir", mkdir_main, _BB_DIR_BIN},
174#endif 182#endif
175#ifdef BB_MKFIFO //usr/bin 183#ifdef BB_MKFIFO //usr/bin
176 {"mkfifo", mkfifo_main}, 184 {"mkfifo", mkfifo_main, _BB_DIR_USR_BIN},
177#endif 185#endif
178#ifdef BB_MKNOD //bin 186#ifdef BB_MKNOD //bin
179 {"mknod", mknod_main}, 187 {"mknod", mknod_main, _BB_DIR_BIN},
180#endif 188#endif
181#ifdef BB_MKSWAP //sbin 189#ifdef BB_MKSWAP //sbin
182 {"mkswap", mkswap_main}, 190 {"mkswap", mkswap_main, _BB_DIR_SBIN},
183#endif 191#endif
184#ifdef BB_MNC //usr/bin 192#ifdef BB_MNC //usr/bin
185 {"mnc", mnc_main}, 193 {"mnc", mnc_main, _BB_DIR_USR_BIN},
186#endif 194#endif
187#ifdef BB_MORE //bin 195#ifdef BB_MORE //bin
188 {"more", more_main}, 196 {"more", more_main, _BB_DIR_BIN},
189#endif 197#endif
190#ifdef BB_MOUNT //bin 198#ifdef BB_MOUNT //bin
191 {"mount", mount_main}, 199 {"mount", mount_main, _BB_DIR_BIN},
192#endif 200#endif
193#ifdef BB_MT //bin 201#ifdef BB_MT //bin
194 {"mt", mt_main}, 202 {"mt", mt_main, _BB_DIR_BIN},
195#endif 203#endif
196#ifdef BB_NSLOOKUP //usr/bin 204#ifdef BB_NSLOOKUP //usr/bin
197 {"nslookup", nslookup_main}, 205 {"nslookup", nslookup_main, _BB_DIR_USR_BIN},
198#endif 206#endif
199#ifdef BB_PING //bin 207#ifdef BB_PING //bin
200 {"ping", ping_main}, 208 {"ping", ping_main, _BB_DIR_BIN},
201#endif 209#endif
202#ifdef BB_POWEROFF //sbin 210#ifdef BB_POWEROFF //sbin
203 {"poweroff", poweroff_main}, 211 {"poweroff", poweroff_main, _BB_DIR_SBIN},
204#endif 212#endif
205#ifdef BB_PRINTF //usr/bin 213#ifdef BB_PRINTF //usr/bin
206 {"printf", printf_main}, 214 {"printf", printf_main, _BB_DIR_USR_BIN},
207#endif 215#endif
208#ifdef BB_PS //bin 216#ifdef BB_PS //bin
209 {"ps", ps_main}, 217 {"ps", ps_main, _BB_DIR_BIN},
210#endif 218#endif
211#ifdef BB_PWD //bin 219#ifdef BB_PWD //bin
212 {"pwd", pwd_main}, 220 {"pwd", pwd_main, _BB_DIR_BIN},
213#endif 221#endif
214#ifdef BB_REBOOT //sbin 222#ifdef BB_REBOOT //sbin
215 {"reboot", reboot_main}, 223 {"reboot", reboot_main, _BB_DIR_SBIN},
216#endif 224#endif
217#ifdef BB_RM //bin 225#ifdef BB_RM //bin
218 {"rm", rm_main}, 226 {"rm", rm_main, _BB_DIR_BIN},
219#endif 227#endif
220#ifdef BB_RMDIR //bin 228#ifdef BB_RMDIR //bin
221 {"rmdir", rmdir_main}, 229 {"rmdir", rmdir_main, _BB_DIR_BIN},
222#endif 230#endif
223#ifdef BB_RMMOD //sbin 231#ifdef BB_RMMOD //sbin
224 {"rmmod", rmmod_main}, 232 {"rmmod", rmmod_main, _BB_DIR_SBIN},
225#endif 233#endif
226#ifdef BB_SED //bin 234#ifdef BB_SED //bin
227 {"sed", sed_main}, 235 {"sed", sed_main, _BB_DIR_BIN},
228#endif 236#endif
229#ifdef BB_SH //bin 237#ifdef BB_SH //bin
230 {"sh", shell_main}, 238 {"sh", shell_main, _BB_DIR_BIN},
231#endif 239#endif
232#ifdef BB_SFDISK //sbin 240#ifdef BB_SFDISK //sbin
233 {"fdisk", sfdisk_main}, 241 {"fdisk", sfdisk_main, _BB_DIR_SBIN},
234 {"sfdisk", sfdisk_main}, 242#ifdef BB_SFDISK //sbin
243#endif
244 {"sfdisk", sfdisk_main, _BB_DIR_SBIN},
235#endif 245#endif
236#ifdef BB_SLEEP //bin 246#ifdef BB_SLEEP //bin
237 {"sleep", sleep_main}, 247 {"sleep", sleep_main, _BB_DIR_BIN},
238#endif 248#endif
239#ifdef BB_SORT //bin 249#ifdef BB_SORT //bin
240 {"sort", sort_main}, 250 {"sort", sort_main, _BB_DIR_BIN},
241#endif 251#endif
242#ifdef BB_SYNC //bin 252#ifdef BB_SYNC //bin
243 {"sync", sync_main}, 253 {"sync", sync_main, _BB_DIR_BIN},
244#endif 254#endif
245#ifdef BB_SYSLOGD //sbin 255#ifdef BB_SYSLOGD //sbin
246 {"syslogd", syslogd_main}, 256 {"syslogd", syslogd_main, _BB_DIR_SBIN},
247#endif 257#endif
248#ifdef BB_LOGGER //usr/bin 258#ifdef BB_LOGGER //usr/bin
249 {"logger", logger_main}, 259 {"logger", logger_main, _BB_DIR_USR_BIN},
250#endif 260#endif
251#ifdef BB_LOGNAME //usr/bin 261#ifdef BB_LOGNAME //usr/bin
252 {"logname", logname_main}, 262 {"logname", logname_main, _BB_DIR_USR_BIN},
263#endif
264#ifdef BB_SWAPONOFF //sbin
265 {"swapon", swap_on_off_main, _BB_DIR_SBIN},
253#endif 266#endif
254#ifdef BB_SWAPONOFF //sbin 267#ifdef BB_SWAPONOFF //sbin
255 {"swapon", swap_on_off_main}, 268 {"swapoff", swap_on_off_main, _BB_DIR_SBIN},
256 {"swapoff", swap_on_off_main},
257#endif 269#endif
258#ifdef BB_TAIL //usr/bin 270#ifdef BB_TAIL //usr/bin
259 {"tail", tail_main}, 271 {"tail", tail_main, _BB_DIR_USR_BIN},
260#endif 272#endif
261#ifdef BB_TAR //bin 273#ifdef BB_TAR //bin
262 {"tar", tar_main}, 274 {"tar", tar_main, _BB_DIR_BIN},
263#endif 275#endif
264#ifdef BB_TELNET //usr/bin 276#ifdef BB_TELNET //usr/bin
265 {"telnet", telnet_main}, 277 {"telnet", telnet_main, _BB_DIR_USR_BIN},
278#endif
279#ifdef BB_TEST //usr/bin
280 {"[", test_main, _BB_DIR_USR_BIN},
281#endif
282#ifdef BB_TEST //usr/bin
283 {"test", test_main, _BB_DIR_USR_BIN},
266#endif 284#endif
267#ifdef BB_TEE //bin 285#ifdef BB_TEE //bin
268 {"tee", tee_main}, 286 {"tee", tee_main, _BB_DIR_BIN},
269#endif 287#endif
270#ifdef BB_TOUCH //usr/bin 288#ifdef BB_TOUCH //usr/bin
271 {"touch", touch_main}, 289 {"touch", touch_main, _BB_DIR_USR_BIN},
272#endif 290#endif
273#ifdef BB_TR //usr/bin 291#ifdef BB_TR //usr/bin
274 {"tr", tr_main}, 292 {"tr", tr_main, _BB_DIR_USR_BIN},
275#endif 293#endif
276#ifdef BB_TRUE_FALSE //bin 294#ifdef BB_TRUE_FALSE //bin
277 {"true", true_main}, 295 {"true", true_main, _BB_DIR_BIN},
278 {"false", false_main}, 296#endif
297#ifdef BB_TRUE_FALSE //bin
298 {"false", false_main, _BB_DIR_BIN},
279#endif 299#endif
280#ifdef BB_TTY //usr/bin 300#ifdef BB_TTY //usr/bin
281 {"tty", tty_main}, 301 {"tty", tty_main, _BB_DIR_USR_BIN},
282#endif 302#endif
283#ifdef BB_UMOUNT //bin 303#ifdef BB_UMOUNT //bin
284 {"umount", umount_main}, 304 {"umount", umount_main, _BB_DIR_BIN},
285#endif 305#endif
286#ifdef BB_UNAME //bin 306#ifdef BB_UNAME //bin
287 {"uname", uname_main}, 307 {"uname", uname_main, _BB_DIR_BIN},
288#endif 308#endif
289#ifdef BB_UPTIME //usr/bin 309#ifdef BB_UPTIME //usr/bin
290 {"uptime", uptime_main}, 310 {"uptime", uptime_main, _BB_DIR_USR_BIN},
291#endif 311#endif
292#ifdef BB_UNIQ //bin 312#ifdef BB_UNIQ //bin
293 {"uniq", uniq_main}, 313 {"uniq", uniq_main, _BB_DIR_BIN},
294#endif 314#endif
295#ifdef BB_UPDATE //sbin 315#ifdef BB_UPDATE //sbin
296 {"update", update_main}, 316 {"update", update_main, _BB_DIR_SBIN},
297#endif 317#endif
298#ifdef BB_WC //usr/bin 318#ifdef BB_WC //usr/bin
299 {"wc", wc_main}, 319 {"wc", wc_main, _BB_DIR_USR_BIN},
300#endif 320#endif
301#ifdef BB_WHOAMI //usr/bin 321#ifdef BB_WHOAMI //usr/bin
302 {"whoami", whoami_main}, 322 {"whoami", whoami_main, _BB_DIR_USR_BIN},
303#endif 323#endif
304#ifdef BB_YES //usr/bin 324#ifdef BB_YES //usr/bin
305 {"yes", yes_main}, 325 {"yes", yes_main, _BB_DIR_USR_BIN},
326#endif
327#ifdef BB_GUNZIP //bin
328 {"zcat", gunzip_main, _BB_DIR_BIN},
306#endif 329#endif
307#ifdef BB_GUNZIP //bin 330#ifdef BB_GUNZIP //bin
308 {"zcat", gunzip_main}, 331 {"gunzip", gunzip_main, _BB_DIR_BIN},
309 {"gunzip", gunzip_main},
310#endif 332#endif
311#ifdef BB_GZIP //bin 333#ifdef BB_GZIP //bin
312 {"gzip", gzip_main}, 334 {"gzip", gzip_main, _BB_DIR_BIN},
313#endif 335#endif
314 {0} 336 {0}
315}; 337};
@@ -318,11 +340,11 @@ static const struct Applet applets[] = {
318 340
319int main(int argc, char **argv) 341int main(int argc, char **argv)
320{ 342{
321 char *s = argv[0]; 343 char *s;
322 char *name = argv[0]; 344 char *name;
323 const struct Applet *a = applets; 345 const struct Applet *a = applets;
324 346
325 while (*s != '\0') { 347 for (s = name = argv[0]; *s != '\0';) {
326 if (*s++ == '/') 348 if (*s++ == '/')
327 name = s; 349 name = s;
328 } 350 }
diff --git a/applets/busybox.mkll b/applets/busybox.mkll
index c4420f50d..fa1bff209 100755
--- a/applets/busybox.mkll
+++ b/applets/busybox.mkll
@@ -4,12 +4,16 @@
4DF="busybox.def.h" 4DF="busybox.def.h"
5MF="busybox.c" 5MF="busybox.c"
6 6
7LIST="$(sed -n '/^#define/{s/^#define //p;}' $DF)" 7LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)"
8 8
9for def in ${LIST}; do 9for def in ${LIST}; do
10 i=`sed -n 's/^#ifdef \<'$def'\>.*\/\/\(.*$\)/\/\1\//gp' $MF` 10 i=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*\(_BB_DIR_[A-Z_]*\).*$/\2\/\1/gp; }' $MF`
11 j=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*/\1/gp; }' $MF` 11 for j in $i; do
12 for k in $j; do 12 if [ -z $j ] ; then
13 echo $i$k 13 continue;
14 done 14 fi;
15 echo $j | sed -e 's/_BB_DIR_ROOT//g;s/_BB_DIR_BIN/\/bin/g;' \
16 -e 's/_BB_DIR_SBIN/\/sbin/g;s/_BB_DIR_USR_BIN/\/usr\/bin/g;' \
17 -e 's/_BB_DIR_USR_SBIN/\/usr\/sbin/g;'
18 done;
15done 19done
diff --git a/applets/busybox.sh b/applets/busybox.sh
index cab248f11..304ac87e7 100755
--- a/applets/busybox.sh
+++ b/applets/busybox.sh
@@ -1,4 +1,3 @@
1#!/bin/sh 1#!/bin/sh
2ls -1 `sed -n '/^#define/{s/.*BB_// ; s/$/.c/p; }' busybox.def.h | \ 2sed -n -e 's/^#define.*BB_FEATURE.*$//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;' \
3tr [:upper:] [:lower:]` 2> /dev/null | sed -e 's/\.c$/\.o/g' 3 -e '/^#define/{s/.*bb_//;s/$/.o/p;}' busybox.def.h
4
diff --git a/busybox.c b/busybox.c
index 9aa46eaae..7582647d5 100644
--- a/busybox.c
+++ b/busybox.c
@@ -34,282 +34,304 @@ int atexit(void (*__func) (void))
34void *__libc_stack_end; 34void *__libc_stack_end;
35#endif 35#endif
36 36
37
38static const struct Applet applets[] = { 37static const struct Applet applets[] = {
39 38
40#ifdef BB_BASENAME //usr/bin/basename 39#ifdef BB_BASENAME //usr/bin/basename
41 {"basename", basename_main}, 40 {"basename", basename_main, _BB_DIR_USR_BIN},
42#endif 41#endif
43#ifdef BB_BUSYBOX //bin 42#ifdef BB_BUSYBOX //bin
44 {"busybox", busybox_main}, 43 {"busybox", busybox_main, _BB_DIR_BIN},
45#endif 44#endif
46#ifdef BB_BLOCK_DEVICE //sbin 45#ifdef BB_BLOCK_DEVICE //sbin
47 {"block_device", block_device_main}, 46 {"block_device", block_device_main, _BB_DIR_SBIN},
48#endif 47#endif
49#ifdef BB_CAT //bin 48#ifdef BB_CAT //bin
50 {"cat", cat_main}, 49 {"cat", cat_main, _BB_DIR_BIN},
50#endif
51#ifdef BB_CHMOD_CHOWN_CHGRP //bin
52 {"chmod", chmod_chown_chgrp_main, _BB_DIR_BIN},
53#endif
54#ifdef BB_CHMOD_CHOWN_CHGRP //bin
55 {"chown", chmod_chown_chgrp_main, _BB_DIR_BIN},
51#endif 56#endif
52#ifdef BB_CHMOD_CHOWN_CHGRP //bin 57#ifdef BB_CHMOD_CHOWN_CHGRP //bin
53 {"chmod", chmod_chown_chgrp_main}, 58 {"chgrp", chmod_chown_chgrp_main, _BB_DIR_BIN},
54 {"chown", chmod_chown_chgrp_main},
55 {"chgrp", chmod_chown_chgrp_main},
56#endif 59#endif
57#ifdef BB_CHROOT //sbin 60#ifdef BB_CHROOT //sbin
58 {"chroot", chroot_main}, 61 {"chroot", chroot_main, _BB_DIR_SBIN},
59#endif 62#endif
60#ifdef BB_CLEAR //usr/bin 63#ifdef BB_CLEAR //usr/bin
61 {"clear", clear_main}, 64 {"clear", clear_main, _BB_DIR_USR_BIN},
62#endif 65#endif
63#ifdef BB_CHVT //usr/bin 66#ifdef BB_CHVT //usr/bin
64 {"chvt", chvt_main}, 67 {"chvt", chvt_main, _BB_DIR_USR_BIN},
65#endif 68#endif
66#ifdef BB_CP_MV //bin 69#ifdef BB_CP_MV //bin
67 {"cp", cp_mv_main}, 70 {"cp", cp_mv_main, _BB_DIR_BIN},
68 {"mv", cp_mv_main}, 71#endif
72#ifdef BB_CP_MV //bin
73 {"mv", cp_mv_main, _BB_DIR_BIN},
69#endif 74#endif
70#ifdef BB_DATE //bin 75#ifdef BB_DATE //bin
71 {"date", date_main}, 76 {"date", date_main, _BB_DIR_BIN},
72#endif 77#endif
73#ifdef BB_DD //bin 78#ifdef BB_DD //bin
74 {"dd", dd_main}, 79 {"dd", dd_main, _BB_DIR_BIN},
75#endif 80#endif
76#ifdef BB_DF //bin 81#ifdef BB_DF //bin
77 {"df", df_main}, 82 {"df", df_main, _BB_DIR_BIN},
78#endif 83#endif
79#ifdef BB_DIRNAME //usr/bin 84#ifdef BB_DIRNAME //usr/bin
80 {"dirname", dirname_main}, 85 {"dirname", dirname_main, _BB_DIR_USR_BIN},
81#endif 86#endif
82#ifdef BB_DMESG //bin 87#ifdef BB_DMESG //bin
83 {"dmesg", dmesg_main}, 88 {"dmesg", dmesg_main, _BB_DIR_BIN},
84#endif 89#endif
85#ifdef BB_DU //bin 90#ifdef BB_DU //bin
86 {"du", du_main}, 91 {"du", du_main, _BB_DIR_BIN},
87#endif 92#endif
88#ifdef BB_DUTMP //usr/sbin 93#ifdef BB_DUTMP //usr/sbin
89 {"dutmp", dutmp_main}, 94 {"dutmp", dutmp_main, _BB_DIR_USR_SBIN},
95#endif
96#ifdef BB_ECHO //bin
97 {"echo", echo_main, _BB_DIR_BIN},
90#endif 98#endif
91#ifdef BB_FBSET //usr/sbin 99#ifdef BB_FBSET //usr/sbin
92 {"fbset", fbset_main}, 100 {"fbset", fbset_main, _BB_DIR_USR_SBIN},
93#endif 101#endif
94#ifdef BB_FDFLUSH //bin 102#ifdef BB_FDFLUSH //bin
95 {"fdflush", fdflush_main}, 103 {"fdflush", fdflush_main, _BB_DIR_BIN},
96#endif 104#endif
97#ifdef BB_FIND //usr/bin 105#ifdef BB_FIND //usr/bin
98 {"find", find_main}, 106 {"find", find_main, _BB_DIR_USR_BIN},
99#endif 107#endif
100#ifdef BB_FREE //usr/bin 108#ifdef BB_FREE //usr/bin
101 {"free", free_main}, 109 {"free", free_main, _BB_DIR_USR_BIN},
102#endif 110#endif
103#ifdef BB_FREERAMDISK //sbin 111#ifdef BB_FREERAMDISK //sbin
104 {"freeramdisk", freeramdisk_main}, 112 {"freeramdisk", freeramdisk_main, _BB_DIR_SBIN},
105#endif 113#endif
106#ifdef BB_DEALLOCVT //usr/bin 114#ifdef BB_DEALLOCVT //usr/bin
107 {"deallocvt", deallocvt_main}, 115 {"deallocvt", deallocvt_main, _BB_DIR_USR_BIN},
108#endif 116#endif
109#ifdef BB_FSCK_MINIX //sbin 117#ifdef BB_FSCK_MINIX //sbin
110 {"fsck.minix", fsck_minix_main}, 118 {"fsck.minix", fsck_minix_main, _BB_DIR_SBIN},
111#endif 119#endif
112#ifdef BB_MKFS_MINIX //sbin 120#ifdef BB_MKFS_MINIX //sbin
113 {"mkfs.minix", mkfs_minix_main}, 121 {"mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN},
114#endif 122#endif
115#ifdef BB_GREP //bin 123#ifdef BB_GREP //bin
116 {"grep", grep_main}, 124 {"grep", grep_main, _BB_DIR_BIN},
117#endif 125#endif
118#ifdef BB_HALT //sbin 126#ifdef BB_HALT //sbin
119 {"halt", halt_main}, 127 {"halt", halt_main, _BB_DIR_SBIN},
120#endif 128#endif
121#ifdef BB_HEAD //bin 129#ifdef BB_HEAD //bin
122 {"head", head_main}, 130 {"head", head_main, _BB_DIR_BIN},
123#endif 131#endif
124#ifdef BB_HOSTID //usr/bin 132#ifdef BB_HOSTID //usr/bin
125 {"hostid", hostid_main}, 133 {"hostid", hostid_main, _BB_DIR_USR_BIN},
126#endif 134#endif
127#ifdef BB_HOSTNAME //bin 135#ifdef BB_HOSTNAME //bin
128 {"hostname", hostname_main}, 136 {"hostname", hostname_main, _BB_DIR_BIN},
129#endif 137#endif
130#ifdef BB_INIT //sbin 138#ifdef BB_INIT //sbin
131 {"init", init_main}, 139 {"init", init_main, _BB_DIR_SBIN},
132#endif 140#endif
133#ifdef BB_INSMOD //sbin 141#ifdef BB_INSMOD //sbin
134 {"insmod", insmod_main}, 142 {"insmod", insmod_main, _BB_DIR_SBIN},
135#endif 143#endif
136#ifdef BB_FEATURE_LINUXRC // 144#ifdef BB_FEATURE_LINUXRC //
137 {"linuxrc", init_main}, 145 {"linuxrc", init_main, _BB_DIR_ROOT},
138#endif 146#endif
139#ifdef BB_KILL //bin 147#ifdef BB_KILL //bin
140 {"kill", kill_main}, 148 {"kill", kill_main, _BB_DIR_BIN},
141#endif 149#endif
142#ifdef BB_KILLALL //usr/bin 150#ifdef BB_KILLALL //usr/bin
143 {"killall", kill_main}, 151 {"killall", kill_main, _BB_DIR_USR_BIN},
144#endif 152#endif
145#ifdef BB_LENGTH //usr/bin 153#ifdef BB_LENGTH //usr/bin
146 {"length", length_main}, 154 {"length", length_main, _BB_DIR_USR_BIN},
147#endif 155#endif
148#ifdef BB_LN //bin 156#ifdef BB_LN //bin
149 {"ln", ln_main}, 157 {"ln", ln_main, _BB_DIR_BIN},
150#endif 158#endif
151#ifdef BB_LOADACM //usr/bin 159#ifdef BB_LOADACM //usr/bin
152 {"loadacm", loadacm_main}, 160 {"loadacm", loadacm_main, _BB_DIR_USR_BIN},
153#endif 161#endif
154#ifdef BB_LOADFONT //usr/bin 162#ifdef BB_LOADFONT //usr/bin
155 {"loadfont", loadfont_main}, 163 {"loadfont", loadfont_main, _BB_DIR_USR_BIN},
156#endif 164#endif
157#ifdef BB_LOADKMAP //sbin 165#ifdef BB_LOADKMAP //sbin
158 {"loadkmap", loadkmap_main}, 166 {"loadkmap", loadkmap_main, _BB_DIR_SBIN},
159#endif 167#endif
160#ifdef BB_LS //bin 168#ifdef BB_LS //bin
161 {"ls", ls_main}, 169 {"ls", ls_main, _BB_DIR_BIN},
162#endif 170#endif
163#ifdef BB_LSMOD //sbin 171#ifdef BB_LSMOD //sbin
164 {"lsmod", lsmod_main}, 172 {"lsmod", lsmod_main, _BB_DIR_SBIN},
165#endif 173#endif
166#ifdef BB_MAKEDEVS //sbin 174#ifdef BB_MAKEDEVS //sbin
167 {"makedevs", makedevs_main}, 175 {"makedevs", makedevs_main, _BB_DIR_SBIN},
168#endif 176#endif
169#ifdef BB_MATH //usr/bin 177#ifdef BB_MATH //usr/bin
170 {"math", math_main}, 178 {"math", math_main, _BB_DIR_USR_BIN},
171#endif 179#endif
172#ifdef BB_MKDIR //bin 180#ifdef BB_MKDIR //bin
173 {"mkdir", mkdir_main}, 181 {"mkdir", mkdir_main, _BB_DIR_BIN},
174#endif 182#endif
175#ifdef BB_MKFIFO //usr/bin 183#ifdef BB_MKFIFO //usr/bin
176 {"mkfifo", mkfifo_main}, 184 {"mkfifo", mkfifo_main, _BB_DIR_USR_BIN},
177#endif 185#endif
178#ifdef BB_MKNOD //bin 186#ifdef BB_MKNOD //bin
179 {"mknod", mknod_main}, 187 {"mknod", mknod_main, _BB_DIR_BIN},
180#endif 188#endif
181#ifdef BB_MKSWAP //sbin 189#ifdef BB_MKSWAP //sbin
182 {"mkswap", mkswap_main}, 190 {"mkswap", mkswap_main, _BB_DIR_SBIN},
183#endif 191#endif
184#ifdef BB_MNC //usr/bin 192#ifdef BB_MNC //usr/bin
185 {"mnc", mnc_main}, 193 {"mnc", mnc_main, _BB_DIR_USR_BIN},
186#endif 194#endif
187#ifdef BB_MORE //bin 195#ifdef BB_MORE //bin
188 {"more", more_main}, 196 {"more", more_main, _BB_DIR_BIN},
189#endif 197#endif
190#ifdef BB_MOUNT //bin 198#ifdef BB_MOUNT //bin
191 {"mount", mount_main}, 199 {"mount", mount_main, _BB_DIR_BIN},
192#endif 200#endif
193#ifdef BB_MT //bin 201#ifdef BB_MT //bin
194 {"mt", mt_main}, 202 {"mt", mt_main, _BB_DIR_BIN},
195#endif 203#endif
196#ifdef BB_NSLOOKUP //usr/bin 204#ifdef BB_NSLOOKUP //usr/bin
197 {"nslookup", nslookup_main}, 205 {"nslookup", nslookup_main, _BB_DIR_USR_BIN},
198#endif 206#endif
199#ifdef BB_PING //bin 207#ifdef BB_PING //bin
200 {"ping", ping_main}, 208 {"ping", ping_main, _BB_DIR_BIN},
201#endif 209#endif
202#ifdef BB_POWEROFF //sbin 210#ifdef BB_POWEROFF //sbin
203 {"poweroff", poweroff_main}, 211 {"poweroff", poweroff_main, _BB_DIR_SBIN},
204#endif 212#endif
205#ifdef BB_PRINTF //usr/bin 213#ifdef BB_PRINTF //usr/bin
206 {"printf", printf_main}, 214 {"printf", printf_main, _BB_DIR_USR_BIN},
207#endif 215#endif
208#ifdef BB_PS //bin 216#ifdef BB_PS //bin
209 {"ps", ps_main}, 217 {"ps", ps_main, _BB_DIR_BIN},
210#endif 218#endif
211#ifdef BB_PWD //bin 219#ifdef BB_PWD //bin
212 {"pwd", pwd_main}, 220 {"pwd", pwd_main, _BB_DIR_BIN},
213#endif 221#endif
214#ifdef BB_REBOOT //sbin 222#ifdef BB_REBOOT //sbin
215 {"reboot", reboot_main}, 223 {"reboot", reboot_main, _BB_DIR_SBIN},
216#endif 224#endif
217#ifdef BB_RM //bin 225#ifdef BB_RM //bin
218 {"rm", rm_main}, 226 {"rm", rm_main, _BB_DIR_BIN},
219#endif 227#endif
220#ifdef BB_RMDIR //bin 228#ifdef BB_RMDIR //bin
221 {"rmdir", rmdir_main}, 229 {"rmdir", rmdir_main, _BB_DIR_BIN},
222#endif 230#endif
223#ifdef BB_RMMOD //sbin 231#ifdef BB_RMMOD //sbin
224 {"rmmod", rmmod_main}, 232 {"rmmod", rmmod_main, _BB_DIR_SBIN},
225#endif 233#endif
226#ifdef BB_SED //bin 234#ifdef BB_SED //bin
227 {"sed", sed_main}, 235 {"sed", sed_main, _BB_DIR_BIN},
228#endif 236#endif
229#ifdef BB_SH //bin 237#ifdef BB_SH //bin
230 {"sh", shell_main}, 238 {"sh", shell_main, _BB_DIR_BIN},
231#endif 239#endif
232#ifdef BB_SFDISK //sbin 240#ifdef BB_SFDISK //sbin
233 {"fdisk", sfdisk_main}, 241 {"fdisk", sfdisk_main, _BB_DIR_SBIN},
234 {"sfdisk", sfdisk_main}, 242#ifdef BB_SFDISK //sbin
243#endif
244 {"sfdisk", sfdisk_main, _BB_DIR_SBIN},
235#endif 245#endif
236#ifdef BB_SLEEP //bin 246#ifdef BB_SLEEP //bin
237 {"sleep", sleep_main}, 247 {"sleep", sleep_main, _BB_DIR_BIN},
238#endif 248#endif
239#ifdef BB_SORT //bin 249#ifdef BB_SORT //bin
240 {"sort", sort_main}, 250 {"sort", sort_main, _BB_DIR_BIN},
241#endif 251#endif
242#ifdef BB_SYNC //bin 252#ifdef BB_SYNC //bin
243 {"sync", sync_main}, 253 {"sync", sync_main, _BB_DIR_BIN},
244#endif 254#endif
245#ifdef BB_SYSLOGD //sbin 255#ifdef BB_SYSLOGD //sbin
246 {"syslogd", syslogd_main}, 256 {"syslogd", syslogd_main, _BB_DIR_SBIN},
247#endif 257#endif
248#ifdef BB_LOGGER //usr/bin 258#ifdef BB_LOGGER //usr/bin
249 {"logger", logger_main}, 259 {"logger", logger_main, _BB_DIR_USR_BIN},
250#endif 260#endif
251#ifdef BB_LOGNAME //usr/bin 261#ifdef BB_LOGNAME //usr/bin
252 {"logname", logname_main}, 262 {"logname", logname_main, _BB_DIR_USR_BIN},
263#endif
264#ifdef BB_SWAPONOFF //sbin
265 {"swapon", swap_on_off_main, _BB_DIR_SBIN},
253#endif 266#endif
254#ifdef BB_SWAPONOFF //sbin 267#ifdef BB_SWAPONOFF //sbin
255 {"swapon", swap_on_off_main}, 268 {"swapoff", swap_on_off_main, _BB_DIR_SBIN},
256 {"swapoff", swap_on_off_main},
257#endif 269#endif
258#ifdef BB_TAIL //usr/bin 270#ifdef BB_TAIL //usr/bin
259 {"tail", tail_main}, 271 {"tail", tail_main, _BB_DIR_USR_BIN},
260#endif 272#endif
261#ifdef BB_TAR //bin 273#ifdef BB_TAR //bin
262 {"tar", tar_main}, 274 {"tar", tar_main, _BB_DIR_BIN},
263#endif 275#endif
264#ifdef BB_TELNET //usr/bin 276#ifdef BB_TELNET //usr/bin
265 {"telnet", telnet_main}, 277 {"telnet", telnet_main, _BB_DIR_USR_BIN},
278#endif
279#ifdef BB_TEST //usr/bin
280 {"[", test_main, _BB_DIR_USR_BIN},
281#endif
282#ifdef BB_TEST //usr/bin
283 {"test", test_main, _BB_DIR_USR_BIN},
266#endif 284#endif
267#ifdef BB_TEE //bin 285#ifdef BB_TEE //bin
268 {"tee", tee_main}, 286 {"tee", tee_main, _BB_DIR_BIN},
269#endif 287#endif
270#ifdef BB_TOUCH //usr/bin 288#ifdef BB_TOUCH //usr/bin
271 {"touch", touch_main}, 289 {"touch", touch_main, _BB_DIR_USR_BIN},
272#endif 290#endif
273#ifdef BB_TR //usr/bin 291#ifdef BB_TR //usr/bin
274 {"tr", tr_main}, 292 {"tr", tr_main, _BB_DIR_USR_BIN},
275#endif 293#endif
276#ifdef BB_TRUE_FALSE //bin 294#ifdef BB_TRUE_FALSE //bin
277 {"true", true_main}, 295 {"true", true_main, _BB_DIR_BIN},
278 {"false", false_main}, 296#endif
297#ifdef BB_TRUE_FALSE //bin
298 {"false", false_main, _BB_DIR_BIN},
279#endif 299#endif
280#ifdef BB_TTY //usr/bin 300#ifdef BB_TTY //usr/bin
281 {"tty", tty_main}, 301 {"tty", tty_main, _BB_DIR_USR_BIN},
282#endif 302#endif
283#ifdef BB_UMOUNT //bin 303#ifdef BB_UMOUNT //bin
284 {"umount", umount_main}, 304 {"umount", umount_main, _BB_DIR_BIN},
285#endif 305#endif
286#ifdef BB_UNAME //bin 306#ifdef BB_UNAME //bin
287 {"uname", uname_main}, 307 {"uname", uname_main, _BB_DIR_BIN},
288#endif 308#endif
289#ifdef BB_UPTIME //usr/bin 309#ifdef BB_UPTIME //usr/bin
290 {"uptime", uptime_main}, 310 {"uptime", uptime_main, _BB_DIR_USR_BIN},
291#endif 311#endif
292#ifdef BB_UNIQ //bin 312#ifdef BB_UNIQ //bin
293 {"uniq", uniq_main}, 313 {"uniq", uniq_main, _BB_DIR_BIN},
294#endif 314#endif
295#ifdef BB_UPDATE //sbin 315#ifdef BB_UPDATE //sbin
296 {"update", update_main}, 316 {"update", update_main, _BB_DIR_SBIN},
297#endif 317#endif
298#ifdef BB_WC //usr/bin 318#ifdef BB_WC //usr/bin
299 {"wc", wc_main}, 319 {"wc", wc_main, _BB_DIR_USR_BIN},
300#endif 320#endif
301#ifdef BB_WHOAMI //usr/bin 321#ifdef BB_WHOAMI //usr/bin
302 {"whoami", whoami_main}, 322 {"whoami", whoami_main, _BB_DIR_USR_BIN},
303#endif 323#endif
304#ifdef BB_YES //usr/bin 324#ifdef BB_YES //usr/bin
305 {"yes", yes_main}, 325 {"yes", yes_main, _BB_DIR_USR_BIN},
326#endif
327#ifdef BB_GUNZIP //bin
328 {"zcat", gunzip_main, _BB_DIR_BIN},
306#endif 329#endif
307#ifdef BB_GUNZIP //bin 330#ifdef BB_GUNZIP //bin
308 {"zcat", gunzip_main}, 331 {"gunzip", gunzip_main, _BB_DIR_BIN},
309 {"gunzip", gunzip_main},
310#endif 332#endif
311#ifdef BB_GZIP //bin 333#ifdef BB_GZIP //bin
312 {"gzip", gzip_main}, 334 {"gzip", gzip_main, _BB_DIR_BIN},
313#endif 335#endif
314 {0} 336 {0}
315}; 337};
@@ -318,11 +340,11 @@ static const struct Applet applets[] = {
318 340
319int main(int argc, char **argv) 341int main(int argc, char **argv)
320{ 342{
321 char *s = argv[0]; 343 char *s;
322 char *name = argv[0]; 344 char *name;
323 const struct Applet *a = applets; 345 const struct Applet *a = applets;
324 346
325 while (*s != '\0') { 347 for (s = name = argv[0]; *s != '\0';) {
326 if (*s++ == '/') 348 if (*s++ == '/')
327 name = s; 349 name = s;
328 } 350 }
diff --git a/busybox.def.h b/busybox.def.h
index 0caa57380..d78a0efe8 100644
--- a/busybox.def.h
+++ b/busybox.def.h
@@ -22,13 +22,14 @@
22#define BB_DMESG 22#define BB_DMESG
23//#define BB_DUTMP 23//#define BB_DUTMP
24#define BB_DU 24#define BB_DU
25#define BB_FBSET 25#define BB_ECHO
26//#define BB_FBSET
26//#define BB_FDFLUSH 27//#define BB_FDFLUSH
27#define BB_FIND 28#define BB_FIND
28#define BB_FREE 29#define BB_FREE
29#define BB_FREERAMDISK 30//#define BB_FREERAMDISK
30#define BB_FSCK_MINIX 31//#define BB_FSCK_MINIX
31#define BB_GREP 32//#define BB_GREP
32#define BB_GUNZIP 33#define BB_GUNZIP
33#define BB_GZIP 34#define BB_GZIP
34//#define BB_HALT 35//#define BB_HALT
@@ -36,12 +37,9 @@
36//#define BB_HOSTID 37//#define BB_HOSTID
37#define BB_HOSTNAME 38#define BB_HOSTNAME
38#define BB_INIT 39#define BB_INIT
39// Don't turn BB_INSMOD on. It doesn't work. 40// Don't bother turning BB_INSMOD on. It doesn't work.
40//#define BB_INSMOD 41//#define BB_INSMOD
41#define BB_KILL 42#define BB_KILL
42#ifdef BB_KILL
43#define BB_KILLALL
44#endif
45#define BB_KLOGD 43#define BB_KLOGD
46//#define BB_LENGTH 44//#define BB_LENGTH
47#define BB_LN 45#define BB_LN
@@ -53,7 +51,7 @@
53#define BB_LS 51#define BB_LS
54//#define BB_LSMOD 52//#define BB_LSMOD
55//#define BB_MAKEDEVS 53//#define BB_MAKEDEVS
56#define BB_MKFS_MINIX 54//#define BB_MKFS_MINIX
57//#define BB_MATH 55//#define BB_MATH
58#define BB_MKDIR 56#define BB_MKDIR
59//#define BB_MKFIFO 57//#define BB_MKFIFO
@@ -62,7 +60,7 @@
62//#define BB_MNC 60//#define BB_MNC
63#define BB_MORE 61#define BB_MORE
64#define BB_MOUNT 62#define BB_MOUNT
65#define BB_NFSMOUNT 63//#define BB_NFSMOUNT
66//#define BB_MT 64//#define BB_MT
67#define BB_NSLOOKUP 65#define BB_NSLOOKUP
68#define BB_PING 66#define BB_PING
@@ -71,7 +69,6 @@
71#define BB_PS 69#define BB_PS
72#define BB_PWD 70#define BB_PWD
73#define BB_REBOOT 71#define BB_REBOOT
74#define BB_REGEXP
75#define BB_RM 72#define BB_RM
76#define BB_RMDIR 73#define BB_RMDIR
77//#define BB_RMMOD 74//#define BB_RMMOD
@@ -86,6 +83,7 @@
86#define BB_TAIL 83#define BB_TAIL
87#define BB_TAR 84#define BB_TAR
88#define BB_TEE 85#define BB_TEE
86#define BB_TEST
89// Don't turn BB_TELNET on. It doesn't work. 87// Don't turn BB_TELNET on. It doesn't work.
90#define BB_TELNET 88#define BB_TELNET
91#define BB_TOUCH 89#define BB_TOUCH
@@ -104,7 +102,7 @@
104// 102//
105// 103//
106// 104//
107// 105// ---------------------------------------------------------
108// This is where feature definitions go. Generally speaking, 106// This is where feature definitions go. Generally speaking,
109// turning this stuff off makes things a bit smaller (and less 107// turning this stuff off makes things a bit smaller (and less
110// pretty/useful). 108// pretty/useful).
@@ -117,10 +115,10 @@
117// You can't use this and USE_PROCFS at the same time... 115// You can't use this and USE_PROCFS at the same time...
118//#define BB_FEATURE_USE_DEVPS_PATCH 116//#define BB_FEATURE_USE_DEVPS_PATCH
119// 117//
120//
121// enable features that use the /proc filesystem (apps that 118// enable features that use the /proc filesystem (apps that
122// break without this will tell you on compile)... 119// break without this will tell you on compile)...
123// You can't use this and DEVPS_N_DEVMTAB at the same time... 120// You can't use this and BB_FEATURE_USE_DEVPS_PATCH
121// at the same time...
124#define BB_FEATURE_USE_PROCFS 122#define BB_FEATURE_USE_PROCFS
125// 123//
126// Use termios to manipulate the screen ('more' is prettier with this on) 124// Use termios to manipulate the screen ('more' is prettier with this on)
@@ -130,24 +128,23 @@
130#define BB_FEATURE_AUTOWIDTH 128#define BB_FEATURE_AUTOWIDTH
131// 129//
132// show username/groupnames (bypasses libc6 NSS) for ls 130// show username/groupnames (bypasses libc6 NSS) for ls
133#define BB_FEATURE_LS_USERNAME 131#define BB_FEATURE_LS_USERNAME
134// 132//
135// show file timestamps in ls 133// show file timestamps in ls
136#define BB_FEATURE_LS_TIMESTAMPS 134#define BB_FEATURE_LS_TIMESTAMPS
137// 135//
138// enable ls -p and -F 136// enable ls -p and -F
139#define BB_FEATURE_LS_FILETYPES 137#define BB_FEATURE_LS_FILETYPES
140// 138//
141// Change ping implementation -- simplified, featureless, but really small. 139// Change ping implementation -- simplified, featureless, but really small.
142//#define BB_SIMPLE_PING 140//#define BB_SIMPLE_PING
143//// 141//
144// Make init use a simplified /etc/inittab file (recommended). 142// Make init use a simplified /etc/inittab file (recommended).
145#define BB_FEATURE_USE_INITTAB 143#define BB_FEATURE_USE_INITTAB
146// 144//
147//Enable init being called as /linuxrc 145//Enable init being called as /linuxrc
148//#define BB_FEATURE_LINUXRC 146//#define BB_FEATURE_LINUXRC
149// 147//
150//
151//Simple tail implementation (2k vs 6k for the full one). Still 148//Simple tail implementation (2k vs 6k for the full one). Still
152//provides 'tail -f' support -- but for only one file at a time. 149//provides 'tail -f' support -- but for only one file at a time.
153#define BB_FEATURE_SIMPLE_TAIL 150#define BB_FEATURE_SIMPLE_TAIL
@@ -156,9 +153,7 @@
156#define BB_FEATURE_MOUNT_LOOP 153#define BB_FEATURE_MOUNT_LOOP
157// 154//
158// Enable support for a real /etc/mtab file instead of /proc/mounts 155// Enable support for a real /etc/mtab file instead of /proc/mounts
159#ifdef BB_MOUNT 156//#define BB_FEATURE_MOUNT_MTAB_SUPPORT
160//#define BB_MTAB
161#endif
162// 157//
163// 158//
164// Enable support for remounting filesystems 159// Enable support for remounting filesystems
@@ -173,10 +168,41 @@
173// Allow init to permenently chroot, and umount the old root fs 168// Allow init to permenently chroot, and umount the old root fs
174// just like an initrd does. Requires a kernel patch by Werner Almesberger. 169// just like an initrd does. Requires a kernel patch by Werner Almesberger.
175// ftp://icaftp.epfl.ch/pub/people/almesber/misc/umount-root-*.tar.gz 170// ftp://icaftp.epfl.ch/pub/people/almesber/misc/umount-root-*.tar.gz
176#ifdef BB_MOUNT
177//#define BB_FEATURE_INIT_CHROOT 171//#define BB_FEATURE_INIT_CHROOT
178#endif
179// 172//
180//Make sure nothing is printed to the console on boot 173//Make sure nothing is printed to the console on boot
181#define BB_FEATURE_EXTRA_QUIET 174#define BB_FEATURE_EXTRA_QUIET
182 175//
176// Enable full regular expressions. This adds about
177// 4k. When this is off, things that would normally
178// use regualr expressions (like grep) will just use
179// normal strings.
180#define BB_FEATURE_FULL_REGULAR_EXPRESSIONS
181//
182//
183// Enable command line editing in the shell
184#define BB_FEATURE_SH_COMMAND_EDITING
185//
186//
187// End of Features List
188//
189//
190//
191//
192//
193//
194//---------------------------------------------------
195// Nothing beyond this point should ever be touched by
196// mere mortals so leave this stuff alone.
197#ifdef BB_FEATURE_MOUNT_MTAB_SUPPORT
198#define BB_MTAB
199#endif
200//
201#ifdef BB_FEATURE_FULL_REGULAR_EXPRESSIONS
202#define BB_REGEXP
203#endif
204//
205#ifdef BB_FEATURE_SH_COMMAND_EDITING
206#define BB_CMDEDIT
207#endif
208//
diff --git a/busybox.mkll b/busybox.mkll
index c4420f50d..fa1bff209 100755
--- a/busybox.mkll
+++ b/busybox.mkll
@@ -4,12 +4,16 @@
4DF="busybox.def.h" 4DF="busybox.def.h"
5MF="busybox.c" 5MF="busybox.c"
6 6
7LIST="$(sed -n '/^#define/{s/^#define //p;}' $DF)" 7LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)"
8 8
9for def in ${LIST}; do 9for def in ${LIST}; do
10 i=`sed -n 's/^#ifdef \<'$def'\>.*\/\/\(.*$\)/\/\1\//gp' $MF` 10 i=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*\(_BB_DIR_[A-Z_]*\).*$/\2\/\1/gp; }' $MF`
11 j=`sed -n '/^#ifdef \<'$def'\>.*/,/^#endif/{ s/.*\"\(.*\)\".*/\1/gp; }' $MF` 11 for j in $i; do
12 for k in $j; do 12 if [ -z $j ] ; then
13 echo $i$k 13 continue;
14 done 14 fi;
15 echo $j | sed -e 's/_BB_DIR_ROOT//g;s/_BB_DIR_BIN/\/bin/g;' \
16 -e 's/_BB_DIR_SBIN/\/sbin/g;s/_BB_DIR_USR_BIN/\/usr\/bin/g;' \
17 -e 's/_BB_DIR_USR_SBIN/\/usr\/sbin/g;'
18 done;
15done 19done
diff --git a/busybox.sh b/busybox.sh
index cab248f11..304ac87e7 100755
--- a/busybox.sh
+++ b/busybox.sh
@@ -1,4 +1,3 @@
1#!/bin/sh 1#!/bin/sh
2ls -1 `sed -n '/^#define/{s/.*BB_// ; s/$/.c/p; }' busybox.def.h | \ 2sed -n -e 's/^#define.*BB_FEATURE.*$//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;' \
3tr [:upper:] [:lower:]` 2> /dev/null | sed -e 's/\.c$/\.o/g' 3 -e '/^#define/{s/.*bb_//;s/$/.o/p;}' busybox.def.h
4
diff --git a/internal.h b/internal.h
index e96eebba9..c91d3b19d 100644
--- a/internal.h
+++ b/internal.h
@@ -51,10 +51,18 @@
51#define isOctal(ch) (((ch) >= '0') && ((ch) <= '7')) 51#define isOctal(ch) (((ch) >= '0') && ((ch) <= '7'))
52#define isWildCard(ch) (((ch) == '*') || ((ch) == '?') || ((ch) == '[')) 52#define isWildCard(ch) (((ch) == '*') || ((ch) == '?') || ((ch) == '['))
53 53
54enum Location {
55 _BB_DIR_ROOT = 0,
56 _BB_DIR_BIN,
57 _BB_DIR_SBIN,
58 _BB_DIR_USR_BIN,
59 _BB_DIR_USR_SBIN
60};
54 61
55struct Applet { 62struct Applet {
56 const char* name; 63 const char* name;
57 int (*main)(int argc, char** argv); 64 int (*main)(int argc, char** argv);
65 enum Location location;
58}; 66};
59 67
60extern int basename_main(int argc, char **argv); 68extern int basename_main(int argc, char **argv);
@@ -74,6 +82,7 @@ extern int df_main(int argc, char** argv);
74extern int dmesg_main(int argc, char** argv); 82extern int dmesg_main(int argc, char** argv);
75extern int du_main(int argc, char** argv); 83extern int du_main(int argc, char** argv);
76extern int dutmp_main(int argc, char** argv); 84extern int dutmp_main(int argc, char** argv);
85extern int echo_main(int argc, char** argv);
77extern int false_main(int argc, char** argv); 86extern int false_main(int argc, char** argv);
78extern int fbset_main(int argc, char** argv); 87extern int fbset_main(int argc, char** argv);
79extern int fdisk_main(int argc, char** argv); 88extern int fdisk_main(int argc, char** argv);
@@ -134,6 +143,7 @@ extern int syslogd_main(int argc, char **argv);
134extern int tail_main(int argc, char** argv); 143extern int tail_main(int argc, char** argv);
135extern int tar_main(int argc, char** argv); 144extern int tar_main(int argc, char** argv);
136extern int tee_main(int argc, char** argv); 145extern int tee_main(int argc, char** argv);
146extern int test_main(int argc, char** argv);
137extern int telnet_main(int argc, char** argv); 147extern int telnet_main(int argc, char** argv);
138extern int touch_main(int argc, char** argv); 148extern int touch_main(int argc, char** argv);
139extern int tr_main(int argc, char** argv); 149extern int tr_main(int argc, char** argv);
diff --git a/lash.c b/lash.c
index 9e467dc54..498f43779 100644
--- a/lash.c
+++ b/lash.c
@@ -39,293 +39,306 @@
39#include <unistd.h> 39#include <unistd.h>
40 40
41 41
42#define MAX_COMMAND_LEN 250 /* max length of a single command 42#ifdef BB_FEATURE_SH_COMMAND_EDITING
43 string */ 43#include "cmdedit.h"
44#endif
45
44#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 46#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
45 47
46enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND }; 48
49enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
50 REDIRECT_APPEND };
47 51
48struct jobSet { 52struct jobSet {
49 struct job * head; /* head of list of running jobs */ 53 struct job *head; /* head of list of running jobs */
50 struct job * fg; /* current foreground job */ 54 struct job *fg; /* current foreground job */
51}; 55};
52 56
53struct redirectionSpecifier { 57struct redirectionSpecifier {
54 enum redirectionType type; /* type of redirection */ 58 enum redirectionType type; /* type of redirection */
55 int fd; /* file descriptor being redirected */ 59 int fd; /* file descriptor being redirected */
56 char * filename; /* file to redirect fd to */ 60 char *filename; /* file to redirect fd to */
57}; 61};
58 62
59struct childProgram { 63struct childProgram {
60 pid_t pid; /* 0 if exited */ 64 pid_t pid; /* 0 if exited */
61 char ** argv; /* program name and arguments */ 65 char **argv; /* program name and arguments */
62 int numRedirections; /* elements in redirection array */ 66 int numRedirections; /* elements in redirection array */
63 struct redirectionSpecifier * redirections; /* I/O redirections */ 67 struct redirectionSpecifier *redirections; /* I/O redirections */
64 glob_t globResult; /* result of parameter globbing */ 68 glob_t globResult; /* result of parameter globbing */
65 int freeGlob; /* should we globfree(&globResult)? */ 69 int freeGlob; /* should we globfree(&globResult)? */
66 int isStopped; /* is the program currently running? */ 70 int isStopped; /* is the program currently running? */
67}; 71};
68 72
69struct job { 73struct job {
70 int jobId; /* job number */ 74 int jobId; /* job number */
71 int numProgs; /* total number of programs in job */ 75 int numProgs; /* total number of programs in job */
72 int runningProgs; /* number of programs running */ 76 int runningProgs; /* number of programs running */
73 char * text; /* name of job */ 77 char *text; /* name of job */
74 char * cmdBuf; /* buffer various argv's point into */ 78 char *cmdBuf; /* buffer various argv's point into */
75 pid_t pgrp; /* process group ID for the job */ 79 pid_t pgrp; /* process group ID for the job */
76 struct childProgram * progs; /* array of programs in job */ 80 struct childProgram *progs; /* array of programs in job */
77 struct job * next; /* to track background commands */ 81 struct job *next; /* to track background commands */
78 int stoppedProgs; /* number of programs alive, but stopped */ 82 int stoppedProgs; /* number of programs alive, but stopped */
79}; 83};
80 84
81struct builtInCommand { 85struct builtInCommand {
82 char *cmd; /* name */ 86 char *cmd; /* name */
83 char *descr; /* description */ 87 char *descr; /* description */
84 char *usage; /* usage */ 88 char *usage; /* usage */
85 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ 89 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
86}; 90};
87 91
88/* Some function prototypes */ 92/* Some function prototypes */
89static int shell_cd(struct job* cmd, struct jobSet* junk); 93static int shell_cd(struct job *cmd, struct jobSet *junk);
90static int shell_env(struct job* dummy, struct jobSet* junk); 94static int shell_env(struct job *dummy, struct jobSet *junk);
91static int shell_exit(struct job* cmd, struct jobSet* junk); 95static int shell_exit(struct job *cmd, struct jobSet *junk);
92static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); 96static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
93static int shell_help(struct job* cmd, struct jobSet* junk); 97static int shell_help(struct job *cmd, struct jobSet *junk);
94static int shell_jobs(struct job* dummy, struct jobSet* jobList); 98static int shell_jobs(struct job *dummy, struct jobSet *jobList);
95static int shell_pwd(struct job* dummy, struct jobSet* junk); 99static int shell_pwd(struct job *dummy, struct jobSet *junk);
96static int shell_set(struct job* cmd, struct jobSet* junk); 100static int shell_set(struct job *cmd, struct jobSet *junk);
97static int shell_source(struct job* cmd, struct jobSet* jobList); 101static int shell_source(struct job *cmd, struct jobSet *jobList);
98static int shell_unset(struct job* cmd, struct jobSet* junk); 102static int shell_unset(struct job *cmd, struct jobSet *junk);
99 103
100static void checkJobs(struct jobSet * jobList); 104static void checkJobs(struct jobSet *jobList);
101static int getCommand(FILE * source, char * command); 105static int getCommand(FILE * source, char *command);
102static int parseCommand(char ** commandPtr, struct job * job, int * isBg); 106static int parseCommand(char **commandPtr, struct job *job, int *isBg);
103static int setupRedirections(struct childProgram * prog); 107static int setupRedirections(struct childProgram *prog);
104static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); 108static int runCommand(struct job newJob, struct jobSet *jobList, int inBg);
105static int busy_loop(FILE * input); 109static int busy_loop(FILE * input);
106 110
107 111
108/* Table of built-in functions */ 112/* Table of built-in functions */
109static struct builtInCommand bltins[] = { 113static struct builtInCommand bltins[] = {
110 {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg}, 114 {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg},
111 {"cd", "Change working directory", "cd [dir]", shell_cd}, 115 {"cd", "Change working directory", "cd [dir]", shell_cd},
112 {"env", "Print all environment variables", "env", shell_env}, 116 //{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo},
113 {"exit", "Exit from shell()", "exit", shell_exit}, 117 {"env", "Print all environment variables", "env", shell_env},
114 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, 118 {"exit", "Exit from shell()", "exit", shell_exit},
115 {"jobs", "Lists the active jobs", "jobs", shell_jobs}, 119 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
116 {"pwd", "Print current directory", "pwd", shell_pwd}, 120 {"jobs", "Lists the active jobs", "jobs", shell_jobs},
117 {"set", "Set environment variable", "set [VAR=value]", shell_set}, 121 {"pwd", "Print current directory", "pwd", shell_pwd},
118 {"unset", "Unset environment variable", "unset VAR", shell_unset}, 122 {"set", "Set environment variable", "set [VAR=value]", shell_set},
119 //{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo}, 123 {"unset", "Unset environment variable", "unset VAR", shell_unset},
120 {".", "Source-in and run commands in a file", ". filename", shell_source}, 124 {".", "Source-in and run commands in a file", ". filename",
121 {"help", "List shell built-in commands", "help", shell_help}, 125 shell_source},
122 {NULL, NULL, NULL, NULL} 126 {"help", "List shell built-in commands", "help", shell_help},
127 {NULL, NULL, NULL, NULL}
123}; 128};
124 129
125static const char shell_usage[] = 130static const char shell_usage[] =
126 "sh [FILE]...\n\n" 131 "sh [FILE]...\n\n" "The BusyBox command interpreter (shell).\n\n";
127 "The BusyBox command interpreter (shell).\n\n";
128 132
129 133
130static char cwd[1024]; 134static char cwd[1024];
131static char *prompt = "# "; 135static char *prompt = "# ";
132 136
133 137
138
134/* built-in 'cd <path>' handler */ 139/* built-in 'cd <path>' handler */
135static int shell_cd(struct job* cmd, struct jobSet* junk) 140static int shell_cd(struct job *cmd, struct jobSet *junk)
136{ 141{
137 char *newdir; 142 char *newdir;
138 if (!cmd->progs[0].argv[1] == 1) 143 if (!cmd->progs[0].argv[1] == 1)
139 newdir = getenv("HOME"); 144 newdir = getenv("HOME");
140 else 145 else
141 newdir = cmd->progs[0].argv[1]; 146 newdir = cmd->progs[0].argv[1];
142 if (chdir(newdir)) { 147 if (chdir(newdir)) {
143 printf("cd: %s: %s\n", newdir, strerror(errno)); 148 printf("cd: %s: %s\n", newdir, strerror(errno));
144 return FALSE; 149 return FALSE;
145 } 150 }
146 getcwd(cwd, sizeof(cwd)); 151 getcwd(cwd, sizeof(cwd));
147 152
148 return TRUE; 153 return TRUE;
149} 154}
150 155
151/* built-in 'env' handler */ 156/* built-in 'env' handler */
152static int shell_env(struct job* dummy, struct jobSet* junk) 157static int shell_env(struct job *dummy, struct jobSet *junk)
153{ 158{
154 char **e; 159 char **e;
155 160
156 for (e = environ ; *e ; e++) { 161 for (e = environ; *e; e++) {
157 fprintf(stdout, "%s\n", *e); 162 fprintf(stdout, "%s\n", *e);
158 } 163 }
159 return (0); 164 return (0);
160} 165}
161 166
162/* built-in 'exit' handler */ 167/* built-in 'exit' handler */
163static int shell_exit(struct job* cmd, struct jobSet* junk) 168static int shell_exit(struct job *cmd, struct jobSet *junk)
164{ 169{
165 if (!cmd->progs[0].argv[1] == 1) 170 if (!cmd->progs[0].argv[1] == 1)
166 exit TRUE; 171 exit TRUE;
167 else 172 else
168 exit(atoi(cmd->progs[0].argv[1])); 173 exit(atoi(cmd->progs[0].argv[1]));
169} 174}
170 175
171/* built-in 'fg' and 'bg' handler */ 176/* built-in 'fg' and 'bg' handler */
172static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) 177static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
173{ 178{
174 int i, jobNum; 179 int i, jobNum;
175 struct job* job; 180 struct job *job;
176 181
177 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { 182 if (!jobList->head) {
178 fprintf(stderr, "%s: exactly one argument is expected\n", 183 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
179 cmd->progs[0].argv[0]); 184 fprintf(stderr, "%s: exactly one argument is expected\n",
180 return FALSE; 185 cmd->progs[0].argv[0]);
181 } 186 return FALSE;
182 187 }
183 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { 188 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) {
184 fprintf(stderr, "%s: bad argument '%s'\n", 189 fprintf(stderr, "%s: bad argument '%s'\n",
185 cmd->progs[0].argv[0], cmd->progs[0].argv[1]); 190 cmd->progs[0].argv[0], cmd->progs[0].argv[1]);
186 return FALSE; 191 return FALSE;
187 } 192 }
188 193 } else {
189 for (job = jobList->head; job; job = job->next) 194 job = jobList->head;
190 if (job->jobId == jobNum) break; 195 }
191 196
192 if (!job) { 197 for (job = jobList->head; job; job = job->next)
193 fprintf(stderr, "%s: unknown job %d\n", 198 if (job->jobId == jobNum)
194 cmd->progs[0].argv[0], jobNum); 199 break;
195 return FALSE; 200
196 } 201 if (!job) {
197 202 fprintf(stderr, "%s: unknown job %d\n",
198 if (*cmd->progs[0].argv[0] == 'f') { 203 cmd->progs[0].argv[0], jobNum);
199 /* Make this job the foreground job */ 204 return FALSE;
200 205 }
201 if (tcsetpgrp(0, job->pgrp)) 206
202 perror("tcsetpgrp"); 207 if (*cmd->progs[0].argv[0] == 'f') {
203 jobList->fg = job; 208 /* Make this job the foreground job */
204 } 209
205 210 if (tcsetpgrp(0, job->pgrp))
206 /* Restart the processes in the job */ 211 perror("tcsetpgrp");
207 for (i = 0; i < job->numProgs; i++) 212 jobList->fg = job;
208 job->progs[i].isStopped = 0; 213 }
209 214
210 kill(-job->pgrp, SIGCONT); 215 /* Restart the processes in the job */
211 216 for (i = 0; i < job->numProgs; i++)
212 job->stoppedProgs = 0; 217 job->progs[i].isStopped = 0;
213 218
214 return TRUE; 219 kill(-job->pgrp, SIGCONT);
220
221 job->stoppedProgs = 0;
222
223 return TRUE;
215} 224}
216 225
217/* built-in 'help' handler */ 226/* built-in 'help' handler */
218static int shell_help(struct job* cmd, struct jobSet* junk) 227static int shell_help(struct job *cmd, struct jobSet *junk)
219{ 228{
220 struct builtInCommand *x; 229 struct builtInCommand *x;
221 230
222 fprintf(stdout, "\nBuilt-in commands:\n"); 231 fprintf(stdout, "\nBuilt-in commands:\n");
223 fprintf(stdout, "-------------------\n"); 232 fprintf(stdout, "-------------------\n");
224 for ( x=bltins; x->cmd; x++) { 233 for (x = bltins; x->cmd; x++) {
225 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 234 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
226 } 235 }
227 fprintf(stdout, "\n\n"); 236 fprintf(stdout, "\n\n");
228 return TRUE; 237 return TRUE;
229} 238}
230 239
231/* built-in 'jobs' handler */ 240/* built-in 'jobs' handler */
232static int shell_jobs(struct job* dummy, struct jobSet* jobList) 241static int shell_jobs(struct job *dummy, struct jobSet *jobList)
233{ 242{
234 struct job * job; 243 struct job *job;
235 char * statusString; 244 char *statusString;
236 for (job = jobList->head; job; job = job->next) { 245 for (job = jobList->head; job; job = job->next) {
237 if (job->runningProgs == job->stoppedProgs) 246 if (job->runningProgs == job->stoppedProgs)
238 statusString = "Stopped"; 247 statusString = "Stopped";
239 else 248 else
240 statusString = "Running"; 249 statusString = "Running";
241 250
242 printf(JOB_STATUS_FORMAT, job->jobId, statusString, 251 printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text);
243 job->text); 252 }
244 } 253 return TRUE;
245 return TRUE;
246} 254}
247 255
248 256
249/* built-in 'pwd' handler */ 257/* built-in 'pwd' handler */
250static int shell_pwd(struct job* dummy, struct jobSet* junk) 258static int shell_pwd(struct job *dummy, struct jobSet *junk)
251{ 259{
252 getcwd(cwd, sizeof(cwd)); 260 getcwd(cwd, sizeof(cwd));
253 fprintf(stdout, "%s\n", cwd); 261 fprintf(stdout, "%s\n", cwd);
254 return TRUE; 262 return TRUE;
255} 263}
256 264
257/* built-in 'set VAR=value' handler */ 265/* built-in 'set VAR=value' handler */
258static int shell_set(struct job* cmd, struct jobSet* junk) 266static int shell_set(struct job *cmd, struct jobSet *junk)
259{ 267{
260 int res; 268 int res;
261 269
262 if (!cmd->progs[0].argv[1] == 1) { 270 if (!cmd->progs[0].argv[1] == 1) {
263 return (shell_env(cmd, junk)); 271 return (shell_env(cmd, junk));
264 } 272 }
265 res = putenv(cmd->progs[0].argv[1]); 273 res = putenv(cmd->progs[0].argv[1]);
266 if (res) 274 if (res)
267 fprintf(stdout, "set: %s\n", strerror(errno)); 275 fprintf(stdout, "set: %s\n", strerror(errno));
268 return (res); 276 return (res);
269} 277}
270 278
271/* Built-in '.' handler (read-in and execute commands from file) */ 279/* Built-in '.' handler (read-in and execute commands from file) */
272static int shell_source(struct job* cmd, struct jobSet* junk) 280static int shell_source(struct job *cmd, struct jobSet *junk)
273{ 281{
274 FILE *input; 282 FILE *input;
275 int status; 283 int status;
276
277 if (!cmd->progs[0].argv[1] == 1)
278 return FALSE;
279
280 input = fopen(cmd->progs[0].argv[1], "r");
281 if (!input) {
282 fprintf(stdout, "Couldn't open file '%s'\n", cmd->progs[0].argv[1]);
283 return FALSE;
284 }
285 284
286 /* Now run the file */ 285 if (!cmd->progs[0].argv[1] == 1)
287 status = busy_loop(input); 286 return FALSE;
288 return (status); 287
288 input = fopen(cmd->progs[0].argv[1], "r");
289 if (!input) {
290 fprintf(stdout, "Couldn't open file '%s'\n",
291 cmd->progs[0].argv[1]);
292 return FALSE;
293 }
294
295 /* Now run the file */
296 status = busy_loop(input);
297 return (status);
289} 298}
290 299
291/* built-in 'unset VAR' handler */ 300/* built-in 'unset VAR' handler */
292static int shell_unset(struct job* cmd, struct jobSet* junk) 301static int shell_unset(struct job *cmd, struct jobSet *junk)
293{ 302{
294 if (!cmd->progs[0].argv[1] == 1) { 303 if (!cmd->progs[0].argv[1] == 1) {
295 fprintf(stdout, "unset: parameter required.\n"); 304 fprintf(stdout, "unset: parameter required.\n");
296 return FALSE; 305 return FALSE;
297 } 306 }
298 unsetenv(cmd->progs[0].argv[1]); 307 unsetenv(cmd->progs[0].argv[1]);
299 return TRUE; 308 return TRUE;
300} 309}
301 310
302/* free up all memory from a job */ 311/* free up all memory from a job */
303static void freeJob(struct job * cmd) 312static void freeJob(struct job *cmd)
304{ 313{
305 int i; 314 int i;
306 315
307 for (i = 0; i < cmd->numProgs; i++) { 316 for (i = 0; i < cmd->numProgs; i++) {
308 free(cmd->progs[i].argv); 317 free(cmd->progs[i].argv);
309 if (cmd->progs[i].redirections) free(cmd->progs[i].redirections); 318 if (cmd->progs[i].redirections)
310 if (cmd->progs[i].freeGlob) globfree(&cmd->progs[i].globResult); 319 free(cmd->progs[i].redirections);
320 if (cmd->progs[i].freeGlob)
321 globfree(&cmd->progs[i].globResult);
311 } 322 }
312 free(cmd->progs); 323 free(cmd->progs);
313 if (cmd->text) free(cmd->text); 324 if (cmd->text)
325 free(cmd->text);
314 free(cmd->cmdBuf); 326 free(cmd->cmdBuf);
315} 327}
316 328
317/* remove a job from the jobList */ 329/* remove a job from the jobList */
318static void removeJob(struct jobSet * jobList, struct job * job) 330static void removeJob(struct jobSet *jobList, struct job *job)
319{ 331{
320 struct job * prevJob; 332 struct job *prevJob;
321 333
322 freeJob(job); 334 freeJob(job);
323 if (job == jobList->head) { 335 if (job == jobList->head) {
324 jobList->head = job->next; 336 jobList->head = job->next;
325 } else { 337 } else {
326 prevJob = jobList->head; 338 prevJob = jobList->head;
327 while (prevJob->next != job) prevJob = prevJob->next; 339 while (prevJob->next != job)
328 prevJob->next = job->next; 340 prevJob = prevJob->next;
341 prevJob->next = job->next;
329 } 342 }
330 343
331 free(job); 344 free(job);
@@ -333,56 +346,62 @@ static void removeJob(struct jobSet * jobList, struct job * job)
333 346
334/* Checks to see if any background processes have exited -- if they 347/* Checks to see if any background processes have exited -- if they
335 have, figure out why and see if a job has completed */ 348 have, figure out why and see if a job has completed */
336static void checkJobs(struct jobSet * jobList) 349static void checkJobs(struct jobSet *jobList)
337{ 350{
338 struct job * job; 351 struct job *job;
339 pid_t childpid; 352 pid_t childpid;
340 int status; 353 int status;
341 int progNum=0; 354 int progNum = 0;
342 355
343 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { 356 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
344 for (job = jobList->head; job; job = job->next) { 357 for (job = jobList->head; job; job = job->next) {
345 progNum = 0; 358 progNum = 0;
346 while (progNum < job->numProgs && 359 while (progNum < job->numProgs &&
347 job->progs[progNum].pid != childpid) 360 job->progs[progNum].pid != childpid) progNum++;
348 progNum++; 361 if (progNum < job->numProgs)
349 if (progNum < job->numProgs) break; 362 break;
350 } 363 }
351 364
352 if (WIFEXITED(status) || WIFSIGNALED(status)) { 365 if (WIFEXITED(status) || WIFSIGNALED(status)) {
353 /* child exited */ 366 /* child exited */
354 job->runningProgs--; 367 job->runningProgs--;
355 job->progs[progNum].pid = 0; 368 job->progs[progNum].pid = 0;
356 369
357 if (!job->runningProgs) { 370 if (!job->runningProgs) {
358 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text); 371 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text);
359 removeJob(jobList, job); 372 removeJob(jobList, job);
360 } 373 }
361 } else { 374 } else {
362 /* child stopped */ 375 /* child stopped */
363 job->stoppedProgs++; 376 job->stoppedProgs++;
364 job->progs[progNum].isStopped = 1; 377 job->progs[progNum].isStopped = 1;
365 378
366 if (job->stoppedProgs == job->numProgs) { 379 if (job->stoppedProgs == job->numProgs) {
367 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", job->text); 380 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped",
368 } 381 job->text);
369 } 382 }
383 }
370 } 384 }
371 385
372 if (childpid == -1 && errno != ECHILD) 386 if (childpid == -1 && errno != ECHILD)
373 perror("waitpid"); 387 perror("waitpid");
374} 388}
375 389
376static int getCommand(FILE * source, char * command) 390static int getCommand(FILE * source, char *command)
377{ 391{
378 if (source == stdin) { 392 if (source == stdin) {
379 fprintf(stdout, "%s %s", cwd, prompt); 393 fprintf(stdout, "BBSHELL %s %s", cwd, prompt);
380 fflush(stdout); 394 fflush(stdout);
395#ifdef BB_FEATURE_SH_COMMAND_EDITING
396 cmdedit_read_input(fileno(stdin), fileno(stdout), command);
397 return 0;
398#endif
381 } 399 }
382 400
383 if (!fgets(command, MAX_COMMAND_LEN, source)) { 401 if (!fgets(command, BUFSIZ - 2, source)) {
384 if (source == stdin) printf("\n"); 402 if (source == stdin)
385 return 1; 403 printf("\n");
404 return 1;
386 } 405 }
387 406
388 /* remove trailing newline */ 407 /* remove trailing newline */
@@ -391,46 +410,48 @@ static int getCommand(FILE * source, char * command)
391 return 0; 410 return 0;
392} 411}
393 412
394static void globLastArgument(struct childProgram * prog, int * argcPtr, 413static void globLastArgument(struct childProgram *prog, int *argcPtr,
395 int * argcAllocedPtr) 414 int *argcAllocedPtr)
396{ 415{
397 int argc = *argcPtr; 416 int argc = *argcPtr;
398 int argcAlloced = *argcAllocedPtr; 417 int argcAlloced = *argcAllocedPtr;
399 int rc; 418 int rc;
400 int flags; 419 int flags;
401 int i; 420 int i;
402 char * src, * dst; 421 char *src, *dst;
403 422
404 if (argc > 1) { /* cmd->globResult is already initialized */ 423 if (argc > 1) { /* cmd->globResult is already initialized */
405 flags = GLOB_APPEND; 424 flags = GLOB_APPEND;
406 i = prog->globResult.gl_pathc; 425 i = prog->globResult.gl_pathc;
407 } else { 426 } else {
408 prog->freeGlob = 1; 427 prog->freeGlob = 1;
409 flags = 0; 428 flags = 0;
410 i = 0; 429 i = 0;
411 } 430 }
412 431
413 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); 432 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);
414 if (rc == GLOB_NOSPACE) { 433 if (rc == GLOB_NOSPACE) {
415 fprintf(stderr, "out of space during glob operation\n"); 434 fprintf(stderr, "out of space during glob operation\n");
416 return; 435 return;
417 } else if (rc == GLOB_NOMATCH || 436 } else if (rc == GLOB_NOMATCH ||
418 (!rc && (prog->globResult.gl_pathc - i) == 1 && 437 (!rc && (prog->globResult.gl_pathc - i) == 1 &&
419 !strcmp(prog->argv[argc - 1], 438 !strcmp(prog->argv[argc - 1],
420 prog->globResult.gl_pathv[i]))) { 439 prog->globResult.gl_pathv[i]))) {
421 /* we need to remove whatever \ quoting is still present */ 440 /* we need to remove whatever \ quoting is still present */
422 src = dst = prog->argv[argc - 1]; 441 src = dst = prog->argv[argc - 1];
423 while (*src) { 442 while (*src) {
424 if (*src != '\\') *dst++ = *src; 443 if (*src != '\\')
425 src++; 444 *dst++ = *src;
426 } 445 src++;
427 *dst = '\0'; 446 }
447 *dst = '\0';
428 } else if (!rc) { 448 } else if (!rc) {
429 argcAlloced += (prog->globResult.gl_pathc - i); 449 argcAlloced += (prog->globResult.gl_pathc - i);
430 prog->argv = realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 450 prog->argv =
431 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, 451 realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
432 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 452 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
433 argc += (prog->globResult.gl_pathc - i - 1); 453 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
454 argc += (prog->globResult.gl_pathc - i - 1);
434 } 455 }
435 456
436 *argcAllocedPtr = argcAlloced; 457 *argcAllocedPtr = argcAlloced;
@@ -442,27 +463,28 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
442 the beginning of the next command (if the original command had more 463 the beginning of the next command (if the original command had more
443 then one job associated with it) or NULL if no more commands are 464 then one job associated with it) or NULL if no more commands are
444 present. */ 465 present. */
445static int parseCommand(char ** commandPtr, struct job * job, int * isBg) 466static int parseCommand(char **commandPtr, struct job *job, int *isBg)
446{ 467{
447 char * command; 468 char *command;
448 char * returnCommand = NULL; 469 char *returnCommand = NULL;
449 char * src, * buf, * chptr; 470 char *src, *buf, *chptr;
450 int argc = 0; 471 int argc = 0;
451 int done = 0; 472 int done = 0;
452 int argvAlloced; 473 int argvAlloced;
453 int i; 474 int i;
454 char quote = '\0'; 475 char quote = '\0';
455 int count; 476 int count;
456 struct childProgram * prog; 477 struct childProgram *prog;
457 478
458 /* skip leading white space */ 479 /* skip leading white space */
459 while (**commandPtr && isspace(**commandPtr)) (*commandPtr)++; 480 while (**commandPtr && isspace(**commandPtr))
460 481 (*commandPtr)++;
461 /* this handles empty lines or leading '#' characters */ 482
462 if (!**commandPtr || (**commandPtr=='#')) { 483 /* this handles empty lines or leading '#' characters */
463 job->numProgs = 0; 484 if (!**commandPtr || (**commandPtr == '#')) {
464 *commandPtr = NULL; 485 job->numProgs = 0;
465 return 0; 486 *commandPtr = NULL;
487 return 0;
466 } 488 }
467 489
468 *isBg = 0; 490 *isBg = 0;
@@ -491,177 +513,185 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
491 buf = command; 513 buf = command;
492 src = *commandPtr; 514 src = *commandPtr;
493 while (*src && !done) { 515 while (*src && !done) {
494 if (quote == *src) { 516 if (quote == *src) {
495 quote = '\0'; 517 quote = '\0';
496 } else if (quote) { 518 } else if (quote) {
497 if (*src == '\\') { 519 if (*src == '\\') {
498 src++; 520 src++;
499 if (!*src) { 521 if (!*src) {
500 fprintf(stderr, "character expected after \\\n"); 522 fprintf(stderr, "character expected after \\\n");
501 freeJob(job); 523 freeJob(job);
502 return 1; 524 return 1;
503 } 525 }
504 526
505 /* in shell, "\'" should yield \' */ 527 /* in shell, "\'" should yield \' */
506 if (*src != quote) *buf++ = '\\'; 528 if (*src != quote)
507 } else if (*src == '*' || *src == '?' || *src == '[' || 529 *buf++ = '\\';
508 *src == ']') 530 } else if (*src == '*' || *src == '?' || *src == '[' ||
509 *buf++ = '\\'; 531 *src == ']') *buf++ = '\\';
510 *buf++ = *src; 532 *buf++ = *src;
511 } else if (isspace(*src)) { 533 } else if (isspace(*src)) {
512 if (*prog->argv[argc]) { 534 if (*prog->argv[argc]) {
513 buf++, argc++; 535 buf++, argc++;
514 /* +1 here leaves room for the NULL which ends argv */ 536 /* +1 here leaves room for the NULL which ends argv */
515 if ((argc + 1) == argvAlloced) { 537 if ((argc + 1) == argvAlloced) {
516 argvAlloced += 5; 538 argvAlloced += 5;
517 prog->argv = realloc(prog->argv, 539 prog->argv = realloc(prog->argv,
518 sizeof(*prog->argv) * argvAlloced); 540 sizeof(*prog->argv) *
519 } 541 argvAlloced);
520 prog->argv[argc] = buf; 542 }
521 543 prog->argv[argc] = buf;
522 globLastArgument(prog, &argc, &argvAlloced); 544
523 } 545 globLastArgument(prog, &argc, &argvAlloced);
524 } else switch (*src) { 546 }
525 case '"': 547 } else
526 case '\'': 548 switch (*src) {
527 quote = *src; 549 case '"':
528 break; 550 case '\'':
529 551 quote = *src;
530 case '#': /* comment */ 552 break;
531 done = 1; 553
532 break; 554 case '#': /* comment */
533 555 done = 1;
534 case '>': /* redirections */ 556 break;
535 case '<': 557
536 i = prog->numRedirections++; 558 case '>': /* redirections */
537 prog->redirections = realloc(prog->redirections, 559 case '<':
538 sizeof(*prog->redirections) * (i + 1)); 560 i = prog->numRedirections++;
539 561 prog->redirections = realloc(prog->redirections,
540 prog->redirections[i].fd = -1; 562 sizeof(*prog->redirections) *
541 if (buf != prog->argv[argc]) { 563 (i + 1));
542 /* the stuff before this character may be the file number 564
543 being redirected */ 565 prog->redirections[i].fd = -1;
544 prog->redirections[i].fd = strtol(prog->argv[argc], &chptr, 10); 566 if (buf != prog->argv[argc]) {
545 567 /* the stuff before this character may be the file number
546 if (*chptr && *prog->argv[argc]) { 568 being redirected */
547 buf++, argc++; 569 prog->redirections[i].fd =
548 globLastArgument(prog, &argc, &argvAlloced); 570 strtol(prog->argv[argc], &chptr, 10);
549 } 571
550 } 572 if (*chptr && *prog->argv[argc]) {
551 573 buf++, argc++;
552 if (prog->redirections[i].fd == -1) { 574 globLastArgument(prog, &argc, &argvAlloced);
553 if (*src == '>') 575 }
554 prog->redirections[i].fd = 1; 576 }
555 else 577
556 prog->redirections[i].fd = 0; 578 if (prog->redirections[i].fd == -1) {
557 } 579 if (*src == '>')
558 580 prog->redirections[i].fd = 1;
559 if (*src++ == '>') { 581 else
560 if (*src == '>') 582 prog->redirections[i].fd = 0;
561 prog->redirections[i].type = REDIRECT_APPEND, src++; 583 }
562 else 584
563 prog->redirections[i].type = REDIRECT_OVERWRITE; 585 if (*src++ == '>') {
564 } else { 586 if (*src == '>')
565 prog->redirections[i].type = REDIRECT_INPUT; 587 prog->redirections[i].type =
566 } 588 REDIRECT_APPEND, src++;
567 589 else
568 /* This isn't POSIX sh compliant. Oh well. */ 590 prog->redirections[i].type = REDIRECT_OVERWRITE;
569 chptr = src; 591 } else {
570 while (isspace(*chptr)) chptr++; 592 prog->redirections[i].type = REDIRECT_INPUT;
571 593 }
572 if (!*chptr) { 594
573 fprintf(stderr, "file name expected after %c\n", *src); 595 /* This isn't POSIX sh compliant. Oh well. */
574 freeJob(job); 596 chptr = src;
575 return 1; 597 while (isspace(*chptr))
576 } 598 chptr++;
577 599
578 prog->redirections[i].filename = buf; 600 if (!*chptr) {
579 while (*chptr && !isspace(*chptr)) 601 fprintf(stderr, "file name expected after %c\n", *src);
580 *buf++ = *chptr++; 602 freeJob(job);
581 603 return 1;
582 src = chptr - 1; /* we src++ later */ 604 }
583 prog->argv[argc] = ++buf; 605
584 break; 606 prog->redirections[i].filename = buf;
585 607 while (*chptr && !isspace(*chptr))
586 case '|': /* pipe */ 608 *buf++ = *chptr++;
587 /* finish this command */ 609
588 if (*prog->argv[argc]) argc++; 610 src = chptr - 1; /* we src++ later */
589 if (!argc) { 611 prog->argv[argc] = ++buf;
590 fprintf(stderr, "empty command in pipe\n"); 612 break;
591 freeJob(job); 613
592 return 1; 614 case '|': /* pipe */
593 } 615 /* finish this command */
594 prog->argv[argc] = NULL; 616 if (*prog->argv[argc])
595 617 argc++;
596 /* and start the next */ 618 if (!argc) {
597 job->numProgs++; 619 fprintf(stderr, "empty command in pipe\n");
598 job->progs = realloc(job->progs, 620 freeJob(job);
599 sizeof(*job->progs) * job->numProgs); 621 return 1;
600 prog = job->progs + (job->numProgs - 1); 622 }
601 prog->numRedirections = 0; 623 prog->argv[argc] = NULL;
602 prog->redirections = NULL; 624
603 prog->freeGlob = 0; 625 /* and start the next */
604 argc = 0; 626 job->numProgs++;
605 627 job->progs = realloc(job->progs,
606 argvAlloced = 5; 628 sizeof(*job->progs) * job->numProgs);
607 prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); 629 prog = job->progs + (job->numProgs - 1);
608 prog->argv[0] = ++buf; 630 prog->numRedirections = 0;
609 631 prog->redirections = NULL;
610 src++; 632 prog->freeGlob = 0;
611 while (*src && isspace(*src)) src++; 633 argc = 0;
612 634
613 if (!*src) { 635 argvAlloced = 5;
614 fprintf(stderr, "empty command in pipe\n"); 636 prog->argv = malloc(sizeof(*prog->argv) * argvAlloced);
615 return 1; 637 prog->argv[0] = ++buf;
616 } 638
617 src--; /* we'll ++ it at the end of the loop */ 639 src++;
618 640 while (*src && isspace(*src))
619 break; 641 src++;
620 642
621 case '&': /* background */ 643 if (!*src) {
622 *isBg = 1; 644 fprintf(stderr, "empty command in pipe\n");
623 case ';': /* multiple commands */ 645 return 1;
624 done = 1; 646 }
625 returnCommand = *commandPtr + (src - *commandPtr) + 1; 647 src--; /* we'll ++ it at the end of the loop */
626 break; 648
627 649 break;
628 case '\\': 650
629 src++; 651 case '&': /* background */
630 if (!*src) { 652 *isBg = 1;
631 freeJob(job); 653 case ';': /* multiple commands */
632 fprintf(stderr, "character expected after \\\n"); 654 done = 1;
633 return 1; 655 returnCommand = *commandPtr + (src - *commandPtr) + 1;
634 } 656 break;
635 if (*src == '*' || *src == '[' || *src == ']' || *src == '?') 657
636 *buf++ = '\\'; 658 case '\\':
637 /* fallthrough */ 659 src++;
638 default: 660 if (!*src) {
639 *buf++ = *src; 661 freeJob(job);
640 } 662 fprintf(stderr, "character expected after \\\n");
641 663 return 1;
642 src++; 664 }
665 if (*src == '*' || *src == '[' || *src == ']'
666 || *src == '?') *buf++ = '\\';
667 /* fallthrough */
668 default:
669 *buf++ = *src;
670 }
671
672 src++;
643 } 673 }
644 674
645 if (*prog->argv[argc]) { 675 if (*prog->argv[argc]) {
646 argc++; 676 argc++;
647 globLastArgument(prog, &argc, &argvAlloced); 677 globLastArgument(prog, &argc, &argvAlloced);
648 } 678 }
649 if (!argc) { 679 if (!argc) {
650 freeJob(job); 680 freeJob(job);
651 return 0; 681 return 0;
652 } 682 }
653 prog->argv[argc] = NULL; 683 prog->argv[argc] = NULL;
654 684
655 if (!returnCommand) { 685 if (!returnCommand) {
656 job->text = malloc(strlen(*commandPtr) + 1); 686 job->text = malloc(strlen(*commandPtr) + 1);
657 strcpy(job->text, *commandPtr); 687 strcpy(job->text, *commandPtr);
658 } else { 688 } else {
659 /* This leaves any trailing spaces, which is a bit sloppy */ 689 /* This leaves any trailing spaces, which is a bit sloppy */
660 690
661 count = returnCommand - *commandPtr; 691 count = returnCommand - *commandPtr;
662 job->text = malloc(count + 1); 692 job->text = malloc(count + 1);
663 strncpy(job->text, *commandPtr, count); 693 strncpy(job->text, *commandPtr, count);
664 job->text[count] = '\0'; 694 job->text[count] = '\0';
665 } 695 }
666 696
667 *commandPtr = returnCommand; 697 *commandPtr = returnCommand;
@@ -669,63 +699,64 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
669 return 0; 699 return 0;
670} 700}
671 701
672static int runCommand(struct job newJob, struct jobSet * jobList, 702static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
673 int inBg)
674{ 703{
675 struct job * job; 704 struct job *job;
676 int i; 705 int i;
677 int nextin, nextout; 706 int nextin, nextout;
678 int pipefds[2]; /* pipefd[0] is for reading */ 707 int pipefds[2]; /* pipefd[0] is for reading */
679 struct builtInCommand *x; 708 struct builtInCommand *x;
680 709
681 /* handle built-ins here -- we don't fork() so we can't background 710 /* handle built-ins here -- we don't fork() so we can't background
682 these very easily */ 711 these very easily */
683 for( x=bltins ; x->cmd ; x++) { 712 for (x = bltins; x->cmd; x++) {
684 if (!strcmp(newJob.progs[0].argv[0], x->cmd)) { 713 if (!strcmp(newJob.progs[0].argv[0], x->cmd)) {
685 return(x->function(&newJob, jobList)); 714 return (x->function(&newJob, jobList));
686 } 715 }
687 } 716 }
688 717
689 nextin = 0, nextout = 1; 718 nextin = 0, nextout = 1;
690 for (i = 0; i < newJob.numProgs; i++) { 719 for (i = 0; i < newJob.numProgs; i++) {
691 if ((i + 1) < newJob.numProgs) { 720 if ((i + 1) < newJob.numProgs) {
692 pipe(pipefds); 721 pipe(pipefds);
693 nextout = pipefds[1]; 722 nextout = pipefds[1];
694 } else { 723 } else {
695 nextout = 1; 724 nextout = 1;
696 } 725 }
697 726
698 if (!(newJob.progs[i].pid = fork())) { 727 if (!(newJob.progs[i].pid = fork())) {
699 signal(SIGTTOU, SIG_DFL); 728 signal(SIGTTOU, SIG_DFL);
700 729
701 if (nextin != 0) { 730 if (nextin != 0) {
702 dup2(nextin, 0); 731 dup2(nextin, 0);
703 close(nextin); 732 close(nextin);
704 } 733 }
705 734
706 if (nextout != 1) { 735 if (nextout != 1) {
707 dup2(nextout, 1); 736 dup2(nextout, 1);
708 close(nextout); 737 close(nextout);
709 } 738 }
710 739
711 /* explicit redirections override pipes */ 740 /* explicit redirections override pipes */
712 setupRedirections(newJob.progs + i); 741 setupRedirections(newJob.progs + i);
713 742
714 execvp(newJob.progs[i].argv[0], newJob.progs[i].argv); 743 execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);
715 fatalError( "sh: %s: %s\n", newJob.progs[i].argv[0], 744 fatalError("sh: %s: %s\n", newJob.progs[i].argv[0],
716 strerror(errno)); 745 strerror(errno));
717 } 746 }
718 747
719 /* put our child in the process group whose leader is the 748 /* put our child in the process group whose leader is the
720 first process in this pipe */ 749 first process in this pipe */
721 setpgid(newJob.progs[i].pid, newJob.progs[0].pid); 750 setpgid(newJob.progs[i].pid, newJob.progs[0].pid);
722 751
723 if (nextin != 0) close(nextin); 752 if (nextin != 0)
724 if (nextout != 1) close(nextout); 753 close(nextin);
725 754 if (nextout != 1)
726 /* If there isn't another process, nextin is garbage 755 close(nextout);
727 but it doesn't matter */ 756
728 nextin = pipefds[0]; 757 /* If there isn't another process, nextin is garbage
758 but it doesn't matter */
759 nextin = pipefds[0];
729 } 760 }
730 761
731 newJob.pgrp = newJob.progs[0].pid; 762 newJob.pgrp = newJob.progs[0].pid;
@@ -733,16 +764,16 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
733 /* find the ID for the job to use */ 764 /* find the ID for the job to use */
734 newJob.jobId = 1; 765 newJob.jobId = 1;
735 for (job = jobList->head; job; job = job->next) 766 for (job = jobList->head; job; job = job->next)
736 if (job->jobId >= newJob.jobId) 767 if (job->jobId >= newJob.jobId)
737 newJob.jobId = job->jobId + 1; 768 newJob.jobId = job->jobId + 1;
738 769
739 /* add the job to the list of running jobs */ 770 /* add the job to the list of running jobs */
740 if (!jobList->head) { 771 if (!jobList->head) {
741 job = jobList->head = malloc(sizeof(*job)); 772 job = jobList->head = malloc(sizeof(*job));
742 } else { 773 } else {
743 for (job = jobList->head; job->next; job = job->next); 774 for (job = jobList->head; job->next; job = job->next);
744 job->next = malloc(sizeof(*job)); 775 job->next = malloc(sizeof(*job));
745 job = job->next; 776 job = job->next;
746 } 777 }
747 778
748 *job = newJob; 779 *job = newJob;
@@ -751,165 +782,177 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
751 job->stoppedProgs = 0; 782 job->stoppedProgs = 0;
752 783
753 if (inBg) { 784 if (inBg) {
754 /* we don't wait for background jobs to return -- append it 785 /* we don't wait for background jobs to return -- append it
755 to the list of backgrounded jobs and leave it alone */ 786 to the list of backgrounded jobs and leave it alone */
756 787
757 printf("[%d] %d\n", job->jobId, 788 printf("[%d] %d\n", job->jobId,
758 newJob.progs[newJob.numProgs - 1].pid); 789 newJob.progs[newJob.numProgs - 1].pid);
759 } else { 790 } else {
760 jobList->fg = job; 791 jobList->fg = job;
792
793 /* move the new process group into the foreground */
761 794
762 /* move the new process group into the foreground */ 795 if (tcsetpgrp(0, newJob.pgrp))
763 796 perror("tcsetpgrp");
764 if (tcsetpgrp(0, newJob.pgrp))
765 perror("tcsetpgrp");
766 } 797 }
767 798
768 return 0; 799 return 0;
769} 800}
770 801
771static int setupRedirections(struct childProgram * prog) 802static int setupRedirections(struct childProgram *prog)
772{ 803{
773 int i; 804 int i;
774 int openfd; 805 int openfd;
775 int mode=O_RDONLY; 806 int mode = O_RDONLY;
776 struct redirectionSpecifier * redir = prog->redirections; 807 struct redirectionSpecifier *redir = prog->redirections;
777 808
778 for (i = 0; i < prog->numRedirections; i++, redir++) { 809 for (i = 0; i < prog->numRedirections; i++, redir++) {
779 switch (redir->type) { 810 switch (redir->type) {
780 case REDIRECT_INPUT: 811 case REDIRECT_INPUT:
781 mode = O_RDONLY; 812 mode = O_RDONLY;
782 break; 813 break;
783 case REDIRECT_OVERWRITE: 814 case REDIRECT_OVERWRITE:
784 mode = O_RDWR | O_CREAT | O_TRUNC; 815 mode = O_RDWR | O_CREAT | O_TRUNC;
785 break; 816 break;
786 case REDIRECT_APPEND: 817 case REDIRECT_APPEND:
787 mode = O_RDWR | O_CREAT | O_APPEND; 818 mode = O_RDWR | O_CREAT | O_APPEND;
788 break; 819 break;
789 } 820 }
790 821
791 openfd = open(redir->filename, mode, 0666); 822 openfd = open(redir->filename, mode, 0666);
792 if (openfd < 0) { 823 if (openfd < 0) {
793 /* this could get lost if stderr has been redirected, but 824 /* this could get lost if stderr has been redirected, but
794 bash and ash both lose it as well (though zsh doesn't!) */ 825 bash and ash both lose it as well (though zsh doesn't!) */
795 fprintf(stderr, "error opening %s: %s\n", redir->filename, 826 fprintf(stderr, "error opening %s: %s\n", redir->filename,
796 strerror(errno)); 827 strerror(errno));
797 return 1; 828 return 1;
798 } 829 }
799 830
800 if (openfd != redir->fd) { 831 if (openfd != redir->fd) {
801 dup2(openfd, redir->fd); 832 dup2(openfd, redir->fd);
802 close(openfd); 833 close(openfd);
803 } 834 }
804 } 835 }
805 836
806 return 0; 837 return 0;
807} 838}
808 839
809 840
810static int busy_loop(FILE * input) 841static int busy_loop(FILE * input)
811{ 842{
812 char command[MAX_COMMAND_LEN + 1]; 843 char *command;
813 char * nextCommand = NULL; 844 char *nextCommand = NULL;
814 struct jobSet jobList = { NULL, NULL }; 845 struct jobSet jobList = { NULL, NULL };
815 struct job newJob; 846 struct job newJob;
816 int i; 847 int i;
817 int status; 848 int status;
818 int inBg; 849 int inBg;
819 850
851 command = (char*) calloc(BUFSIZ, sizeof(char));
852
820 /* don't pay any attention to this signal; it just confuses 853 /* don't pay any attention to this signal; it just confuses
821 things and isn't really meant for shells anyway */ 854 things and isn't really meant for shells anyway */
822 signal(SIGTTOU, SIG_IGN); 855 signal(SIGTTOU, SIG_IGN);
823 856
824 while (1) { 857 while (1) {
825 if (!jobList.fg) { 858 if (!jobList.fg) {
826 /* no job is in the foreground */ 859 /* no job is in the foreground */
827 860
828 /* see if any background processes have exited */ 861 /* see if any background processes have exited */
829 checkJobs(&jobList); 862 checkJobs(&jobList);
830 863
831 if (!nextCommand) { 864 if (!nextCommand) {
832 if (getCommand(input, command)) break; 865 if (getCommand(input, command))
833 nextCommand = command; 866 break;
834 } 867 nextCommand = command;
835 868 }
836 if (!parseCommand(&nextCommand, &newJob, &inBg) && 869
837 newJob.numProgs) { 870 if (!parseCommand(&nextCommand, &newJob, &inBg) &&
838 runCommand(newJob, &jobList, inBg); 871 newJob.numProgs) {
839 } 872 runCommand(newJob, &jobList, inBg);
840 } else { 873 }
841 /* a job is running in the foreground; wait for it */ 874 } else {
842 i = 0; 875 /* a job is running in the foreground; wait for it */
843 while (!jobList.fg->progs[i].pid || 876 i = 0;
844 jobList.fg->progs[i].isStopped) i++; 877 while (!jobList.fg->progs[i].pid ||
845 878 jobList.fg->progs[i].isStopped) i++;
846 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); 879
847 880 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
848 if (WIFEXITED(status) || WIFSIGNALED(status)) { 881
849 /* the child exited */ 882 if (WIFEXITED(status) || WIFSIGNALED(status)) {
850 jobList.fg->runningProgs--; 883 /* the child exited */
851 jobList.fg->progs[i].pid = 0; 884 jobList.fg->runningProgs--;
852 885 jobList.fg->progs[i].pid = 0;
853 if (!jobList.fg->runningProgs) { 886
854 /* child exited */ 887 if (!jobList.fg->runningProgs) {
855 888 /* child exited */
856 removeJob(&jobList, jobList.fg); 889
857 jobList.fg = NULL; 890 removeJob(&jobList, jobList.fg);
858 891 jobList.fg = NULL;
859 /* move the shell to the foreground */ 892
860 if (tcsetpgrp(0, getpid())) 893 /* move the shell to the foreground */
861 perror("tcsetpgrp"); 894 if (tcsetpgrp(0, getpid()))
862 } 895 perror("tcsetpgrp");
863 } else { 896 }
864 /* the child was stopped */ 897 } else {
865 jobList.fg->stoppedProgs++; 898 /* the child was stopped */
866 jobList.fg->progs[i].isStopped = 1; 899 jobList.fg->stoppedProgs++;
867 900 jobList.fg->progs[i].isStopped = 1;
868 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) { 901
869 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId, 902 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) {
870 "Stopped", jobList.fg->text); 903 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId,
871 jobList.fg = NULL; 904 "Stopped", jobList.fg->text);
872 } 905 jobList.fg = NULL;
873 } 906 }
874 907 }
875 if (!jobList.fg) { 908
876 /* move the shell to the foreground */ 909 if (!jobList.fg) {
877 if (tcsetpgrp(0, getpid())) 910 /* move the shell to the foreground */
878 perror("tcsetpgrp"); 911 if (tcsetpgrp(0, getpid()))
879 } 912 perror("tcsetpgrp");
880 } 913 }
881 } 914 }
915 }
916 free( command);
882 917
883 return 0; 918 return 0;
884} 919}
885 920
886 921
887int shell_main(int argc, char ** argv) 922int shell_main(int argc, char **argv)
888{ 923{
889 FILE * input = stdin; 924 FILE *input = stdin;
890 925
891 if (argc > 2) { 926 if (argc > 2) {
892 usage( shell_usage); 927 usage(shell_usage);
893 } 928 }
894 /* initialize the cwd */ 929 /* initialize the cwd */
895 getcwd(cwd, sizeof(cwd)); 930 getcwd(cwd, sizeof(cwd));
896 931
897 932
898 //if (argv[0] && argv[0][0] == '-') { 933 //if (argv[0] && argv[0][0] == '-') {
899 // shell_source("/etc/profile"); 934 // shell_source("/etc/profile");
900 //} 935 //}
901 936
902 if (argc < 2) { 937 if (argc < 2) {
903 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); 938 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER,
904 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); 939 BB_BT);
905 } else { 940 fprintf(stdout,
906 input = fopen(argv[1], "r"); 941 "Enter 'help' for a list of built-in commands.\n\n");
907 if (!input) 942 } else {
908 fatalError("A: Couldn't open file '%s': %s\n", argv[1], strerror(errno)); 943 input = fopen(argv[1], "r");
909// else 944 if (!input)
910// fatalError("Got it.\n"); 945 fatalError("A: Couldn't open file '%s': %s\n", argv[1],
911 //exit(shell_source(argv[1])); 946 strerror(errno));
912 } 947// else
913 948// fatalError("Got it.\n");
914 return (busy_loop( input)); 949 //exit(shell_source(argv[1]));
950
951 /* Set terminal IO to canonical mode, and save old term settings. */
952#ifdef BB_FEATURE_SH_COMMAND_EDITING
953 cmdedit_init();
954#endif
955 }
956
957 return (busy_loop(input));
915} 958}
diff --git a/sh.c b/sh.c
index 9e467dc54..498f43779 100644
--- a/sh.c
+++ b/sh.c
@@ -39,293 +39,306 @@
39#include <unistd.h> 39#include <unistd.h>
40 40
41 41
42#define MAX_COMMAND_LEN 250 /* max length of a single command 42#ifdef BB_FEATURE_SH_COMMAND_EDITING
43 string */ 43#include "cmdedit.h"
44#endif
45
44#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 46#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
45 47
46enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND }; 48
49enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
50 REDIRECT_APPEND };
47 51
48struct jobSet { 52struct jobSet {
49 struct job * head; /* head of list of running jobs */ 53 struct job *head; /* head of list of running jobs */
50 struct job * fg; /* current foreground job */ 54 struct job *fg; /* current foreground job */
51}; 55};
52 56
53struct redirectionSpecifier { 57struct redirectionSpecifier {
54 enum redirectionType type; /* type of redirection */ 58 enum redirectionType type; /* type of redirection */
55 int fd; /* file descriptor being redirected */ 59 int fd; /* file descriptor being redirected */
56 char * filename; /* file to redirect fd to */ 60 char *filename; /* file to redirect fd to */
57}; 61};
58 62
59struct childProgram { 63struct childProgram {
60 pid_t pid; /* 0 if exited */ 64 pid_t pid; /* 0 if exited */
61 char ** argv; /* program name and arguments */ 65 char **argv; /* program name and arguments */
62 int numRedirections; /* elements in redirection array */ 66 int numRedirections; /* elements in redirection array */
63 struct redirectionSpecifier * redirections; /* I/O redirections */ 67 struct redirectionSpecifier *redirections; /* I/O redirections */
64 glob_t globResult; /* result of parameter globbing */ 68 glob_t globResult; /* result of parameter globbing */
65 int freeGlob; /* should we globfree(&globResult)? */ 69 int freeGlob; /* should we globfree(&globResult)? */
66 int isStopped; /* is the program currently running? */ 70 int isStopped; /* is the program currently running? */
67}; 71};
68 72
69struct job { 73struct job {
70 int jobId; /* job number */ 74 int jobId; /* job number */
71 int numProgs; /* total number of programs in job */ 75 int numProgs; /* total number of programs in job */
72 int runningProgs; /* number of programs running */ 76 int runningProgs; /* number of programs running */
73 char * text; /* name of job */ 77 char *text; /* name of job */
74 char * cmdBuf; /* buffer various argv's point into */ 78 char *cmdBuf; /* buffer various argv's point into */
75 pid_t pgrp; /* process group ID for the job */ 79 pid_t pgrp; /* process group ID for the job */
76 struct childProgram * progs; /* array of programs in job */ 80 struct childProgram *progs; /* array of programs in job */
77 struct job * next; /* to track background commands */ 81 struct job *next; /* to track background commands */
78 int stoppedProgs; /* number of programs alive, but stopped */ 82 int stoppedProgs; /* number of programs alive, but stopped */
79}; 83};
80 84
81struct builtInCommand { 85struct builtInCommand {
82 char *cmd; /* name */ 86 char *cmd; /* name */
83 char *descr; /* description */ 87 char *descr; /* description */
84 char *usage; /* usage */ 88 char *usage; /* usage */
85 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ 89 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
86}; 90};
87 91
88/* Some function prototypes */ 92/* Some function prototypes */
89static int shell_cd(struct job* cmd, struct jobSet* junk); 93static int shell_cd(struct job *cmd, struct jobSet *junk);
90static int shell_env(struct job* dummy, struct jobSet* junk); 94static int shell_env(struct job *dummy, struct jobSet *junk);
91static int shell_exit(struct job* cmd, struct jobSet* junk); 95static int shell_exit(struct job *cmd, struct jobSet *junk);
92static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); 96static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
93static int shell_help(struct job* cmd, struct jobSet* junk); 97static int shell_help(struct job *cmd, struct jobSet *junk);
94static int shell_jobs(struct job* dummy, struct jobSet* jobList); 98static int shell_jobs(struct job *dummy, struct jobSet *jobList);
95static int shell_pwd(struct job* dummy, struct jobSet* junk); 99static int shell_pwd(struct job *dummy, struct jobSet *junk);
96static int shell_set(struct job* cmd, struct jobSet* junk); 100static int shell_set(struct job *cmd, struct jobSet *junk);
97static int shell_source(struct job* cmd, struct jobSet* jobList); 101static int shell_source(struct job *cmd, struct jobSet *jobList);
98static int shell_unset(struct job* cmd, struct jobSet* junk); 102static int shell_unset(struct job *cmd, struct jobSet *junk);
99 103
100static void checkJobs(struct jobSet * jobList); 104static void checkJobs(struct jobSet *jobList);
101static int getCommand(FILE * source, char * command); 105static int getCommand(FILE * source, char *command);
102static int parseCommand(char ** commandPtr, struct job * job, int * isBg); 106static int parseCommand(char **commandPtr, struct job *job, int *isBg);
103static int setupRedirections(struct childProgram * prog); 107static int setupRedirections(struct childProgram *prog);
104static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); 108static int runCommand(struct job newJob, struct jobSet *jobList, int inBg);
105static int busy_loop(FILE * input); 109static int busy_loop(FILE * input);
106 110
107 111
108/* Table of built-in functions */ 112/* Table of built-in functions */
109static struct builtInCommand bltins[] = { 113static struct builtInCommand bltins[] = {
110 {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg}, 114 {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg},
111 {"cd", "Change working directory", "cd [dir]", shell_cd}, 115 {"cd", "Change working directory", "cd [dir]", shell_cd},
112 {"env", "Print all environment variables", "env", shell_env}, 116 //{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo},
113 {"exit", "Exit from shell()", "exit", shell_exit}, 117 {"env", "Print all environment variables", "env", shell_env},
114 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, 118 {"exit", "Exit from shell()", "exit", shell_exit},
115 {"jobs", "Lists the active jobs", "jobs", shell_jobs}, 119 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
116 {"pwd", "Print current directory", "pwd", shell_pwd}, 120 {"jobs", "Lists the active jobs", "jobs", shell_jobs},
117 {"set", "Set environment variable", "set [VAR=value]", shell_set}, 121 {"pwd", "Print current directory", "pwd", shell_pwd},
118 {"unset", "Unset environment variable", "unset VAR", shell_unset}, 122 {"set", "Set environment variable", "set [VAR=value]", shell_set},
119 //{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo}, 123 {"unset", "Unset environment variable", "unset VAR", shell_unset},
120 {".", "Source-in and run commands in a file", ". filename", shell_source}, 124 {".", "Source-in and run commands in a file", ". filename",
121 {"help", "List shell built-in commands", "help", shell_help}, 125 shell_source},
122 {NULL, NULL, NULL, NULL} 126 {"help", "List shell built-in commands", "help", shell_help},
127 {NULL, NULL, NULL, NULL}
123}; 128};
124 129
125static const char shell_usage[] = 130static const char shell_usage[] =
126 "sh [FILE]...\n\n" 131 "sh [FILE]...\n\n" "The BusyBox command interpreter (shell).\n\n";
127 "The BusyBox command interpreter (shell).\n\n";
128 132
129 133
130static char cwd[1024]; 134static char cwd[1024];
131static char *prompt = "# "; 135static char *prompt = "# ";
132 136
133 137
138
134/* built-in 'cd <path>' handler */ 139/* built-in 'cd <path>' handler */
135static int shell_cd(struct job* cmd, struct jobSet* junk) 140static int shell_cd(struct job *cmd, struct jobSet *junk)
136{ 141{
137 char *newdir; 142 char *newdir;
138 if (!cmd->progs[0].argv[1] == 1) 143 if (!cmd->progs[0].argv[1] == 1)
139 newdir = getenv("HOME"); 144 newdir = getenv("HOME");
140 else 145 else
141 newdir = cmd->progs[0].argv[1]; 146 newdir = cmd->progs[0].argv[1];
142 if (chdir(newdir)) { 147 if (chdir(newdir)) {
143 printf("cd: %s: %s\n", newdir, strerror(errno)); 148 printf("cd: %s: %s\n", newdir, strerror(errno));
144 return FALSE; 149 return FALSE;
145 } 150 }
146 getcwd(cwd, sizeof(cwd)); 151 getcwd(cwd, sizeof(cwd));
147 152
148 return TRUE; 153 return TRUE;
149} 154}
150 155
151/* built-in 'env' handler */ 156/* built-in 'env' handler */
152static int shell_env(struct job* dummy, struct jobSet* junk) 157static int shell_env(struct job *dummy, struct jobSet *junk)
153{ 158{
154 char **e; 159 char **e;
155 160
156 for (e = environ ; *e ; e++) { 161 for (e = environ; *e; e++) {
157 fprintf(stdout, "%s\n", *e); 162 fprintf(stdout, "%s\n", *e);
158 } 163 }
159 return (0); 164 return (0);
160} 165}
161 166
162/* built-in 'exit' handler */ 167/* built-in 'exit' handler */
163static int shell_exit(struct job* cmd, struct jobSet* junk) 168static int shell_exit(struct job *cmd, struct jobSet *junk)
164{ 169{
165 if (!cmd->progs[0].argv[1] == 1) 170 if (!cmd->progs[0].argv[1] == 1)
166 exit TRUE; 171 exit TRUE;
167 else 172 else
168 exit(atoi(cmd->progs[0].argv[1])); 173 exit(atoi(cmd->progs[0].argv[1]));
169} 174}
170 175
171/* built-in 'fg' and 'bg' handler */ 176/* built-in 'fg' and 'bg' handler */
172static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) 177static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
173{ 178{
174 int i, jobNum; 179 int i, jobNum;
175 struct job* job; 180 struct job *job;
176 181
177 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { 182 if (!jobList->head) {
178 fprintf(stderr, "%s: exactly one argument is expected\n", 183 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
179 cmd->progs[0].argv[0]); 184 fprintf(stderr, "%s: exactly one argument is expected\n",
180 return FALSE; 185 cmd->progs[0].argv[0]);
181 } 186 return FALSE;
182 187 }
183 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { 188 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) {
184 fprintf(stderr, "%s: bad argument '%s'\n", 189 fprintf(stderr, "%s: bad argument '%s'\n",
185 cmd->progs[0].argv[0], cmd->progs[0].argv[1]); 190 cmd->progs[0].argv[0], cmd->progs[0].argv[1]);
186 return FALSE; 191 return FALSE;
187 } 192 }
188 193 } else {
189 for (job = jobList->head; job; job = job->next) 194 job = jobList->head;
190 if (job->jobId == jobNum) break; 195 }
191 196
192 if (!job) { 197 for (job = jobList->head; job; job = job->next)
193 fprintf(stderr, "%s: unknown job %d\n", 198 if (job->jobId == jobNum)
194 cmd->progs[0].argv[0], jobNum); 199 break;
195 return FALSE; 200
196 } 201 if (!job) {
197 202 fprintf(stderr, "%s: unknown job %d\n",
198 if (*cmd->progs[0].argv[0] == 'f') { 203 cmd->progs[0].argv[0], jobNum);
199 /* Make this job the foreground job */ 204 return FALSE;
200 205 }
201 if (tcsetpgrp(0, job->pgrp)) 206
202 perror("tcsetpgrp"); 207 if (*cmd->progs[0].argv[0] == 'f') {
203 jobList->fg = job; 208 /* Make this job the foreground job */
204 } 209
205 210 if (tcsetpgrp(0, job->pgrp))
206 /* Restart the processes in the job */ 211 perror("tcsetpgrp");
207 for (i = 0; i < job->numProgs; i++) 212 jobList->fg = job;
208 job->progs[i].isStopped = 0; 213 }
209 214
210 kill(-job->pgrp, SIGCONT); 215 /* Restart the processes in the job */
211 216 for (i = 0; i < job->numProgs; i++)
212 job->stoppedProgs = 0; 217 job->progs[i].isStopped = 0;
213 218
214 return TRUE; 219 kill(-job->pgrp, SIGCONT);
220
221 job->stoppedProgs = 0;
222
223 return TRUE;
215} 224}
216 225
217/* built-in 'help' handler */ 226/* built-in 'help' handler */
218static int shell_help(struct job* cmd, struct jobSet* junk) 227static int shell_help(struct job *cmd, struct jobSet *junk)
219{ 228{
220 struct builtInCommand *x; 229 struct builtInCommand *x;
221 230
222 fprintf(stdout, "\nBuilt-in commands:\n"); 231 fprintf(stdout, "\nBuilt-in commands:\n");
223 fprintf(stdout, "-------------------\n"); 232 fprintf(stdout, "-------------------\n");
224 for ( x=bltins; x->cmd; x++) { 233 for (x = bltins; x->cmd; x++) {
225 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 234 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
226 } 235 }
227 fprintf(stdout, "\n\n"); 236 fprintf(stdout, "\n\n");
228 return TRUE; 237 return TRUE;
229} 238}
230 239
231/* built-in 'jobs' handler */ 240/* built-in 'jobs' handler */
232static int shell_jobs(struct job* dummy, struct jobSet* jobList) 241static int shell_jobs(struct job *dummy, struct jobSet *jobList)
233{ 242{
234 struct job * job; 243 struct job *job;
235 char * statusString; 244 char *statusString;
236 for (job = jobList->head; job; job = job->next) { 245 for (job = jobList->head; job; job = job->next) {
237 if (job->runningProgs == job->stoppedProgs) 246 if (job->runningProgs == job->stoppedProgs)
238 statusString = "Stopped"; 247 statusString = "Stopped";
239 else 248 else
240 statusString = "Running"; 249 statusString = "Running";
241 250
242 printf(JOB_STATUS_FORMAT, job->jobId, statusString, 251 printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text);
243 job->text); 252 }
244 } 253 return TRUE;
245 return TRUE;
246} 254}
247 255
248 256
249/* built-in 'pwd' handler */ 257/* built-in 'pwd' handler */
250static int shell_pwd(struct job* dummy, struct jobSet* junk) 258static int shell_pwd(struct job *dummy, struct jobSet *junk)
251{ 259{
252 getcwd(cwd, sizeof(cwd)); 260 getcwd(cwd, sizeof(cwd));
253 fprintf(stdout, "%s\n", cwd); 261 fprintf(stdout, "%s\n", cwd);
254 return TRUE; 262 return TRUE;
255} 263}
256 264
257/* built-in 'set VAR=value' handler */ 265/* built-in 'set VAR=value' handler */
258static int shell_set(struct job* cmd, struct jobSet* junk) 266static int shell_set(struct job *cmd, struct jobSet *junk)
259{ 267{
260 int res; 268 int res;
261 269
262 if (!cmd->progs[0].argv[1] == 1) { 270 if (!cmd->progs[0].argv[1] == 1) {
263 return (shell_env(cmd, junk)); 271 return (shell_env(cmd, junk));
264 } 272 }
265 res = putenv(cmd->progs[0].argv[1]); 273 res = putenv(cmd->progs[0].argv[1]);
266 if (res) 274 if (res)
267 fprintf(stdout, "set: %s\n", strerror(errno)); 275 fprintf(stdout, "set: %s\n", strerror(errno));
268 return (res); 276 return (res);
269} 277}
270 278
271/* Built-in '.' handler (read-in and execute commands from file) */ 279/* Built-in '.' handler (read-in and execute commands from file) */
272static int shell_source(struct job* cmd, struct jobSet* junk) 280static int shell_source(struct job *cmd, struct jobSet *junk)
273{ 281{
274 FILE *input; 282 FILE *input;
275 int status; 283 int status;
276
277 if (!cmd->progs[0].argv[1] == 1)
278 return FALSE;
279
280 input = fopen(cmd->progs[0].argv[1], "r");
281 if (!input) {
282 fprintf(stdout, "Couldn't open file '%s'\n", cmd->progs[0].argv[1]);
283 return FALSE;
284 }
285 284
286 /* Now run the file */ 285 if (!cmd->progs[0].argv[1] == 1)
287 status = busy_loop(input); 286 return FALSE;
288 return (status); 287
288 input = fopen(cmd->progs[0].argv[1], "r");
289 if (!input) {
290 fprintf(stdout, "Couldn't open file '%s'\n",
291 cmd->progs[0].argv[1]);
292 return FALSE;
293 }
294
295 /* Now run the file */
296 status = busy_loop(input);
297 return (status);
289} 298}
290 299
291/* built-in 'unset VAR' handler */ 300/* built-in 'unset VAR' handler */
292static int shell_unset(struct job* cmd, struct jobSet* junk) 301static int shell_unset(struct job *cmd, struct jobSet *junk)
293{ 302{
294 if (!cmd->progs[0].argv[1] == 1) { 303 if (!cmd->progs[0].argv[1] == 1) {
295 fprintf(stdout, "unset: parameter required.\n"); 304 fprintf(stdout, "unset: parameter required.\n");
296 return FALSE; 305 return FALSE;
297 } 306 }
298 unsetenv(cmd->progs[0].argv[1]); 307 unsetenv(cmd->progs[0].argv[1]);
299 return TRUE; 308 return TRUE;
300} 309}
301 310
302/* free up all memory from a job */ 311/* free up all memory from a job */
303static void freeJob(struct job * cmd) 312static void freeJob(struct job *cmd)
304{ 313{
305 int i; 314 int i;
306 315
307 for (i = 0; i < cmd->numProgs; i++) { 316 for (i = 0; i < cmd->numProgs; i++) {
308 free(cmd->progs[i].argv); 317 free(cmd->progs[i].argv);
309 if (cmd->progs[i].redirections) free(cmd->progs[i].redirections); 318 if (cmd->progs[i].redirections)
310 if (cmd->progs[i].freeGlob) globfree(&cmd->progs[i].globResult); 319 free(cmd->progs[i].redirections);
320 if (cmd->progs[i].freeGlob)
321 globfree(&cmd->progs[i].globResult);
311 } 322 }
312 free(cmd->progs); 323 free(cmd->progs);
313 if (cmd->text) free(cmd->text); 324 if (cmd->text)
325 free(cmd->text);
314 free(cmd->cmdBuf); 326 free(cmd->cmdBuf);
315} 327}
316 328
317/* remove a job from the jobList */ 329/* remove a job from the jobList */
318static void removeJob(struct jobSet * jobList, struct job * job) 330static void removeJob(struct jobSet *jobList, struct job *job)
319{ 331{
320 struct job * prevJob; 332 struct job *prevJob;
321 333
322 freeJob(job); 334 freeJob(job);
323 if (job == jobList->head) { 335 if (job == jobList->head) {
324 jobList->head = job->next; 336 jobList->head = job->next;
325 } else { 337 } else {
326 prevJob = jobList->head; 338 prevJob = jobList->head;
327 while (prevJob->next != job) prevJob = prevJob->next; 339 while (prevJob->next != job)
328 prevJob->next = job->next; 340 prevJob = prevJob->next;
341 prevJob->next = job->next;
329 } 342 }
330 343
331 free(job); 344 free(job);
@@ -333,56 +346,62 @@ static void removeJob(struct jobSet * jobList, struct job * job)
333 346
334/* Checks to see if any background processes have exited -- if they 347/* Checks to see if any background processes have exited -- if they
335 have, figure out why and see if a job has completed */ 348 have, figure out why and see if a job has completed */
336static void checkJobs(struct jobSet * jobList) 349static void checkJobs(struct jobSet *jobList)
337{ 350{
338 struct job * job; 351 struct job *job;
339 pid_t childpid; 352 pid_t childpid;
340 int status; 353 int status;
341 int progNum=0; 354 int progNum = 0;
342 355
343 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { 356 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
344 for (job = jobList->head; job; job = job->next) { 357 for (job = jobList->head; job; job = job->next) {
345 progNum = 0; 358 progNum = 0;
346 while (progNum < job->numProgs && 359 while (progNum < job->numProgs &&
347 job->progs[progNum].pid != childpid) 360 job->progs[progNum].pid != childpid) progNum++;
348 progNum++; 361 if (progNum < job->numProgs)
349 if (progNum < job->numProgs) break; 362 break;
350 } 363 }
351 364
352 if (WIFEXITED(status) || WIFSIGNALED(status)) { 365 if (WIFEXITED(status) || WIFSIGNALED(status)) {
353 /* child exited */ 366 /* child exited */
354 job->runningProgs--; 367 job->runningProgs--;
355 job->progs[progNum].pid = 0; 368 job->progs[progNum].pid = 0;
356 369
357 if (!job->runningProgs) { 370 if (!job->runningProgs) {
358 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text); 371 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text);
359 removeJob(jobList, job); 372 removeJob(jobList, job);
360 } 373 }
361 } else { 374 } else {
362 /* child stopped */ 375 /* child stopped */
363 job->stoppedProgs++; 376 job->stoppedProgs++;
364 job->progs[progNum].isStopped = 1; 377 job->progs[progNum].isStopped = 1;
365 378
366 if (job->stoppedProgs == job->numProgs) { 379 if (job->stoppedProgs == job->numProgs) {
367 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", job->text); 380 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped",
368 } 381 job->text);
369 } 382 }
383 }
370 } 384 }
371 385
372 if (childpid == -1 && errno != ECHILD) 386 if (childpid == -1 && errno != ECHILD)
373 perror("waitpid"); 387 perror("waitpid");
374} 388}
375 389
376static int getCommand(FILE * source, char * command) 390static int getCommand(FILE * source, char *command)
377{ 391{
378 if (source == stdin) { 392 if (source == stdin) {
379 fprintf(stdout, "%s %s", cwd, prompt); 393 fprintf(stdout, "BBSHELL %s %s", cwd, prompt);
380 fflush(stdout); 394 fflush(stdout);
395#ifdef BB_FEATURE_SH_COMMAND_EDITING
396 cmdedit_read_input(fileno(stdin), fileno(stdout), command);
397 return 0;
398#endif
381 } 399 }
382 400
383 if (!fgets(command, MAX_COMMAND_LEN, source)) { 401 if (!fgets(command, BUFSIZ - 2, source)) {
384 if (source == stdin) printf("\n"); 402 if (source == stdin)
385 return 1; 403 printf("\n");
404 return 1;
386 } 405 }
387 406
388 /* remove trailing newline */ 407 /* remove trailing newline */
@@ -391,46 +410,48 @@ static int getCommand(FILE * source, char * command)
391 return 0; 410 return 0;
392} 411}
393 412
394static void globLastArgument(struct childProgram * prog, int * argcPtr, 413static void globLastArgument(struct childProgram *prog, int *argcPtr,
395 int * argcAllocedPtr) 414 int *argcAllocedPtr)
396{ 415{
397 int argc = *argcPtr; 416 int argc = *argcPtr;
398 int argcAlloced = *argcAllocedPtr; 417 int argcAlloced = *argcAllocedPtr;
399 int rc; 418 int rc;
400 int flags; 419 int flags;
401 int i; 420 int i;
402 char * src, * dst; 421 char *src, *dst;
403 422
404 if (argc > 1) { /* cmd->globResult is already initialized */ 423 if (argc > 1) { /* cmd->globResult is already initialized */
405 flags = GLOB_APPEND; 424 flags = GLOB_APPEND;
406 i = prog->globResult.gl_pathc; 425 i = prog->globResult.gl_pathc;
407 } else { 426 } else {
408 prog->freeGlob = 1; 427 prog->freeGlob = 1;
409 flags = 0; 428 flags = 0;
410 i = 0; 429 i = 0;
411 } 430 }
412 431
413 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); 432 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);
414 if (rc == GLOB_NOSPACE) { 433 if (rc == GLOB_NOSPACE) {
415 fprintf(stderr, "out of space during glob operation\n"); 434 fprintf(stderr, "out of space during glob operation\n");
416 return; 435 return;
417 } else if (rc == GLOB_NOMATCH || 436 } else if (rc == GLOB_NOMATCH ||
418 (!rc && (prog->globResult.gl_pathc - i) == 1 && 437 (!rc && (prog->globResult.gl_pathc - i) == 1 &&
419 !strcmp(prog->argv[argc - 1], 438 !strcmp(prog->argv[argc - 1],
420 prog->globResult.gl_pathv[i]))) { 439 prog->globResult.gl_pathv[i]))) {
421 /* we need to remove whatever \ quoting is still present */ 440 /* we need to remove whatever \ quoting is still present */
422 src = dst = prog->argv[argc - 1]; 441 src = dst = prog->argv[argc - 1];
423 while (*src) { 442 while (*src) {
424 if (*src != '\\') *dst++ = *src; 443 if (*src != '\\')
425 src++; 444 *dst++ = *src;
426 } 445 src++;
427 *dst = '\0'; 446 }
447 *dst = '\0';
428 } else if (!rc) { 448 } else if (!rc) {
429 argcAlloced += (prog->globResult.gl_pathc - i); 449 argcAlloced += (prog->globResult.gl_pathc - i);
430 prog->argv = realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 450 prog->argv =
431 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, 451 realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
432 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 452 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
433 argc += (prog->globResult.gl_pathc - i - 1); 453 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
454 argc += (prog->globResult.gl_pathc - i - 1);
434 } 455 }
435 456
436 *argcAllocedPtr = argcAlloced; 457 *argcAllocedPtr = argcAlloced;
@@ -442,27 +463,28 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
442 the beginning of the next command (if the original command had more 463 the beginning of the next command (if the original command had more
443 then one job associated with it) or NULL if no more commands are 464 then one job associated with it) or NULL if no more commands are
444 present. */ 465 present. */
445static int parseCommand(char ** commandPtr, struct job * job, int * isBg) 466static int parseCommand(char **commandPtr, struct job *job, int *isBg)
446{ 467{
447 char * command; 468 char *command;
448 char * returnCommand = NULL; 469 char *returnCommand = NULL;
449 char * src, * buf, * chptr; 470 char *src, *buf, *chptr;
450 int argc = 0; 471 int argc = 0;
451 int done = 0; 472 int done = 0;
452 int argvAlloced; 473 int argvAlloced;
453 int i; 474 int i;
454 char quote = '\0'; 475 char quote = '\0';
455 int count; 476 int count;
456 struct childProgram * prog; 477 struct childProgram *prog;
457 478
458 /* skip leading white space */ 479 /* skip leading white space */
459 while (**commandPtr && isspace(**commandPtr)) (*commandPtr)++; 480 while (**commandPtr && isspace(**commandPtr))
460 481 (*commandPtr)++;
461 /* this handles empty lines or leading '#' characters */ 482
462 if (!**commandPtr || (**commandPtr=='#')) { 483 /* this handles empty lines or leading '#' characters */
463 job->numProgs = 0; 484 if (!**commandPtr || (**commandPtr == '#')) {
464 *commandPtr = NULL; 485 job->numProgs = 0;
465 return 0; 486 *commandPtr = NULL;
487 return 0;
466 } 488 }
467 489
468 *isBg = 0; 490 *isBg = 0;
@@ -491,177 +513,185 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
491 buf = command; 513 buf = command;
492 src = *commandPtr; 514 src = *commandPtr;
493 while (*src && !done) { 515 while (*src && !done) {
494 if (quote == *src) { 516 if (quote == *src) {
495 quote = '\0'; 517 quote = '\0';
496 } else if (quote) { 518 } else if (quote) {
497 if (*src == '\\') { 519 if (*src == '\\') {
498 src++; 520 src++;
499 if (!*src) { 521 if (!*src) {
500 fprintf(stderr, "character expected after \\\n"); 522 fprintf(stderr, "character expected after \\\n");
501 freeJob(job); 523 freeJob(job);
502 return 1; 524 return 1;
503 } 525 }
504 526
505 /* in shell, "\'" should yield \' */ 527 /* in shell, "\'" should yield \' */
506 if (*src != quote) *buf++ = '\\'; 528 if (*src != quote)
507 } else if (*src == '*' || *src == '?' || *src == '[' || 529 *buf++ = '\\';
508 *src == ']') 530 } else if (*src == '*' || *src == '?' || *src == '[' ||
509 *buf++ = '\\'; 531 *src == ']') *buf++ = '\\';
510 *buf++ = *src; 532 *buf++ = *src;
511 } else if (isspace(*src)) { 533 } else if (isspace(*src)) {
512 if (*prog->argv[argc]) { 534 if (*prog->argv[argc]) {
513 buf++, argc++; 535 buf++, argc++;
514 /* +1 here leaves room for the NULL which ends argv */ 536 /* +1 here leaves room for the NULL which ends argv */
515 if ((argc + 1) == argvAlloced) { 537 if ((argc + 1) == argvAlloced) {
516 argvAlloced += 5; 538 argvAlloced += 5;
517 prog->argv = realloc(prog->argv, 539 prog->argv = realloc(prog->argv,
518 sizeof(*prog->argv) * argvAlloced); 540 sizeof(*prog->argv) *
519 } 541 argvAlloced);
520 prog->argv[argc] = buf; 542 }
521 543 prog->argv[argc] = buf;
522 globLastArgument(prog, &argc, &argvAlloced); 544
523 } 545 globLastArgument(prog, &argc, &argvAlloced);
524 } else switch (*src) { 546 }
525 case '"': 547 } else
526 case '\'': 548 switch (*src) {
527 quote = *src; 549 case '"':
528 break; 550 case '\'':
529 551 quote = *src;
530 case '#': /* comment */ 552 break;
531 done = 1; 553
532 break; 554 case '#': /* comment */
533 555 done = 1;
534 case '>': /* redirections */ 556 break;
535 case '<': 557
536 i = prog->numRedirections++; 558 case '>': /* redirections */
537 prog->redirections = realloc(prog->redirections, 559 case '<':
538 sizeof(*prog->redirections) * (i + 1)); 560 i = prog->numRedirections++;
539 561 prog->redirections = realloc(prog->redirections,
540 prog->redirections[i].fd = -1; 562 sizeof(*prog->redirections) *
541 if (buf != prog->argv[argc]) { 563 (i + 1));
542 /* the stuff before this character may be the file number 564
543 being redirected */ 565 prog->redirections[i].fd = -1;
544 prog->redirections[i].fd = strtol(prog->argv[argc], &chptr, 10); 566 if (buf != prog->argv[argc]) {
545 567 /* the stuff before this character may be the file number
546 if (*chptr && *prog->argv[argc]) { 568 being redirected */
547 buf++, argc++; 569 prog->redirections[i].fd =
548 globLastArgument(prog, &argc, &argvAlloced); 570 strtol(prog->argv[argc], &chptr, 10);
549 } 571
550 } 572 if (*chptr && *prog->argv[argc]) {
551 573 buf++, argc++;
552 if (prog->redirections[i].fd == -1) { 574 globLastArgument(prog, &argc, &argvAlloced);
553 if (*src == '>') 575 }
554 prog->redirections[i].fd = 1; 576 }
555 else 577
556 prog->redirections[i].fd = 0; 578 if (prog->redirections[i].fd == -1) {
557 } 579 if (*src == '>')
558 580 prog->redirections[i].fd = 1;
559 if (*src++ == '>') { 581 else
560 if (*src == '>') 582 prog->redirections[i].fd = 0;
561 prog->redirections[i].type = REDIRECT_APPEND, src++; 583 }
562 else 584
563 prog->redirections[i].type = REDIRECT_OVERWRITE; 585 if (*src++ == '>') {
564 } else { 586 if (*src == '>')
565 prog->redirections[i].type = REDIRECT_INPUT; 587 prog->redirections[i].type =
566 } 588 REDIRECT_APPEND, src++;
567 589 else
568 /* This isn't POSIX sh compliant. Oh well. */ 590 prog->redirections[i].type = REDIRECT_OVERWRITE;
569 chptr = src; 591 } else {
570 while (isspace(*chptr)) chptr++; 592 prog->redirections[i].type = REDIRECT_INPUT;
571 593 }
572 if (!*chptr) { 594
573 fprintf(stderr, "file name expected after %c\n", *src); 595 /* This isn't POSIX sh compliant. Oh well. */
574 freeJob(job); 596 chptr = src;
575 return 1; 597 while (isspace(*chptr))
576 } 598 chptr++;
577 599
578 prog->redirections[i].filename = buf; 600 if (!*chptr) {
579 while (*chptr && !isspace(*chptr)) 601 fprintf(stderr, "file name expected after %c\n", *src);
580 *buf++ = *chptr++; 602 freeJob(job);
581 603 return 1;
582 src = chptr - 1; /* we src++ later */ 604 }
583 prog->argv[argc] = ++buf; 605
584 break; 606 prog->redirections[i].filename = buf;
585 607 while (*chptr && !isspace(*chptr))
586 case '|': /* pipe */ 608 *buf++ = *chptr++;
587 /* finish this command */ 609
588 if (*prog->argv[argc]) argc++; 610 src = chptr - 1; /* we src++ later */
589 if (!argc) { 611 prog->argv[argc] = ++buf;
590 fprintf(stderr, "empty command in pipe\n"); 612 break;
591 freeJob(job); 613
592 return 1; 614 case '|': /* pipe */
593 } 615 /* finish this command */
594 prog->argv[argc] = NULL; 616 if (*prog->argv[argc])
595 617 argc++;
596 /* and start the next */ 618 if (!argc) {
597 job->numProgs++; 619 fprintf(stderr, "empty command in pipe\n");
598 job->progs = realloc(job->progs, 620 freeJob(job);
599 sizeof(*job->progs) * job->numProgs); 621 return 1;
600 prog = job->progs + (job->numProgs - 1); 622 }
601 prog->numRedirections = 0; 623 prog->argv[argc] = NULL;
602 prog->redirections = NULL; 624
603 prog->freeGlob = 0; 625 /* and start the next */
604 argc = 0; 626 job->numProgs++;
605 627 job->progs = realloc(job->progs,
606 argvAlloced = 5; 628 sizeof(*job->progs) * job->numProgs);
607 prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); 629 prog = job->progs + (job->numProgs - 1);
608 prog->argv[0] = ++buf; 630 prog->numRedirections = 0;
609 631 prog->redirections = NULL;
610 src++; 632 prog->freeGlob = 0;
611 while (*src && isspace(*src)) src++; 633 argc = 0;
612 634
613 if (!*src) { 635 argvAlloced = 5;
614 fprintf(stderr, "empty command in pipe\n"); 636 prog->argv = malloc(sizeof(*prog->argv) * argvAlloced);
615 return 1; 637 prog->argv[0] = ++buf;
616 } 638
617 src--; /* we'll ++ it at the end of the loop */ 639 src++;
618 640 while (*src && isspace(*src))
619 break; 641 src++;
620 642
621 case '&': /* background */ 643 if (!*src) {
622 *isBg = 1; 644 fprintf(stderr, "empty command in pipe\n");
623 case ';': /* multiple commands */ 645 return 1;
624 done = 1; 646 }
625 returnCommand = *commandPtr + (src - *commandPtr) + 1; 647 src--; /* we'll ++ it at the end of the loop */
626 break; 648
627 649 break;
628 case '\\': 650
629 src++; 651 case '&': /* background */
630 if (!*src) { 652 *isBg = 1;
631 freeJob(job); 653 case ';': /* multiple commands */
632 fprintf(stderr, "character expected after \\\n"); 654 done = 1;
633 return 1; 655 returnCommand = *commandPtr + (src - *commandPtr) + 1;
634 } 656 break;
635 if (*src == '*' || *src == '[' || *src == ']' || *src == '?') 657
636 *buf++ = '\\'; 658 case '\\':
637 /* fallthrough */ 659 src++;
638 default: 660 if (!*src) {
639 *buf++ = *src; 661 freeJob(job);
640 } 662 fprintf(stderr, "character expected after \\\n");
641 663 return 1;
642 src++; 664 }
665 if (*src == '*' || *src == '[' || *src == ']'
666 || *src == '?') *buf++ = '\\';
667 /* fallthrough */
668 default:
669 *buf++ = *src;
670 }
671
672 src++;
643 } 673 }
644 674
645 if (*prog->argv[argc]) { 675 if (*prog->argv[argc]) {
646 argc++; 676 argc++;
647 globLastArgument(prog, &argc, &argvAlloced); 677 globLastArgument(prog, &argc, &argvAlloced);
648 } 678 }
649 if (!argc) { 679 if (!argc) {
650 freeJob(job); 680 freeJob(job);
651 return 0; 681 return 0;
652 } 682 }
653 prog->argv[argc] = NULL; 683 prog->argv[argc] = NULL;
654 684
655 if (!returnCommand) { 685 if (!returnCommand) {
656 job->text = malloc(strlen(*commandPtr) + 1); 686 job->text = malloc(strlen(*commandPtr) + 1);
657 strcpy(job->text, *commandPtr); 687 strcpy(job->text, *commandPtr);
658 } else { 688 } else {
659 /* This leaves any trailing spaces, which is a bit sloppy */ 689 /* This leaves any trailing spaces, which is a bit sloppy */
660 690
661 count = returnCommand - *commandPtr; 691 count = returnCommand - *commandPtr;
662 job->text = malloc(count + 1); 692 job->text = malloc(count + 1);
663 strncpy(job->text, *commandPtr, count); 693 strncpy(job->text, *commandPtr, count);
664 job->text[count] = '\0'; 694 job->text[count] = '\0';
665 } 695 }
666 696
667 *commandPtr = returnCommand; 697 *commandPtr = returnCommand;
@@ -669,63 +699,64 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
669 return 0; 699 return 0;
670} 700}
671 701
672static int runCommand(struct job newJob, struct jobSet * jobList, 702static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
673 int inBg)
674{ 703{
675 struct job * job; 704 struct job *job;
676 int i; 705 int i;
677 int nextin, nextout; 706 int nextin, nextout;
678 int pipefds[2]; /* pipefd[0] is for reading */ 707 int pipefds[2]; /* pipefd[0] is for reading */
679 struct builtInCommand *x; 708 struct builtInCommand *x;
680 709
681 /* handle built-ins here -- we don't fork() so we can't background 710 /* handle built-ins here -- we don't fork() so we can't background
682 these very easily */ 711 these very easily */
683 for( x=bltins ; x->cmd ; x++) { 712 for (x = bltins; x->cmd; x++) {
684 if (!strcmp(newJob.progs[0].argv[0], x->cmd)) { 713 if (!strcmp(newJob.progs[0].argv[0], x->cmd)) {
685 return(x->function(&newJob, jobList)); 714 return (x->function(&newJob, jobList));
686 } 715 }
687 } 716 }
688 717
689 nextin = 0, nextout = 1; 718 nextin = 0, nextout = 1;
690 for (i = 0; i < newJob.numProgs; i++) { 719 for (i = 0; i < newJob.numProgs; i++) {
691 if ((i + 1) < newJob.numProgs) { 720 if ((i + 1) < newJob.numProgs) {
692 pipe(pipefds); 721 pipe(pipefds);
693 nextout = pipefds[1]; 722 nextout = pipefds[1];
694 } else { 723 } else {
695 nextout = 1; 724 nextout = 1;
696 } 725 }
697 726
698 if (!(newJob.progs[i].pid = fork())) { 727 if (!(newJob.progs[i].pid = fork())) {
699 signal(SIGTTOU, SIG_DFL); 728 signal(SIGTTOU, SIG_DFL);
700 729
701 if (nextin != 0) { 730 if (nextin != 0) {
702 dup2(nextin, 0); 731 dup2(nextin, 0);
703 close(nextin); 732 close(nextin);
704 } 733 }
705 734
706 if (nextout != 1) { 735 if (nextout != 1) {
707 dup2(nextout, 1); 736 dup2(nextout, 1);
708 close(nextout); 737 close(nextout);
709 } 738 }
710 739
711 /* explicit redirections override pipes */ 740 /* explicit redirections override pipes */
712 setupRedirections(newJob.progs + i); 741 setupRedirections(newJob.progs + i);
713 742
714 execvp(newJob.progs[i].argv[0], newJob.progs[i].argv); 743 execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);
715 fatalError( "sh: %s: %s\n", newJob.progs[i].argv[0], 744 fatalError("sh: %s: %s\n", newJob.progs[i].argv[0],
716 strerror(errno)); 745 strerror(errno));
717 } 746 }
718 747
719 /* put our child in the process group whose leader is the 748 /* put our child in the process group whose leader is the
720 first process in this pipe */ 749 first process in this pipe */
721 setpgid(newJob.progs[i].pid, newJob.progs[0].pid); 750 setpgid(newJob.progs[i].pid, newJob.progs[0].pid);
722 751
723 if (nextin != 0) close(nextin); 752 if (nextin != 0)
724 if (nextout != 1) close(nextout); 753 close(nextin);
725 754 if (nextout != 1)
726 /* If there isn't another process, nextin is garbage 755 close(nextout);
727 but it doesn't matter */ 756
728 nextin = pipefds[0]; 757 /* If there isn't another process, nextin is garbage
758 but it doesn't matter */
759 nextin = pipefds[0];
729 } 760 }
730 761
731 newJob.pgrp = newJob.progs[0].pid; 762 newJob.pgrp = newJob.progs[0].pid;
@@ -733,16 +764,16 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
733 /* find the ID for the job to use */ 764 /* find the ID for the job to use */
734 newJob.jobId = 1; 765 newJob.jobId = 1;
735 for (job = jobList->head; job; job = job->next) 766 for (job = jobList->head; job; job = job->next)
736 if (job->jobId >= newJob.jobId) 767 if (job->jobId >= newJob.jobId)
737 newJob.jobId = job->jobId + 1; 768 newJob.jobId = job->jobId + 1;
738 769
739 /* add the job to the list of running jobs */ 770 /* add the job to the list of running jobs */
740 if (!jobList->head) { 771 if (!jobList->head) {
741 job = jobList->head = malloc(sizeof(*job)); 772 job = jobList->head = malloc(sizeof(*job));
742 } else { 773 } else {
743 for (job = jobList->head; job->next; job = job->next); 774 for (job = jobList->head; job->next; job = job->next);
744 job->next = malloc(sizeof(*job)); 775 job->next = malloc(sizeof(*job));
745 job = job->next; 776 job = job->next;
746 } 777 }
747 778
748 *job = newJob; 779 *job = newJob;
@@ -751,165 +782,177 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
751 job->stoppedProgs = 0; 782 job->stoppedProgs = 0;
752 783
753 if (inBg) { 784 if (inBg) {
754 /* we don't wait for background jobs to return -- append it 785 /* we don't wait for background jobs to return -- append it
755 to the list of backgrounded jobs and leave it alone */ 786 to the list of backgrounded jobs and leave it alone */
756 787
757 printf("[%d] %d\n", job->jobId, 788 printf("[%d] %d\n", job->jobId,
758 newJob.progs[newJob.numProgs - 1].pid); 789 newJob.progs[newJob.numProgs - 1].pid);
759 } else { 790 } else {
760 jobList->fg = job; 791 jobList->fg = job;
792
793 /* move the new process group into the foreground */
761 794
762 /* move the new process group into the foreground */ 795 if (tcsetpgrp(0, newJob.pgrp))
763 796 perror("tcsetpgrp");
764 if (tcsetpgrp(0, newJob.pgrp))
765 perror("tcsetpgrp");
766 } 797 }
767 798
768 return 0; 799 return 0;
769} 800}
770 801
771static int setupRedirections(struct childProgram * prog) 802static int setupRedirections(struct childProgram *prog)
772{ 803{
773 int i; 804 int i;
774 int openfd; 805 int openfd;
775 int mode=O_RDONLY; 806 int mode = O_RDONLY;
776 struct redirectionSpecifier * redir = prog->redirections; 807 struct redirectionSpecifier *redir = prog->redirections;
777 808
778 for (i = 0; i < prog->numRedirections; i++, redir++) { 809 for (i = 0; i < prog->numRedirections; i++, redir++) {
779 switch (redir->type) { 810 switch (redir->type) {
780 case REDIRECT_INPUT: 811 case REDIRECT_INPUT:
781 mode = O_RDONLY; 812 mode = O_RDONLY;
782 break; 813 break;
783 case REDIRECT_OVERWRITE: 814 case REDIRECT_OVERWRITE:
784 mode = O_RDWR | O_CREAT | O_TRUNC; 815 mode = O_RDWR | O_CREAT | O_TRUNC;
785 break; 816 break;
786 case REDIRECT_APPEND: 817 case REDIRECT_APPEND:
787 mode = O_RDWR | O_CREAT | O_APPEND; 818 mode = O_RDWR | O_CREAT | O_APPEND;
788 break; 819 break;
789 } 820 }
790 821
791 openfd = open(redir->filename, mode, 0666); 822 openfd = open(redir->filename, mode, 0666);
792 if (openfd < 0) { 823 if (openfd < 0) {
793 /* this could get lost if stderr has been redirected, but 824 /* this could get lost if stderr has been redirected, but
794 bash and ash both lose it as well (though zsh doesn't!) */ 825 bash and ash both lose it as well (though zsh doesn't!) */
795 fprintf(stderr, "error opening %s: %s\n", redir->filename, 826 fprintf(stderr, "error opening %s: %s\n", redir->filename,
796 strerror(errno)); 827 strerror(errno));
797 return 1; 828 return 1;
798 } 829 }
799 830
800 if (openfd != redir->fd) { 831 if (openfd != redir->fd) {
801 dup2(openfd, redir->fd); 832 dup2(openfd, redir->fd);
802 close(openfd); 833 close(openfd);
803 } 834 }
804 } 835 }
805 836
806 return 0; 837 return 0;
807} 838}
808 839
809 840
810static int busy_loop(FILE * input) 841static int busy_loop(FILE * input)
811{ 842{
812 char command[MAX_COMMAND_LEN + 1]; 843 char *command;
813 char * nextCommand = NULL; 844 char *nextCommand = NULL;
814 struct jobSet jobList = { NULL, NULL }; 845 struct jobSet jobList = { NULL, NULL };
815 struct job newJob; 846 struct job newJob;
816 int i; 847 int i;
817 int status; 848 int status;
818 int inBg; 849 int inBg;
819 850
851 command = (char*) calloc(BUFSIZ, sizeof(char));
852
820 /* don't pay any attention to this signal; it just confuses 853 /* don't pay any attention to this signal; it just confuses
821 things and isn't really meant for shells anyway */ 854 things and isn't really meant for shells anyway */
822 signal(SIGTTOU, SIG_IGN); 855 signal(SIGTTOU, SIG_IGN);
823 856
824 while (1) { 857 while (1) {
825 if (!jobList.fg) { 858 if (!jobList.fg) {
826 /* no job is in the foreground */ 859 /* no job is in the foreground */
827 860
828 /* see if any background processes have exited */ 861 /* see if any background processes have exited */
829 checkJobs(&jobList); 862 checkJobs(&jobList);
830 863
831 if (!nextCommand) { 864 if (!nextCommand) {
832 if (getCommand(input, command)) break; 865 if (getCommand(input, command))
833 nextCommand = command; 866 break;
834 } 867 nextCommand = command;
835 868 }
836 if (!parseCommand(&nextCommand, &newJob, &inBg) && 869
837 newJob.numProgs) { 870 if (!parseCommand(&nextCommand, &newJob, &inBg) &&
838 runCommand(newJob, &jobList, inBg); 871 newJob.numProgs) {
839 } 872 runCommand(newJob, &jobList, inBg);
840 } else { 873 }
841 /* a job is running in the foreground; wait for it */ 874 } else {
842 i = 0; 875 /* a job is running in the foreground; wait for it */
843 while (!jobList.fg->progs[i].pid || 876 i = 0;
844 jobList.fg->progs[i].isStopped) i++; 877 while (!jobList.fg->progs[i].pid ||
845 878 jobList.fg->progs[i].isStopped) i++;
846 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); 879
847 880 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
848 if (WIFEXITED(status) || WIFSIGNALED(status)) { 881
849 /* the child exited */ 882 if (WIFEXITED(status) || WIFSIGNALED(status)) {
850 jobList.fg->runningProgs--; 883 /* the child exited */
851 jobList.fg->progs[i].pid = 0; 884 jobList.fg->runningProgs--;
852 885 jobList.fg->progs[i].pid = 0;
853 if (!jobList.fg->runningProgs) { 886
854 /* child exited */ 887 if (!jobList.fg->runningProgs) {
855 888 /* child exited */
856 removeJob(&jobList, jobList.fg); 889
857 jobList.fg = NULL; 890 removeJob(&jobList, jobList.fg);
858 891 jobList.fg = NULL;
859 /* move the shell to the foreground */ 892
860 if (tcsetpgrp(0, getpid())) 893 /* move the shell to the foreground */
861 perror("tcsetpgrp"); 894 if (tcsetpgrp(0, getpid()))
862 } 895 perror("tcsetpgrp");
863 } else { 896 }
864 /* the child was stopped */ 897 } else {
865 jobList.fg->stoppedProgs++; 898 /* the child was stopped */
866 jobList.fg->progs[i].isStopped = 1; 899 jobList.fg->stoppedProgs++;
867 900 jobList.fg->progs[i].isStopped = 1;
868 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) { 901
869 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId, 902 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) {
870 "Stopped", jobList.fg->text); 903 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId,
871 jobList.fg = NULL; 904 "Stopped", jobList.fg->text);
872 } 905 jobList.fg = NULL;
873 } 906 }
874 907 }
875 if (!jobList.fg) { 908
876 /* move the shell to the foreground */ 909 if (!jobList.fg) {
877 if (tcsetpgrp(0, getpid())) 910 /* move the shell to the foreground */
878 perror("tcsetpgrp"); 911 if (tcsetpgrp(0, getpid()))
879 } 912 perror("tcsetpgrp");
880 } 913 }
881 } 914 }
915 }
916 free( command);
882 917
883 return 0; 918 return 0;
884} 919}
885 920
886 921
887int shell_main(int argc, char ** argv) 922int shell_main(int argc, char **argv)
888{ 923{
889 FILE * input = stdin; 924 FILE *input = stdin;
890 925
891 if (argc > 2) { 926 if (argc > 2) {
892 usage( shell_usage); 927 usage(shell_usage);
893 } 928 }
894 /* initialize the cwd */ 929 /* initialize the cwd */
895 getcwd(cwd, sizeof(cwd)); 930 getcwd(cwd, sizeof(cwd));
896 931
897 932
898 //if (argv[0] && argv[0][0] == '-') { 933 //if (argv[0] && argv[0][0] == '-') {
899 // shell_source("/etc/profile"); 934 // shell_source("/etc/profile");
900 //} 935 //}
901 936
902 if (argc < 2) { 937 if (argc < 2) {
903 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); 938 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER,
904 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); 939 BB_BT);
905 } else { 940 fprintf(stdout,
906 input = fopen(argv[1], "r"); 941 "Enter 'help' for a list of built-in commands.\n\n");
907 if (!input) 942 } else {
908 fatalError("A: Couldn't open file '%s': %s\n", argv[1], strerror(errno)); 943 input = fopen(argv[1], "r");
909// else 944 if (!input)
910// fatalError("Got it.\n"); 945 fatalError("A: Couldn't open file '%s': %s\n", argv[1],
911 //exit(shell_source(argv[1])); 946 strerror(errno));
912 } 947// else
913 948// fatalError("Got it.\n");
914 return (busy_loop( input)); 949 //exit(shell_source(argv[1]));
950
951 /* Set terminal IO to canonical mode, and save old term settings. */
952#ifdef BB_FEATURE_SH_COMMAND_EDITING
953 cmdedit_init();
954#endif
955 }
956
957 return (busy_loop(input));
915} 958}
diff --git a/shell/lash.c b/shell/lash.c
index 9e467dc54..498f43779 100644
--- a/shell/lash.c
+++ b/shell/lash.c
@@ -39,293 +39,306 @@
39#include <unistd.h> 39#include <unistd.h>
40 40
41 41
42#define MAX_COMMAND_LEN 250 /* max length of a single command 42#ifdef BB_FEATURE_SH_COMMAND_EDITING
43 string */ 43#include "cmdedit.h"
44#endif
45
44#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 46#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
45 47
46enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND }; 48
49enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
50 REDIRECT_APPEND };
47 51
48struct jobSet { 52struct jobSet {
49 struct job * head; /* head of list of running jobs */ 53 struct job *head; /* head of list of running jobs */
50 struct job * fg; /* current foreground job */ 54 struct job *fg; /* current foreground job */
51}; 55};
52 56
53struct redirectionSpecifier { 57struct redirectionSpecifier {
54 enum redirectionType type; /* type of redirection */ 58 enum redirectionType type; /* type of redirection */
55 int fd; /* file descriptor being redirected */ 59 int fd; /* file descriptor being redirected */
56 char * filename; /* file to redirect fd to */ 60 char *filename; /* file to redirect fd to */
57}; 61};
58 62
59struct childProgram { 63struct childProgram {
60 pid_t pid; /* 0 if exited */ 64 pid_t pid; /* 0 if exited */
61 char ** argv; /* program name and arguments */ 65 char **argv; /* program name and arguments */
62 int numRedirections; /* elements in redirection array */ 66 int numRedirections; /* elements in redirection array */
63 struct redirectionSpecifier * redirections; /* I/O redirections */ 67 struct redirectionSpecifier *redirections; /* I/O redirections */
64 glob_t globResult; /* result of parameter globbing */ 68 glob_t globResult; /* result of parameter globbing */
65 int freeGlob; /* should we globfree(&globResult)? */ 69 int freeGlob; /* should we globfree(&globResult)? */
66 int isStopped; /* is the program currently running? */ 70 int isStopped; /* is the program currently running? */
67}; 71};
68 72
69struct job { 73struct job {
70 int jobId; /* job number */ 74 int jobId; /* job number */
71 int numProgs; /* total number of programs in job */ 75 int numProgs; /* total number of programs in job */
72 int runningProgs; /* number of programs running */ 76 int runningProgs; /* number of programs running */
73 char * text; /* name of job */ 77 char *text; /* name of job */
74 char * cmdBuf; /* buffer various argv's point into */ 78 char *cmdBuf; /* buffer various argv's point into */
75 pid_t pgrp; /* process group ID for the job */ 79 pid_t pgrp; /* process group ID for the job */
76 struct childProgram * progs; /* array of programs in job */ 80 struct childProgram *progs; /* array of programs in job */
77 struct job * next; /* to track background commands */ 81 struct job *next; /* to track background commands */
78 int stoppedProgs; /* number of programs alive, but stopped */ 82 int stoppedProgs; /* number of programs alive, but stopped */
79}; 83};
80 84
81struct builtInCommand { 85struct builtInCommand {
82 char *cmd; /* name */ 86 char *cmd; /* name */
83 char *descr; /* description */ 87 char *descr; /* description */
84 char *usage; /* usage */ 88 char *usage; /* usage */
85 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ 89 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
86}; 90};
87 91
88/* Some function prototypes */ 92/* Some function prototypes */
89static int shell_cd(struct job* cmd, struct jobSet* junk); 93static int shell_cd(struct job *cmd, struct jobSet *junk);
90static int shell_env(struct job* dummy, struct jobSet* junk); 94static int shell_env(struct job *dummy, struct jobSet *junk);
91static int shell_exit(struct job* cmd, struct jobSet* junk); 95static int shell_exit(struct job *cmd, struct jobSet *junk);
92static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); 96static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
93static int shell_help(struct job* cmd, struct jobSet* junk); 97static int shell_help(struct job *cmd, struct jobSet *junk);
94static int shell_jobs(struct job* dummy, struct jobSet* jobList); 98static int shell_jobs(struct job *dummy, struct jobSet *jobList);
95static int shell_pwd(struct job* dummy, struct jobSet* junk); 99static int shell_pwd(struct job *dummy, struct jobSet *junk);
96static int shell_set(struct job* cmd, struct jobSet* junk); 100static int shell_set(struct job *cmd, struct jobSet *junk);
97static int shell_source(struct job* cmd, struct jobSet* jobList); 101static int shell_source(struct job *cmd, struct jobSet *jobList);
98static int shell_unset(struct job* cmd, struct jobSet* junk); 102static int shell_unset(struct job *cmd, struct jobSet *junk);
99 103
100static void checkJobs(struct jobSet * jobList); 104static void checkJobs(struct jobSet *jobList);
101static int getCommand(FILE * source, char * command); 105static int getCommand(FILE * source, char *command);
102static int parseCommand(char ** commandPtr, struct job * job, int * isBg); 106static int parseCommand(char **commandPtr, struct job *job, int *isBg);
103static int setupRedirections(struct childProgram * prog); 107static int setupRedirections(struct childProgram *prog);
104static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); 108static int runCommand(struct job newJob, struct jobSet *jobList, int inBg);
105static int busy_loop(FILE * input); 109static int busy_loop(FILE * input);
106 110
107 111
108/* Table of built-in functions */ 112/* Table of built-in functions */
109static struct builtInCommand bltins[] = { 113static struct builtInCommand bltins[] = {
110 {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg}, 114 {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg},
111 {"cd", "Change working directory", "cd [dir]", shell_cd}, 115 {"cd", "Change working directory", "cd [dir]", shell_cd},
112 {"env", "Print all environment variables", "env", shell_env}, 116 //{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo},
113 {"exit", "Exit from shell()", "exit", shell_exit}, 117 {"env", "Print all environment variables", "env", shell_env},
114 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, 118 {"exit", "Exit from shell()", "exit", shell_exit},
115 {"jobs", "Lists the active jobs", "jobs", shell_jobs}, 119 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
116 {"pwd", "Print current directory", "pwd", shell_pwd}, 120 {"jobs", "Lists the active jobs", "jobs", shell_jobs},
117 {"set", "Set environment variable", "set [VAR=value]", shell_set}, 121 {"pwd", "Print current directory", "pwd", shell_pwd},
118 {"unset", "Unset environment variable", "unset VAR", shell_unset}, 122 {"set", "Set environment variable", "set [VAR=value]", shell_set},
119 //{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo}, 123 {"unset", "Unset environment variable", "unset VAR", shell_unset},
120 {".", "Source-in and run commands in a file", ". filename", shell_source}, 124 {".", "Source-in and run commands in a file", ". filename",
121 {"help", "List shell built-in commands", "help", shell_help}, 125 shell_source},
122 {NULL, NULL, NULL, NULL} 126 {"help", "List shell built-in commands", "help", shell_help},
127 {NULL, NULL, NULL, NULL}
123}; 128};
124 129
125static const char shell_usage[] = 130static const char shell_usage[] =
126 "sh [FILE]...\n\n" 131 "sh [FILE]...\n\n" "The BusyBox command interpreter (shell).\n\n";
127 "The BusyBox command interpreter (shell).\n\n";
128 132
129 133
130static char cwd[1024]; 134static char cwd[1024];
131static char *prompt = "# "; 135static char *prompt = "# ";
132 136
133 137
138
134/* built-in 'cd <path>' handler */ 139/* built-in 'cd <path>' handler */
135static int shell_cd(struct job* cmd, struct jobSet* junk) 140static int shell_cd(struct job *cmd, struct jobSet *junk)
136{ 141{
137 char *newdir; 142 char *newdir;
138 if (!cmd->progs[0].argv[1] == 1) 143 if (!cmd->progs[0].argv[1] == 1)
139 newdir = getenv("HOME"); 144 newdir = getenv("HOME");
140 else 145 else
141 newdir = cmd->progs[0].argv[1]; 146 newdir = cmd->progs[0].argv[1];
142 if (chdir(newdir)) { 147 if (chdir(newdir)) {
143 printf("cd: %s: %s\n", newdir, strerror(errno)); 148 printf("cd: %s: %s\n", newdir, strerror(errno));
144 return FALSE; 149 return FALSE;
145 } 150 }
146 getcwd(cwd, sizeof(cwd)); 151 getcwd(cwd, sizeof(cwd));
147 152
148 return TRUE; 153 return TRUE;
149} 154}
150 155
151/* built-in 'env' handler */ 156/* built-in 'env' handler */
152static int shell_env(struct job* dummy, struct jobSet* junk) 157static int shell_env(struct job *dummy, struct jobSet *junk)
153{ 158{
154 char **e; 159 char **e;
155 160
156 for (e = environ ; *e ; e++) { 161 for (e = environ; *e; e++) {
157 fprintf(stdout, "%s\n", *e); 162 fprintf(stdout, "%s\n", *e);
158 } 163 }
159 return (0); 164 return (0);
160} 165}
161 166
162/* built-in 'exit' handler */ 167/* built-in 'exit' handler */
163static int shell_exit(struct job* cmd, struct jobSet* junk) 168static int shell_exit(struct job *cmd, struct jobSet *junk)
164{ 169{
165 if (!cmd->progs[0].argv[1] == 1) 170 if (!cmd->progs[0].argv[1] == 1)
166 exit TRUE; 171 exit TRUE;
167 else 172 else
168 exit(atoi(cmd->progs[0].argv[1])); 173 exit(atoi(cmd->progs[0].argv[1]));
169} 174}
170 175
171/* built-in 'fg' and 'bg' handler */ 176/* built-in 'fg' and 'bg' handler */
172static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) 177static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
173{ 178{
174 int i, jobNum; 179 int i, jobNum;
175 struct job* job; 180 struct job *job;
176 181
177 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { 182 if (!jobList->head) {
178 fprintf(stderr, "%s: exactly one argument is expected\n", 183 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
179 cmd->progs[0].argv[0]); 184 fprintf(stderr, "%s: exactly one argument is expected\n",
180 return FALSE; 185 cmd->progs[0].argv[0]);
181 } 186 return FALSE;
182 187 }
183 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { 188 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) {
184 fprintf(stderr, "%s: bad argument '%s'\n", 189 fprintf(stderr, "%s: bad argument '%s'\n",
185 cmd->progs[0].argv[0], cmd->progs[0].argv[1]); 190 cmd->progs[0].argv[0], cmd->progs[0].argv[1]);
186 return FALSE; 191 return FALSE;
187 } 192 }
188 193 } else {
189 for (job = jobList->head; job; job = job->next) 194 job = jobList->head;
190 if (job->jobId == jobNum) break; 195 }
191 196
192 if (!job) { 197 for (job = jobList->head; job; job = job->next)
193 fprintf(stderr, "%s: unknown job %d\n", 198 if (job->jobId == jobNum)
194 cmd->progs[0].argv[0], jobNum); 199 break;
195 return FALSE; 200
196 } 201 if (!job) {
197 202 fprintf(stderr, "%s: unknown job %d\n",
198 if (*cmd->progs[0].argv[0] == 'f') { 203 cmd->progs[0].argv[0], jobNum);
199 /* Make this job the foreground job */ 204 return FALSE;
200 205 }
201 if (tcsetpgrp(0, job->pgrp)) 206
202 perror("tcsetpgrp"); 207 if (*cmd->progs[0].argv[0] == 'f') {
203 jobList->fg = job; 208 /* Make this job the foreground job */
204 } 209
205 210 if (tcsetpgrp(0, job->pgrp))
206 /* Restart the processes in the job */ 211 perror("tcsetpgrp");
207 for (i = 0; i < job->numProgs; i++) 212 jobList->fg = job;
208 job->progs[i].isStopped = 0; 213 }
209 214
210 kill(-job->pgrp, SIGCONT); 215 /* Restart the processes in the job */
211 216 for (i = 0; i < job->numProgs; i++)
212 job->stoppedProgs = 0; 217 job->progs[i].isStopped = 0;
213 218
214 return TRUE; 219 kill(-job->pgrp, SIGCONT);
220
221 job->stoppedProgs = 0;
222
223 return TRUE;
215} 224}
216 225
217/* built-in 'help' handler */ 226/* built-in 'help' handler */
218static int shell_help(struct job* cmd, struct jobSet* junk) 227static int shell_help(struct job *cmd, struct jobSet *junk)
219{ 228{
220 struct builtInCommand *x; 229 struct builtInCommand *x;
221 230
222 fprintf(stdout, "\nBuilt-in commands:\n"); 231 fprintf(stdout, "\nBuilt-in commands:\n");
223 fprintf(stdout, "-------------------\n"); 232 fprintf(stdout, "-------------------\n");
224 for ( x=bltins; x->cmd; x++) { 233 for (x = bltins; x->cmd; x++) {
225 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 234 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
226 } 235 }
227 fprintf(stdout, "\n\n"); 236 fprintf(stdout, "\n\n");
228 return TRUE; 237 return TRUE;
229} 238}
230 239
231/* built-in 'jobs' handler */ 240/* built-in 'jobs' handler */
232static int shell_jobs(struct job* dummy, struct jobSet* jobList) 241static int shell_jobs(struct job *dummy, struct jobSet *jobList)
233{ 242{
234 struct job * job; 243 struct job *job;
235 char * statusString; 244 char *statusString;
236 for (job = jobList->head; job; job = job->next) { 245 for (job = jobList->head; job; job = job->next) {
237 if (job->runningProgs == job->stoppedProgs) 246 if (job->runningProgs == job->stoppedProgs)
238 statusString = "Stopped"; 247 statusString = "Stopped";
239 else 248 else
240 statusString = "Running"; 249 statusString = "Running";
241 250
242 printf(JOB_STATUS_FORMAT, job->jobId, statusString, 251 printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text);
243 job->text); 252 }
244 } 253 return TRUE;
245 return TRUE;
246} 254}
247 255
248 256
249/* built-in 'pwd' handler */ 257/* built-in 'pwd' handler */
250static int shell_pwd(struct job* dummy, struct jobSet* junk) 258static int shell_pwd(struct job *dummy, struct jobSet *junk)
251{ 259{
252 getcwd(cwd, sizeof(cwd)); 260 getcwd(cwd, sizeof(cwd));
253 fprintf(stdout, "%s\n", cwd); 261 fprintf(stdout, "%s\n", cwd);
254 return TRUE; 262 return TRUE;
255} 263}
256 264
257/* built-in 'set VAR=value' handler */ 265/* built-in 'set VAR=value' handler */
258static int shell_set(struct job* cmd, struct jobSet* junk) 266static int shell_set(struct job *cmd, struct jobSet *junk)
259{ 267{
260 int res; 268 int res;
261 269
262 if (!cmd->progs[0].argv[1] == 1) { 270 if (!cmd->progs[0].argv[1] == 1) {
263 return (shell_env(cmd, junk)); 271 return (shell_env(cmd, junk));
264 } 272 }
265 res = putenv(cmd->progs[0].argv[1]); 273 res = putenv(cmd->progs[0].argv[1]);
266 if (res) 274 if (res)
267 fprintf(stdout, "set: %s\n", strerror(errno)); 275 fprintf(stdout, "set: %s\n", strerror(errno));
268 return (res); 276 return (res);
269} 277}
270 278
271/* Built-in '.' handler (read-in and execute commands from file) */ 279/* Built-in '.' handler (read-in and execute commands from file) */
272static int shell_source(struct job* cmd, struct jobSet* junk) 280static int shell_source(struct job *cmd, struct jobSet *junk)
273{ 281{
274 FILE *input; 282 FILE *input;
275 int status; 283 int status;
276
277 if (!cmd->progs[0].argv[1] == 1)
278 return FALSE;
279
280 input = fopen(cmd->progs[0].argv[1], "r");
281 if (!input) {
282 fprintf(stdout, "Couldn't open file '%s'\n", cmd->progs[0].argv[1]);
283 return FALSE;
284 }
285 284
286 /* Now run the file */ 285 if (!cmd->progs[0].argv[1] == 1)
287 status = busy_loop(input); 286 return FALSE;
288 return (status); 287
288 input = fopen(cmd->progs[0].argv[1], "r");
289 if (!input) {
290 fprintf(stdout, "Couldn't open file '%s'\n",
291 cmd->progs[0].argv[1]);
292 return FALSE;
293 }
294
295 /* Now run the file */
296 status = busy_loop(input);
297 return (status);
289} 298}
290 299
291/* built-in 'unset VAR' handler */ 300/* built-in 'unset VAR' handler */
292static int shell_unset(struct job* cmd, struct jobSet* junk) 301static int shell_unset(struct job *cmd, struct jobSet *junk)
293{ 302{
294 if (!cmd->progs[0].argv[1] == 1) { 303 if (!cmd->progs[0].argv[1] == 1) {
295 fprintf(stdout, "unset: parameter required.\n"); 304 fprintf(stdout, "unset: parameter required.\n");
296 return FALSE; 305 return FALSE;
297 } 306 }
298 unsetenv(cmd->progs[0].argv[1]); 307 unsetenv(cmd->progs[0].argv[1]);
299 return TRUE; 308 return TRUE;
300} 309}
301 310
302/* free up all memory from a job */ 311/* free up all memory from a job */
303static void freeJob(struct job * cmd) 312static void freeJob(struct job *cmd)
304{ 313{
305 int i; 314 int i;
306 315
307 for (i = 0; i < cmd->numProgs; i++) { 316 for (i = 0; i < cmd->numProgs; i++) {
308 free(cmd->progs[i].argv); 317 free(cmd->progs[i].argv);
309 if (cmd->progs[i].redirections) free(cmd->progs[i].redirections); 318 if (cmd->progs[i].redirections)
310 if (cmd->progs[i].freeGlob) globfree(&cmd->progs[i].globResult); 319 free(cmd->progs[i].redirections);
320 if (cmd->progs[i].freeGlob)
321 globfree(&cmd->progs[i].globResult);
311 } 322 }
312 free(cmd->progs); 323 free(cmd->progs);
313 if (cmd->text) free(cmd->text); 324 if (cmd->text)
325 free(cmd->text);
314 free(cmd->cmdBuf); 326 free(cmd->cmdBuf);
315} 327}
316 328
317/* remove a job from the jobList */ 329/* remove a job from the jobList */
318static void removeJob(struct jobSet * jobList, struct job * job) 330static void removeJob(struct jobSet *jobList, struct job *job)
319{ 331{
320 struct job * prevJob; 332 struct job *prevJob;
321 333
322 freeJob(job); 334 freeJob(job);
323 if (job == jobList->head) { 335 if (job == jobList->head) {
324 jobList->head = job->next; 336 jobList->head = job->next;
325 } else { 337 } else {
326 prevJob = jobList->head; 338 prevJob = jobList->head;
327 while (prevJob->next != job) prevJob = prevJob->next; 339 while (prevJob->next != job)
328 prevJob->next = job->next; 340 prevJob = prevJob->next;
341 prevJob->next = job->next;
329 } 342 }
330 343
331 free(job); 344 free(job);
@@ -333,56 +346,62 @@ static void removeJob(struct jobSet * jobList, struct job * job)
333 346
334/* Checks to see if any background processes have exited -- if they 347/* Checks to see if any background processes have exited -- if they
335 have, figure out why and see if a job has completed */ 348 have, figure out why and see if a job has completed */
336static void checkJobs(struct jobSet * jobList) 349static void checkJobs(struct jobSet *jobList)
337{ 350{
338 struct job * job; 351 struct job *job;
339 pid_t childpid; 352 pid_t childpid;
340 int status; 353 int status;
341 int progNum=0; 354 int progNum = 0;
342 355
343 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { 356 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
344 for (job = jobList->head; job; job = job->next) { 357 for (job = jobList->head; job; job = job->next) {
345 progNum = 0; 358 progNum = 0;
346 while (progNum < job->numProgs && 359 while (progNum < job->numProgs &&
347 job->progs[progNum].pid != childpid) 360 job->progs[progNum].pid != childpid) progNum++;
348 progNum++; 361 if (progNum < job->numProgs)
349 if (progNum < job->numProgs) break; 362 break;
350 } 363 }
351 364
352 if (WIFEXITED(status) || WIFSIGNALED(status)) { 365 if (WIFEXITED(status) || WIFSIGNALED(status)) {
353 /* child exited */ 366 /* child exited */
354 job->runningProgs--; 367 job->runningProgs--;
355 job->progs[progNum].pid = 0; 368 job->progs[progNum].pid = 0;
356 369
357 if (!job->runningProgs) { 370 if (!job->runningProgs) {
358 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text); 371 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text);
359 removeJob(jobList, job); 372 removeJob(jobList, job);
360 } 373 }
361 } else { 374 } else {
362 /* child stopped */ 375 /* child stopped */
363 job->stoppedProgs++; 376 job->stoppedProgs++;
364 job->progs[progNum].isStopped = 1; 377 job->progs[progNum].isStopped = 1;
365 378
366 if (job->stoppedProgs == job->numProgs) { 379 if (job->stoppedProgs == job->numProgs) {
367 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", job->text); 380 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped",
368 } 381 job->text);
369 } 382 }
383 }
370 } 384 }
371 385
372 if (childpid == -1 && errno != ECHILD) 386 if (childpid == -1 && errno != ECHILD)
373 perror("waitpid"); 387 perror("waitpid");
374} 388}
375 389
376static int getCommand(FILE * source, char * command) 390static int getCommand(FILE * source, char *command)
377{ 391{
378 if (source == stdin) { 392 if (source == stdin) {
379 fprintf(stdout, "%s %s", cwd, prompt); 393 fprintf(stdout, "BBSHELL %s %s", cwd, prompt);
380 fflush(stdout); 394 fflush(stdout);
395#ifdef BB_FEATURE_SH_COMMAND_EDITING
396 cmdedit_read_input(fileno(stdin), fileno(stdout), command);
397 return 0;
398#endif
381 } 399 }
382 400
383 if (!fgets(command, MAX_COMMAND_LEN, source)) { 401 if (!fgets(command, BUFSIZ - 2, source)) {
384 if (source == stdin) printf("\n"); 402 if (source == stdin)
385 return 1; 403 printf("\n");
404 return 1;
386 } 405 }
387 406
388 /* remove trailing newline */ 407 /* remove trailing newline */
@@ -391,46 +410,48 @@ static int getCommand(FILE * source, char * command)
391 return 0; 410 return 0;
392} 411}
393 412
394static void globLastArgument(struct childProgram * prog, int * argcPtr, 413static void globLastArgument(struct childProgram *prog, int *argcPtr,
395 int * argcAllocedPtr) 414 int *argcAllocedPtr)
396{ 415{
397 int argc = *argcPtr; 416 int argc = *argcPtr;
398 int argcAlloced = *argcAllocedPtr; 417 int argcAlloced = *argcAllocedPtr;
399 int rc; 418 int rc;
400 int flags; 419 int flags;
401 int i; 420 int i;
402 char * src, * dst; 421 char *src, *dst;
403 422
404 if (argc > 1) { /* cmd->globResult is already initialized */ 423 if (argc > 1) { /* cmd->globResult is already initialized */
405 flags = GLOB_APPEND; 424 flags = GLOB_APPEND;
406 i = prog->globResult.gl_pathc; 425 i = prog->globResult.gl_pathc;
407 } else { 426 } else {
408 prog->freeGlob = 1; 427 prog->freeGlob = 1;
409 flags = 0; 428 flags = 0;
410 i = 0; 429 i = 0;
411 } 430 }
412 431
413 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); 432 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);
414 if (rc == GLOB_NOSPACE) { 433 if (rc == GLOB_NOSPACE) {
415 fprintf(stderr, "out of space during glob operation\n"); 434 fprintf(stderr, "out of space during glob operation\n");
416 return; 435 return;
417 } else if (rc == GLOB_NOMATCH || 436 } else if (rc == GLOB_NOMATCH ||
418 (!rc && (prog->globResult.gl_pathc - i) == 1 && 437 (!rc && (prog->globResult.gl_pathc - i) == 1 &&
419 !strcmp(prog->argv[argc - 1], 438 !strcmp(prog->argv[argc - 1],
420 prog->globResult.gl_pathv[i]))) { 439 prog->globResult.gl_pathv[i]))) {
421 /* we need to remove whatever \ quoting is still present */ 440 /* we need to remove whatever \ quoting is still present */
422 src = dst = prog->argv[argc - 1]; 441 src = dst = prog->argv[argc - 1];
423 while (*src) { 442 while (*src) {
424 if (*src != '\\') *dst++ = *src; 443 if (*src != '\\')
425 src++; 444 *dst++ = *src;
426 } 445 src++;
427 *dst = '\0'; 446 }
447 *dst = '\0';
428 } else if (!rc) { 448 } else if (!rc) {
429 argcAlloced += (prog->globResult.gl_pathc - i); 449 argcAlloced += (prog->globResult.gl_pathc - i);
430 prog->argv = realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 450 prog->argv =
431 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, 451 realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
432 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 452 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
433 argc += (prog->globResult.gl_pathc - i - 1); 453 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
454 argc += (prog->globResult.gl_pathc - i - 1);
434 } 455 }
435 456
436 *argcAllocedPtr = argcAlloced; 457 *argcAllocedPtr = argcAlloced;
@@ -442,27 +463,28 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
442 the beginning of the next command (if the original command had more 463 the beginning of the next command (if the original command had more
443 then one job associated with it) or NULL if no more commands are 464 then one job associated with it) or NULL if no more commands are
444 present. */ 465 present. */
445static int parseCommand(char ** commandPtr, struct job * job, int * isBg) 466static int parseCommand(char **commandPtr, struct job *job, int *isBg)
446{ 467{
447 char * command; 468 char *command;
448 char * returnCommand = NULL; 469 char *returnCommand = NULL;
449 char * src, * buf, * chptr; 470 char *src, *buf, *chptr;
450 int argc = 0; 471 int argc = 0;
451 int done = 0; 472 int done = 0;
452 int argvAlloced; 473 int argvAlloced;
453 int i; 474 int i;
454 char quote = '\0'; 475 char quote = '\0';
455 int count; 476 int count;
456 struct childProgram * prog; 477 struct childProgram *prog;
457 478
458 /* skip leading white space */ 479 /* skip leading white space */
459 while (**commandPtr && isspace(**commandPtr)) (*commandPtr)++; 480 while (**commandPtr && isspace(**commandPtr))
460 481 (*commandPtr)++;
461 /* this handles empty lines or leading '#' characters */ 482
462 if (!**commandPtr || (**commandPtr=='#')) { 483 /* this handles empty lines or leading '#' characters */
463 job->numProgs = 0; 484 if (!**commandPtr || (**commandPtr == '#')) {
464 *commandPtr = NULL; 485 job->numProgs = 0;
465 return 0; 486 *commandPtr = NULL;
487 return 0;
466 } 488 }
467 489
468 *isBg = 0; 490 *isBg = 0;
@@ -491,177 +513,185 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
491 buf = command; 513 buf = command;
492 src = *commandPtr; 514 src = *commandPtr;
493 while (*src && !done) { 515 while (*src && !done) {
494 if (quote == *src) { 516 if (quote == *src) {
495 quote = '\0'; 517 quote = '\0';
496 } else if (quote) { 518 } else if (quote) {
497 if (*src == '\\') { 519 if (*src == '\\') {
498 src++; 520 src++;
499 if (!*src) { 521 if (!*src) {
500 fprintf(stderr, "character expected after \\\n"); 522 fprintf(stderr, "character expected after \\\n");
501 freeJob(job); 523 freeJob(job);
502 return 1; 524 return 1;
503 } 525 }
504 526
505 /* in shell, "\'" should yield \' */ 527 /* in shell, "\'" should yield \' */
506 if (*src != quote) *buf++ = '\\'; 528 if (*src != quote)
507 } else if (*src == '*' || *src == '?' || *src == '[' || 529 *buf++ = '\\';
508 *src == ']') 530 } else if (*src == '*' || *src == '?' || *src == '[' ||
509 *buf++ = '\\'; 531 *src == ']') *buf++ = '\\';
510 *buf++ = *src; 532 *buf++ = *src;
511 } else if (isspace(*src)) { 533 } else if (isspace(*src)) {
512 if (*prog->argv[argc]) { 534 if (*prog->argv[argc]) {
513 buf++, argc++; 535 buf++, argc++;
514 /* +1 here leaves room for the NULL which ends argv */ 536 /* +1 here leaves room for the NULL which ends argv */
515 if ((argc + 1) == argvAlloced) { 537 if ((argc + 1) == argvAlloced) {
516 argvAlloced += 5; 538 argvAlloced += 5;
517 prog->argv = realloc(prog->argv, 539 prog->argv = realloc(prog->argv,
518 sizeof(*prog->argv) * argvAlloced); 540 sizeof(*prog->argv) *
519 } 541 argvAlloced);
520 prog->argv[argc] = buf; 542 }
521 543 prog->argv[argc] = buf;
522 globLastArgument(prog, &argc, &argvAlloced); 544
523 } 545 globLastArgument(prog, &argc, &argvAlloced);
524 } else switch (*src) { 546 }
525 case '"': 547 } else
526 case '\'': 548 switch (*src) {
527 quote = *src; 549 case '"':
528 break; 550 case '\'':
529 551 quote = *src;
530 case '#': /* comment */ 552 break;
531 done = 1; 553
532 break; 554 case '#': /* comment */
533 555 done = 1;
534 case '>': /* redirections */ 556 break;
535 case '<': 557
536 i = prog->numRedirections++; 558 case '>': /* redirections */
537 prog->redirections = realloc(prog->redirections, 559 case '<':
538 sizeof(*prog->redirections) * (i + 1)); 560 i = prog->numRedirections++;
539 561 prog->redirections = realloc(prog->redirections,
540 prog->redirections[i].fd = -1; 562 sizeof(*prog->redirections) *
541 if (buf != prog->argv[argc]) { 563 (i + 1));
542 /* the stuff before this character may be the file number 564
543 being redirected */ 565 prog->redirections[i].fd = -1;
544 prog->redirections[i].fd = strtol(prog->argv[argc], &chptr, 10); 566 if (buf != prog->argv[argc]) {
545 567 /* the stuff before this character may be the file number
546 if (*chptr && *prog->argv[argc]) { 568 being redirected */
547 buf++, argc++; 569 prog->redirections[i].fd =
548 globLastArgument(prog, &argc, &argvAlloced); 570 strtol(prog->argv[argc], &chptr, 10);
549 } 571
550 } 572 if (*chptr && *prog->argv[argc]) {
551 573 buf++, argc++;
552 if (prog->redirections[i].fd == -1) { 574 globLastArgument(prog, &argc, &argvAlloced);
553 if (*src == '>') 575 }
554 prog->redirections[i].fd = 1; 576 }
555 else 577
556 prog->redirections[i].fd = 0; 578 if (prog->redirections[i].fd == -1) {
557 } 579 if (*src == '>')
558 580 prog->redirections[i].fd = 1;
559 if (*src++ == '>') { 581 else
560 if (*src == '>') 582 prog->redirections[i].fd = 0;
561 prog->redirections[i].type = REDIRECT_APPEND, src++; 583 }
562 else 584
563 prog->redirections[i].type = REDIRECT_OVERWRITE; 585 if (*src++ == '>') {
564 } else { 586 if (*src == '>')
565 prog->redirections[i].type = REDIRECT_INPUT; 587 prog->redirections[i].type =
566 } 588 REDIRECT_APPEND, src++;
567 589 else
568 /* This isn't POSIX sh compliant. Oh well. */ 590 prog->redirections[i].type = REDIRECT_OVERWRITE;
569 chptr = src; 591 } else {
570 while (isspace(*chptr)) chptr++; 592 prog->redirections[i].type = REDIRECT_INPUT;
571 593 }
572 if (!*chptr) { 594
573 fprintf(stderr, "file name expected after %c\n", *src); 595 /* This isn't POSIX sh compliant. Oh well. */
574 freeJob(job); 596 chptr = src;
575 return 1; 597 while (isspace(*chptr))
576 } 598 chptr++;
577 599
578 prog->redirections[i].filename = buf; 600 if (!*chptr) {
579 while (*chptr && !isspace(*chptr)) 601 fprintf(stderr, "file name expected after %c\n", *src);
580 *buf++ = *chptr++; 602 freeJob(job);
581 603 return 1;
582 src = chptr - 1; /* we src++ later */ 604 }
583 prog->argv[argc] = ++buf; 605
584 break; 606 prog->redirections[i].filename = buf;
585 607 while (*chptr && !isspace(*chptr))
586 case '|': /* pipe */ 608 *buf++ = *chptr++;
587 /* finish this command */ 609
588 if (*prog->argv[argc]) argc++; 610 src = chptr - 1; /* we src++ later */
589 if (!argc) { 611 prog->argv[argc] = ++buf;
590 fprintf(stderr, "empty command in pipe\n"); 612 break;
591 freeJob(job); 613
592 return 1; 614 case '|': /* pipe */
593 } 615 /* finish this command */
594 prog->argv[argc] = NULL; 616 if (*prog->argv[argc])
595 617 argc++;
596 /* and start the next */ 618 if (!argc) {
597 job->numProgs++; 619 fprintf(stderr, "empty command in pipe\n");
598 job->progs = realloc(job->progs, 620 freeJob(job);
599 sizeof(*job->progs) * job->numProgs); 621 return 1;
600 prog = job->progs + (job->numProgs - 1); 622 }
601 prog->numRedirections = 0; 623 prog->argv[argc] = NULL;
602 prog->redirections = NULL; 624
603 prog->freeGlob = 0; 625 /* and start the next */
604 argc = 0; 626 job->numProgs++;
605 627 job->progs = realloc(job->progs,
606 argvAlloced = 5; 628 sizeof(*job->progs) * job->numProgs);
607 prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); 629 prog = job->progs + (job->numProgs - 1);
608 prog->argv[0] = ++buf; 630 prog->numRedirections = 0;
609 631 prog->redirections = NULL;
610 src++; 632 prog->freeGlob = 0;
611 while (*src && isspace(*src)) src++; 633 argc = 0;
612 634
613 if (!*src) { 635 argvAlloced = 5;
614 fprintf(stderr, "empty command in pipe\n"); 636 prog->argv = malloc(sizeof(*prog->argv) * argvAlloced);
615 return 1; 637 prog->argv[0] = ++buf;
616 } 638
617 src--; /* we'll ++ it at the end of the loop */ 639 src++;
618 640 while (*src && isspace(*src))
619 break; 641 src++;
620 642
621 case '&': /* background */ 643 if (!*src) {
622 *isBg = 1; 644 fprintf(stderr, "empty command in pipe\n");
623 case ';': /* multiple commands */ 645 return 1;
624 done = 1; 646 }
625 returnCommand = *commandPtr + (src - *commandPtr) + 1; 647 src--; /* we'll ++ it at the end of the loop */
626 break; 648
627 649 break;
628 case '\\': 650
629 src++; 651 case '&': /* background */
630 if (!*src) { 652 *isBg = 1;
631 freeJob(job); 653 case ';': /* multiple commands */
632 fprintf(stderr, "character expected after \\\n"); 654 done = 1;
633 return 1; 655 returnCommand = *commandPtr + (src - *commandPtr) + 1;
634 } 656 break;
635 if (*src == '*' || *src == '[' || *src == ']' || *src == '?') 657
636 *buf++ = '\\'; 658 case '\\':
637 /* fallthrough */ 659 src++;
638 default: 660 if (!*src) {
639 *buf++ = *src; 661 freeJob(job);
640 } 662 fprintf(stderr, "character expected after \\\n");
641 663 return 1;
642 src++; 664 }
665 if (*src == '*' || *src == '[' || *src == ']'
666 || *src == '?') *buf++ = '\\';
667 /* fallthrough */
668 default:
669 *buf++ = *src;
670 }
671
672 src++;
643 } 673 }
644 674
645 if (*prog->argv[argc]) { 675 if (*prog->argv[argc]) {
646 argc++; 676 argc++;
647 globLastArgument(prog, &argc, &argvAlloced); 677 globLastArgument(prog, &argc, &argvAlloced);
648 } 678 }
649 if (!argc) { 679 if (!argc) {
650 freeJob(job); 680 freeJob(job);
651 return 0; 681 return 0;
652 } 682 }
653 prog->argv[argc] = NULL; 683 prog->argv[argc] = NULL;
654 684
655 if (!returnCommand) { 685 if (!returnCommand) {
656 job->text = malloc(strlen(*commandPtr) + 1); 686 job->text = malloc(strlen(*commandPtr) + 1);
657 strcpy(job->text, *commandPtr); 687 strcpy(job->text, *commandPtr);
658 } else { 688 } else {
659 /* This leaves any trailing spaces, which is a bit sloppy */ 689 /* This leaves any trailing spaces, which is a bit sloppy */
660 690
661 count = returnCommand - *commandPtr; 691 count = returnCommand - *commandPtr;
662 job->text = malloc(count + 1); 692 job->text = malloc(count + 1);
663 strncpy(job->text, *commandPtr, count); 693 strncpy(job->text, *commandPtr, count);
664 job->text[count] = '\0'; 694 job->text[count] = '\0';
665 } 695 }
666 696
667 *commandPtr = returnCommand; 697 *commandPtr = returnCommand;
@@ -669,63 +699,64 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
669 return 0; 699 return 0;
670} 700}
671 701
672static int runCommand(struct job newJob, struct jobSet * jobList, 702static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
673 int inBg)
674{ 703{
675 struct job * job; 704 struct job *job;
676 int i; 705 int i;
677 int nextin, nextout; 706 int nextin, nextout;
678 int pipefds[2]; /* pipefd[0] is for reading */ 707 int pipefds[2]; /* pipefd[0] is for reading */
679 struct builtInCommand *x; 708 struct builtInCommand *x;
680 709
681 /* handle built-ins here -- we don't fork() so we can't background 710 /* handle built-ins here -- we don't fork() so we can't background
682 these very easily */ 711 these very easily */
683 for( x=bltins ; x->cmd ; x++) { 712 for (x = bltins; x->cmd; x++) {
684 if (!strcmp(newJob.progs[0].argv[0], x->cmd)) { 713 if (!strcmp(newJob.progs[0].argv[0], x->cmd)) {
685 return(x->function(&newJob, jobList)); 714 return (x->function(&newJob, jobList));
686 } 715 }
687 } 716 }
688 717
689 nextin = 0, nextout = 1; 718 nextin = 0, nextout = 1;
690 for (i = 0; i < newJob.numProgs; i++) { 719 for (i = 0; i < newJob.numProgs; i++) {
691 if ((i + 1) < newJob.numProgs) { 720 if ((i + 1) < newJob.numProgs) {
692 pipe(pipefds); 721 pipe(pipefds);
693 nextout = pipefds[1]; 722 nextout = pipefds[1];
694 } else { 723 } else {
695 nextout = 1; 724 nextout = 1;
696 } 725 }
697 726
698 if (!(newJob.progs[i].pid = fork())) { 727 if (!(newJob.progs[i].pid = fork())) {
699 signal(SIGTTOU, SIG_DFL); 728 signal(SIGTTOU, SIG_DFL);
700 729
701 if (nextin != 0) { 730 if (nextin != 0) {
702 dup2(nextin, 0); 731 dup2(nextin, 0);
703 close(nextin); 732 close(nextin);
704 } 733 }
705 734
706 if (nextout != 1) { 735 if (nextout != 1) {
707 dup2(nextout, 1); 736 dup2(nextout, 1);
708 close(nextout); 737 close(nextout);
709 } 738 }
710 739
711 /* explicit redirections override pipes */ 740 /* explicit redirections override pipes */
712 setupRedirections(newJob.progs + i); 741 setupRedirections(newJob.progs + i);
713 742
714 execvp(newJob.progs[i].argv[0], newJob.progs[i].argv); 743 execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);
715 fatalError( "sh: %s: %s\n", newJob.progs[i].argv[0], 744 fatalError("sh: %s: %s\n", newJob.progs[i].argv[0],
716 strerror(errno)); 745 strerror(errno));
717 } 746 }
718 747
719 /* put our child in the process group whose leader is the 748 /* put our child in the process group whose leader is the
720 first process in this pipe */ 749 first process in this pipe */
721 setpgid(newJob.progs[i].pid, newJob.progs[0].pid); 750 setpgid(newJob.progs[i].pid, newJob.progs[0].pid);
722 751
723 if (nextin != 0) close(nextin); 752 if (nextin != 0)
724 if (nextout != 1) close(nextout); 753 close(nextin);
725 754 if (nextout != 1)
726 /* If there isn't another process, nextin is garbage 755 close(nextout);
727 but it doesn't matter */ 756
728 nextin = pipefds[0]; 757 /* If there isn't another process, nextin is garbage
758 but it doesn't matter */
759 nextin = pipefds[0];
729 } 760 }
730 761
731 newJob.pgrp = newJob.progs[0].pid; 762 newJob.pgrp = newJob.progs[0].pid;
@@ -733,16 +764,16 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
733 /* find the ID for the job to use */ 764 /* find the ID for the job to use */
734 newJob.jobId = 1; 765 newJob.jobId = 1;
735 for (job = jobList->head; job; job = job->next) 766 for (job = jobList->head; job; job = job->next)
736 if (job->jobId >= newJob.jobId) 767 if (job->jobId >= newJob.jobId)
737 newJob.jobId = job->jobId + 1; 768 newJob.jobId = job->jobId + 1;
738 769
739 /* add the job to the list of running jobs */ 770 /* add the job to the list of running jobs */
740 if (!jobList->head) { 771 if (!jobList->head) {
741 job = jobList->head = malloc(sizeof(*job)); 772 job = jobList->head = malloc(sizeof(*job));
742 } else { 773 } else {
743 for (job = jobList->head; job->next; job = job->next); 774 for (job = jobList->head; job->next; job = job->next);
744 job->next = malloc(sizeof(*job)); 775 job->next = malloc(sizeof(*job));
745 job = job->next; 776 job = job->next;
746 } 777 }
747 778
748 *job = newJob; 779 *job = newJob;
@@ -751,165 +782,177 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
751 job->stoppedProgs = 0; 782 job->stoppedProgs = 0;
752 783
753 if (inBg) { 784 if (inBg) {
754 /* we don't wait for background jobs to return -- append it 785 /* we don't wait for background jobs to return -- append it
755 to the list of backgrounded jobs and leave it alone */ 786 to the list of backgrounded jobs and leave it alone */
756 787
757 printf("[%d] %d\n", job->jobId, 788 printf("[%d] %d\n", job->jobId,
758 newJob.progs[newJob.numProgs - 1].pid); 789 newJob.progs[newJob.numProgs - 1].pid);
759 } else { 790 } else {
760 jobList->fg = job; 791 jobList->fg = job;
792
793 /* move the new process group into the foreground */
761 794
762 /* move the new process group into the foreground */ 795 if (tcsetpgrp(0, newJob.pgrp))
763 796 perror("tcsetpgrp");
764 if (tcsetpgrp(0, newJob.pgrp))
765 perror("tcsetpgrp");
766 } 797 }
767 798
768 return 0; 799 return 0;
769} 800}
770 801
771static int setupRedirections(struct childProgram * prog) 802static int setupRedirections(struct childProgram *prog)
772{ 803{
773 int i; 804 int i;
774 int openfd; 805 int openfd;
775 int mode=O_RDONLY; 806 int mode = O_RDONLY;
776 struct redirectionSpecifier * redir = prog->redirections; 807 struct redirectionSpecifier *redir = prog->redirections;
777 808
778 for (i = 0; i < prog->numRedirections; i++, redir++) { 809 for (i = 0; i < prog->numRedirections; i++, redir++) {
779 switch (redir->type) { 810 switch (redir->type) {
780 case REDIRECT_INPUT: 811 case REDIRECT_INPUT:
781 mode = O_RDONLY; 812 mode = O_RDONLY;
782 break; 813 break;
783 case REDIRECT_OVERWRITE: 814 case REDIRECT_OVERWRITE:
784 mode = O_RDWR | O_CREAT | O_TRUNC; 815 mode = O_RDWR | O_CREAT | O_TRUNC;
785 break; 816 break;
786 case REDIRECT_APPEND: 817 case REDIRECT_APPEND:
787 mode = O_RDWR | O_CREAT | O_APPEND; 818 mode = O_RDWR | O_CREAT | O_APPEND;
788 break; 819 break;
789 } 820 }
790 821
791 openfd = open(redir->filename, mode, 0666); 822 openfd = open(redir->filename, mode, 0666);
792 if (openfd < 0) { 823 if (openfd < 0) {
793 /* this could get lost if stderr has been redirected, but 824 /* this could get lost if stderr has been redirected, but
794 bash and ash both lose it as well (though zsh doesn't!) */ 825 bash and ash both lose it as well (though zsh doesn't!) */
795 fprintf(stderr, "error opening %s: %s\n", redir->filename, 826 fprintf(stderr, "error opening %s: %s\n", redir->filename,
796 strerror(errno)); 827 strerror(errno));
797 return 1; 828 return 1;
798 } 829 }
799 830
800 if (openfd != redir->fd) { 831 if (openfd != redir->fd) {
801 dup2(openfd, redir->fd); 832 dup2(openfd, redir->fd);
802 close(openfd); 833 close(openfd);
803 } 834 }
804 } 835 }
805 836
806 return 0; 837 return 0;
807} 838}
808 839
809 840
810static int busy_loop(FILE * input) 841static int busy_loop(FILE * input)
811{ 842{
812 char command[MAX_COMMAND_LEN + 1]; 843 char *command;
813 char * nextCommand = NULL; 844 char *nextCommand = NULL;
814 struct jobSet jobList = { NULL, NULL }; 845 struct jobSet jobList = { NULL, NULL };
815 struct job newJob; 846 struct job newJob;
816 int i; 847 int i;
817 int status; 848 int status;
818 int inBg; 849 int inBg;
819 850
851 command = (char*) calloc(BUFSIZ, sizeof(char));
852
820 /* don't pay any attention to this signal; it just confuses 853 /* don't pay any attention to this signal; it just confuses
821 things and isn't really meant for shells anyway */ 854 things and isn't really meant for shells anyway */
822 signal(SIGTTOU, SIG_IGN); 855 signal(SIGTTOU, SIG_IGN);
823 856
824 while (1) { 857 while (1) {
825 if (!jobList.fg) { 858 if (!jobList.fg) {
826 /* no job is in the foreground */ 859 /* no job is in the foreground */
827 860
828 /* see if any background processes have exited */ 861 /* see if any background processes have exited */
829 checkJobs(&jobList); 862 checkJobs(&jobList);
830 863
831 if (!nextCommand) { 864 if (!nextCommand) {
832 if (getCommand(input, command)) break; 865 if (getCommand(input, command))
833 nextCommand = command; 866 break;
834 } 867 nextCommand = command;
835 868 }
836 if (!parseCommand(&nextCommand, &newJob, &inBg) && 869
837 newJob.numProgs) { 870 if (!parseCommand(&nextCommand, &newJob, &inBg) &&
838 runCommand(newJob, &jobList, inBg); 871 newJob.numProgs) {
839 } 872 runCommand(newJob, &jobList, inBg);
840 } else { 873 }
841 /* a job is running in the foreground; wait for it */ 874 } else {
842 i = 0; 875 /* a job is running in the foreground; wait for it */
843 while (!jobList.fg->progs[i].pid || 876 i = 0;
844 jobList.fg->progs[i].isStopped) i++; 877 while (!jobList.fg->progs[i].pid ||
845 878 jobList.fg->progs[i].isStopped) i++;
846 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); 879
847 880 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
848 if (WIFEXITED(status) || WIFSIGNALED(status)) { 881
849 /* the child exited */ 882 if (WIFEXITED(status) || WIFSIGNALED(status)) {
850 jobList.fg->runningProgs--; 883 /* the child exited */
851 jobList.fg->progs[i].pid = 0; 884 jobList.fg->runningProgs--;
852 885 jobList.fg->progs[i].pid = 0;
853 if (!jobList.fg->runningProgs) { 886
854 /* child exited */ 887 if (!jobList.fg->runningProgs) {
855 888 /* child exited */
856 removeJob(&jobList, jobList.fg); 889
857 jobList.fg = NULL; 890 removeJob(&jobList, jobList.fg);
858 891 jobList.fg = NULL;
859 /* move the shell to the foreground */ 892
860 if (tcsetpgrp(0, getpid())) 893 /* move the shell to the foreground */
861 perror("tcsetpgrp"); 894 if (tcsetpgrp(0, getpid()))
862 } 895 perror("tcsetpgrp");
863 } else { 896 }
864 /* the child was stopped */ 897 } else {
865 jobList.fg->stoppedProgs++; 898 /* the child was stopped */
866 jobList.fg->progs[i].isStopped = 1; 899 jobList.fg->stoppedProgs++;
867 900 jobList.fg->progs[i].isStopped = 1;
868 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) { 901
869 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId, 902 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) {
870 "Stopped", jobList.fg->text); 903 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId,
871 jobList.fg = NULL; 904 "Stopped", jobList.fg->text);
872 } 905 jobList.fg = NULL;
873 } 906 }
874 907 }
875 if (!jobList.fg) { 908
876 /* move the shell to the foreground */ 909 if (!jobList.fg) {
877 if (tcsetpgrp(0, getpid())) 910 /* move the shell to the foreground */
878 perror("tcsetpgrp"); 911 if (tcsetpgrp(0, getpid()))
879 } 912 perror("tcsetpgrp");
880 } 913 }
881 } 914 }
915 }
916 free( command);
882 917
883 return 0; 918 return 0;
884} 919}
885 920
886 921
887int shell_main(int argc, char ** argv) 922int shell_main(int argc, char **argv)
888{ 923{
889 FILE * input = stdin; 924 FILE *input = stdin;
890 925
891 if (argc > 2) { 926 if (argc > 2) {
892 usage( shell_usage); 927 usage(shell_usage);
893 } 928 }
894 /* initialize the cwd */ 929 /* initialize the cwd */
895 getcwd(cwd, sizeof(cwd)); 930 getcwd(cwd, sizeof(cwd));
896 931
897 932
898 //if (argv[0] && argv[0][0] == '-') { 933 //if (argv[0] && argv[0][0] == '-') {
899 // shell_source("/etc/profile"); 934 // shell_source("/etc/profile");
900 //} 935 //}
901 936
902 if (argc < 2) { 937 if (argc < 2) {
903 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); 938 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER,
904 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); 939 BB_BT);
905 } else { 940 fprintf(stdout,
906 input = fopen(argv[1], "r"); 941 "Enter 'help' for a list of built-in commands.\n\n");
907 if (!input) 942 } else {
908 fatalError("A: Couldn't open file '%s': %s\n", argv[1], strerror(errno)); 943 input = fopen(argv[1], "r");
909// else 944 if (!input)
910// fatalError("Got it.\n"); 945 fatalError("A: Couldn't open file '%s': %s\n", argv[1],
911 //exit(shell_source(argv[1])); 946 strerror(errno));
912 } 947// else
913 948// fatalError("Got it.\n");
914 return (busy_loop( input)); 949 //exit(shell_source(argv[1]));
950
951 /* Set terminal IO to canonical mode, and save old term settings. */
952#ifdef BB_FEATURE_SH_COMMAND_EDITING
953 cmdedit_init();
954#endif
955 }
956
957 return (busy_loop(input));
915} 958}
diff --git a/utility.c b/utility.c
index d0ffda2a2..4b26a1b76 100644
--- a/utility.c
+++ b/utility.c
@@ -1247,7 +1247,7 @@ extern int device_open(char *device, int mode)
1247#endif /* BB_INIT BB_SYSLOGD */ 1247#endif /* BB_INIT BB_SYSLOGD */
1248 1248
1249 1249
1250#if defined BB_KILLALL || defined BB_FEATURE_LINUXRC && ( defined BB_HALT || defined BB_REBOOT || defined BB_POWEROFF ) 1250#if defined BB_FEATURE_LINUXRC && ( defined BB_HALT || defined BB_REBOOT || defined BB_POWEROFF )
1251 1251
1252#ifdef BB_FEATURE_USE_DEVPS_PATCH 1252#ifdef BB_FEATURE_USE_DEVPS_PATCH
1253#include <linux/devps.h> 1253#include <linux/devps.h>
@@ -1363,7 +1363,7 @@ extern pid_t findPidByName( char* pidName)
1363 return 0; 1363 return 0;
1364} 1364}
1365#endif /* BB_FEATURE_USE_DEVPS_PATCH */ 1365#endif /* BB_FEATURE_USE_DEVPS_PATCH */
1366#endif /* BB_INIT || BB_HALT || BB_REBOOT || BB_KILLALL || BB_POWEROFF */ 1366#endif /* BB_INIT || BB_HALT || BB_REBOOT || BB_POWEROFF */
1367 1367
1368#if defined BB_GUNZIP \ 1368#if defined BB_GUNZIP \
1369 || defined BB_GZIP \ 1369 || defined BB_GZIP \