diff options
author | Erik Andersen <andersen@codepoet.org> | 2000-03-16 08:09:09 +0000 |
---|---|---|
committer | Erik Andersen <andersen@codepoet.org> | 2000-03-16 08:09:09 +0000 |
commit | d75af99529879e6cd38164fd110732052a9cdda4 (patch) | |
tree | 3a6e672d0b0d5104cc3c33f65b20fdaacd365c2e | |
parent | a967e3c8f004d9d613e2f531a3bf7869f2e68b90 (diff) | |
download | busybox-w32-d75af99529879e6cd38164fd110732052a9cdda4.tar.gz busybox-w32-d75af99529879e6cd38164fd110732052a9cdda4.tar.bz2 busybox-w32-d75af99529879e6cd38164fd110732052a9cdda4.zip |
Major build system updates...
-Erik
-rw-r--r-- | Changelog | 5 | ||||
-rw-r--r-- | applets/busybox.c | 222 | ||||
-rwxr-xr-x | applets/busybox.mkll | 16 | ||||
-rwxr-xr-x | applets/busybox.sh | 5 | ||||
-rw-r--r-- | busybox.c | 222 | ||||
-rw-r--r-- | busybox.def.h | 74 | ||||
-rwxr-xr-x | busybox.mkll | 16 | ||||
-rwxr-xr-x | busybox.sh | 5 | ||||
-rw-r--r-- | internal.h | 10 | ||||
-rw-r--r-- | lash.c | 1255 | ||||
-rw-r--r-- | sh.c | 1255 | ||||
-rw-r--r-- | shell/lash.c | 1255 | ||||
-rw-r--r-- | utility.c | 4 |
13 files changed, 2282 insertions, 2062 deletions
@@ -1,4 +1,8 @@ | |||
1 | 0.43 | 1 | 0.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)) | |||
34 | void *__libc_stack_end; | 34 | void *__libc_stack_end; |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | |||
38 | static const struct Applet applets[] = { | 37 | static 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 | ||
319 | int main(int argc, char **argv) | 341 | int 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 @@ | |||
4 | DF="busybox.def.h" | 4 | DF="busybox.def.h" |
5 | MF="busybox.c" | 5 | MF="busybox.c" |
6 | 6 | ||
7 | LIST="$(sed -n '/^#define/{s/^#define //p;}' $DF)" | 7 | LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)" |
8 | 8 | ||
9 | for def in ${LIST}; do | 9 | for 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; | ||
15 | done | 19 | done |
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 |
2 | ls -1 `sed -n '/^#define/{s/.*BB_// ; s/$/.c/p; }' busybox.def.h | \ | 2 | sed -n -e 's/^#define.*BB_FEATURE.*$//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;' \ |
3 | tr [:upper:] [:lower:]` 2> /dev/null | sed -e 's/\.c$/\.o/g' | 3 | -e '/^#define/{s/.*bb_//;s/$/.o/p;}' busybox.def.h |
4 | |||
@@ -34,282 +34,304 @@ int atexit(void (*__func) (void)) | |||
34 | void *__libc_stack_end; | 34 | void *__libc_stack_end; |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | |||
38 | static const struct Applet applets[] = { | 37 | static 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 | ||
319 | int main(int argc, char **argv) | 341 | int 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 @@ | |||
4 | DF="busybox.def.h" | 4 | DF="busybox.def.h" |
5 | MF="busybox.c" | 5 | MF="busybox.c" |
6 | 6 | ||
7 | LIST="$(sed -n '/^#define/{s/^#define //p;}' $DF)" | 7 | LIST="$(sed -n '/^#define/{s/^#define BB_FEATURE_.*//g;s/^#define //p;}' $DF)" |
8 | 8 | ||
9 | for def in ${LIST}; do | 9 | for 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; | ||
15 | done | 19 | done |
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 |
2 | ls -1 `sed -n '/^#define/{s/.*BB_// ; s/$/.c/p; }' busybox.def.h | \ | 2 | sed -n -e 's/^#define.*BB_FEATURE.*$//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;' \ |
3 | tr [: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 | ||
54 | enum 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 | ||
55 | struct Applet { | 62 | struct 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 | ||
60 | extern int basename_main(int argc, char **argv); | 68 | extern int basename_main(int argc, char **argv); |
@@ -74,6 +82,7 @@ extern int df_main(int argc, char** argv); | |||
74 | extern int dmesg_main(int argc, char** argv); | 82 | extern int dmesg_main(int argc, char** argv); |
75 | extern int du_main(int argc, char** argv); | 83 | extern int du_main(int argc, char** argv); |
76 | extern int dutmp_main(int argc, char** argv); | 84 | extern int dutmp_main(int argc, char** argv); |
85 | extern int echo_main(int argc, char** argv); | ||
77 | extern int false_main(int argc, char** argv); | 86 | extern int false_main(int argc, char** argv); |
78 | extern int fbset_main(int argc, char** argv); | 87 | extern int fbset_main(int argc, char** argv); |
79 | extern int fdisk_main(int argc, char** argv); | 88 | extern int fdisk_main(int argc, char** argv); |
@@ -134,6 +143,7 @@ extern int syslogd_main(int argc, char **argv); | |||
134 | extern int tail_main(int argc, char** argv); | 143 | extern int tail_main(int argc, char** argv); |
135 | extern int tar_main(int argc, char** argv); | 144 | extern int tar_main(int argc, char** argv); |
136 | extern int tee_main(int argc, char** argv); | 145 | extern int tee_main(int argc, char** argv); |
146 | extern int test_main(int argc, char** argv); | ||
137 | extern int telnet_main(int argc, char** argv); | 147 | extern int telnet_main(int argc, char** argv); |
138 | extern int touch_main(int argc, char** argv); | 148 | extern int touch_main(int argc, char** argv); |
139 | extern int tr_main(int argc, char** argv); | 149 | extern int tr_main(int argc, char** argv); |
@@ -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 | ||
46 | enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND }; | 48 | |
49 | enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | ||
50 | REDIRECT_APPEND }; | ||
47 | 51 | ||
48 | struct jobSet { | 52 | struct 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 | ||
53 | struct redirectionSpecifier { | 57 | struct 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 | ||
59 | struct childProgram { | 63 | struct 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 | ||
69 | struct job { | 73 | struct 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 | ||
81 | struct builtInCommand { | 85 | struct 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 */ |
89 | static int shell_cd(struct job* cmd, struct jobSet* junk); | 93 | static int shell_cd(struct job *cmd, struct jobSet *junk); |
90 | static int shell_env(struct job* dummy, struct jobSet* junk); | 94 | static int shell_env(struct job *dummy, struct jobSet *junk); |
91 | static int shell_exit(struct job* cmd, struct jobSet* junk); | 95 | static int shell_exit(struct job *cmd, struct jobSet *junk); |
92 | static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); | 96 | static int shell_fg_bg(struct job *cmd, struct jobSet *jobList); |
93 | static int shell_help(struct job* cmd, struct jobSet* junk); | 97 | static int shell_help(struct job *cmd, struct jobSet *junk); |
94 | static int shell_jobs(struct job* dummy, struct jobSet* jobList); | 98 | static int shell_jobs(struct job *dummy, struct jobSet *jobList); |
95 | static int shell_pwd(struct job* dummy, struct jobSet* junk); | 99 | static int shell_pwd(struct job *dummy, struct jobSet *junk); |
96 | static int shell_set(struct job* cmd, struct jobSet* junk); | 100 | static int shell_set(struct job *cmd, struct jobSet *junk); |
97 | static int shell_source(struct job* cmd, struct jobSet* jobList); | 101 | static int shell_source(struct job *cmd, struct jobSet *jobList); |
98 | static int shell_unset(struct job* cmd, struct jobSet* junk); | 102 | static int shell_unset(struct job *cmd, struct jobSet *junk); |
99 | 103 | ||
100 | static void checkJobs(struct jobSet * jobList); | 104 | static void checkJobs(struct jobSet *jobList); |
101 | static int getCommand(FILE * source, char * command); | 105 | static int getCommand(FILE * source, char *command); |
102 | static int parseCommand(char ** commandPtr, struct job * job, int * isBg); | 106 | static int parseCommand(char **commandPtr, struct job *job, int *isBg); |
103 | static int setupRedirections(struct childProgram * prog); | 107 | static int setupRedirections(struct childProgram *prog); |
104 | static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); | 108 | static int runCommand(struct job newJob, struct jobSet *jobList, int inBg); |
105 | static int busy_loop(FILE * input); | 109 | static int busy_loop(FILE * input); |
106 | 110 | ||
107 | 111 | ||
108 | /* Table of built-in functions */ | 112 | /* Table of built-in functions */ |
109 | static struct builtInCommand bltins[] = { | 113 | static 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 | ||
125 | static const char shell_usage[] = | 130 | static 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 | ||
130 | static char cwd[1024]; | 134 | static char cwd[1024]; |
131 | static char *prompt = "# "; | 135 | static char *prompt = "# "; |
132 | 136 | ||
133 | 137 | ||
138 | |||
134 | /* built-in 'cd <path>' handler */ | 139 | /* built-in 'cd <path>' handler */ |
135 | static int shell_cd(struct job* cmd, struct jobSet* junk) | 140 | static 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 */ |
152 | static int shell_env(struct job* dummy, struct jobSet* junk) | 157 | static 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 */ |
163 | static int shell_exit(struct job* cmd, struct jobSet* junk) | 168 | static 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 */ |
172 | static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) | 177 | static 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 */ |
218 | static int shell_help(struct job* cmd, struct jobSet* junk) | 227 | static 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 */ |
232 | static int shell_jobs(struct job* dummy, struct jobSet* jobList) | 241 | static 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 */ |
250 | static int shell_pwd(struct job* dummy, struct jobSet* junk) | 258 | static 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 */ |
258 | static int shell_set(struct job* cmd, struct jobSet* junk) | 266 | static 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) */ |
272 | static int shell_source(struct job* cmd, struct jobSet* junk) | 280 | static 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 */ |
292 | static int shell_unset(struct job* cmd, struct jobSet* junk) | 301 | static 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 */ |
303 | static void freeJob(struct job * cmd) | 312 | static 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 */ |
318 | static void removeJob(struct jobSet * jobList, struct job * job) | 330 | static 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 */ |
336 | static void checkJobs(struct jobSet * jobList) | 349 | static 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 | ||
376 | static int getCommand(FILE * source, char * command) | 390 | static 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 | ||
394 | static void globLastArgument(struct childProgram * prog, int * argcPtr, | 413 | static 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. */ |
445 | static int parseCommand(char ** commandPtr, struct job * job, int * isBg) | 466 | static 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 | ||
672 | static int runCommand(struct job newJob, struct jobSet * jobList, | 702 | static 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 | ||
771 | static int setupRedirections(struct childProgram * prog) | 802 | static 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 | ||
810 | static int busy_loop(FILE * input) | 841 | static 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 | ||
887 | int shell_main(int argc, char ** argv) | 922 | int 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 | } |
@@ -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 | ||
46 | enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND }; | 48 | |
49 | enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | ||
50 | REDIRECT_APPEND }; | ||
47 | 51 | ||
48 | struct jobSet { | 52 | struct 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 | ||
53 | struct redirectionSpecifier { | 57 | struct 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 | ||
59 | struct childProgram { | 63 | struct 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 | ||
69 | struct job { | 73 | struct 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 | ||
81 | struct builtInCommand { | 85 | struct 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 */ |
89 | static int shell_cd(struct job* cmd, struct jobSet* junk); | 93 | static int shell_cd(struct job *cmd, struct jobSet *junk); |
90 | static int shell_env(struct job* dummy, struct jobSet* junk); | 94 | static int shell_env(struct job *dummy, struct jobSet *junk); |
91 | static int shell_exit(struct job* cmd, struct jobSet* junk); | 95 | static int shell_exit(struct job *cmd, struct jobSet *junk); |
92 | static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); | 96 | static int shell_fg_bg(struct job *cmd, struct jobSet *jobList); |
93 | static int shell_help(struct job* cmd, struct jobSet* junk); | 97 | static int shell_help(struct job *cmd, struct jobSet *junk); |
94 | static int shell_jobs(struct job* dummy, struct jobSet* jobList); | 98 | static int shell_jobs(struct job *dummy, struct jobSet *jobList); |
95 | static int shell_pwd(struct job* dummy, struct jobSet* junk); | 99 | static int shell_pwd(struct job *dummy, struct jobSet *junk); |
96 | static int shell_set(struct job* cmd, struct jobSet* junk); | 100 | static int shell_set(struct job *cmd, struct jobSet *junk); |
97 | static int shell_source(struct job* cmd, struct jobSet* jobList); | 101 | static int shell_source(struct job *cmd, struct jobSet *jobList); |
98 | static int shell_unset(struct job* cmd, struct jobSet* junk); | 102 | static int shell_unset(struct job *cmd, struct jobSet *junk); |
99 | 103 | ||
100 | static void checkJobs(struct jobSet * jobList); | 104 | static void checkJobs(struct jobSet *jobList); |
101 | static int getCommand(FILE * source, char * command); | 105 | static int getCommand(FILE * source, char *command); |
102 | static int parseCommand(char ** commandPtr, struct job * job, int * isBg); | 106 | static int parseCommand(char **commandPtr, struct job *job, int *isBg); |
103 | static int setupRedirections(struct childProgram * prog); | 107 | static int setupRedirections(struct childProgram *prog); |
104 | static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); | 108 | static int runCommand(struct job newJob, struct jobSet *jobList, int inBg); |
105 | static int busy_loop(FILE * input); | 109 | static int busy_loop(FILE * input); |
106 | 110 | ||
107 | 111 | ||
108 | /* Table of built-in functions */ | 112 | /* Table of built-in functions */ |
109 | static struct builtInCommand bltins[] = { | 113 | static 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 | ||
125 | static const char shell_usage[] = | 130 | static 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 | ||
130 | static char cwd[1024]; | 134 | static char cwd[1024]; |
131 | static char *prompt = "# "; | 135 | static char *prompt = "# "; |
132 | 136 | ||
133 | 137 | ||
138 | |||
134 | /* built-in 'cd <path>' handler */ | 139 | /* built-in 'cd <path>' handler */ |
135 | static int shell_cd(struct job* cmd, struct jobSet* junk) | 140 | static 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 */ |
152 | static int shell_env(struct job* dummy, struct jobSet* junk) | 157 | static 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 */ |
163 | static int shell_exit(struct job* cmd, struct jobSet* junk) | 168 | static 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 */ |
172 | static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) | 177 | static 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 */ |
218 | static int shell_help(struct job* cmd, struct jobSet* junk) | 227 | static 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 */ |
232 | static int shell_jobs(struct job* dummy, struct jobSet* jobList) | 241 | static 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 */ |
250 | static int shell_pwd(struct job* dummy, struct jobSet* junk) | 258 | static 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 */ |
258 | static int shell_set(struct job* cmd, struct jobSet* junk) | 266 | static 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) */ |
272 | static int shell_source(struct job* cmd, struct jobSet* junk) | 280 | static 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 */ |
292 | static int shell_unset(struct job* cmd, struct jobSet* junk) | 301 | static 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 */ |
303 | static void freeJob(struct job * cmd) | 312 | static 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 */ |
318 | static void removeJob(struct jobSet * jobList, struct job * job) | 330 | static 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 */ |
336 | static void checkJobs(struct jobSet * jobList) | 349 | static 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 | ||
376 | static int getCommand(FILE * source, char * command) | 390 | static 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 | ||
394 | static void globLastArgument(struct childProgram * prog, int * argcPtr, | 413 | static 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. */ |
445 | static int parseCommand(char ** commandPtr, struct job * job, int * isBg) | 466 | static 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 | ||
672 | static int runCommand(struct job newJob, struct jobSet * jobList, | 702 | static 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 | ||
771 | static int setupRedirections(struct childProgram * prog) | 802 | static 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 | ||
810 | static int busy_loop(FILE * input) | 841 | static 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 | ||
887 | int shell_main(int argc, char ** argv) | 922 | int 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 | ||
46 | enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND }; | 48 | |
49 | enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | ||
50 | REDIRECT_APPEND }; | ||
47 | 51 | ||
48 | struct jobSet { | 52 | struct 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 | ||
53 | struct redirectionSpecifier { | 57 | struct 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 | ||
59 | struct childProgram { | 63 | struct 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 | ||
69 | struct job { | 73 | struct 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 | ||
81 | struct builtInCommand { | 85 | struct 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 */ |
89 | static int shell_cd(struct job* cmd, struct jobSet* junk); | 93 | static int shell_cd(struct job *cmd, struct jobSet *junk); |
90 | static int shell_env(struct job* dummy, struct jobSet* junk); | 94 | static int shell_env(struct job *dummy, struct jobSet *junk); |
91 | static int shell_exit(struct job* cmd, struct jobSet* junk); | 95 | static int shell_exit(struct job *cmd, struct jobSet *junk); |
92 | static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); | 96 | static int shell_fg_bg(struct job *cmd, struct jobSet *jobList); |
93 | static int shell_help(struct job* cmd, struct jobSet* junk); | 97 | static int shell_help(struct job *cmd, struct jobSet *junk); |
94 | static int shell_jobs(struct job* dummy, struct jobSet* jobList); | 98 | static int shell_jobs(struct job *dummy, struct jobSet *jobList); |
95 | static int shell_pwd(struct job* dummy, struct jobSet* junk); | 99 | static int shell_pwd(struct job *dummy, struct jobSet *junk); |
96 | static int shell_set(struct job* cmd, struct jobSet* junk); | 100 | static int shell_set(struct job *cmd, struct jobSet *junk); |
97 | static int shell_source(struct job* cmd, struct jobSet* jobList); | 101 | static int shell_source(struct job *cmd, struct jobSet *jobList); |
98 | static int shell_unset(struct job* cmd, struct jobSet* junk); | 102 | static int shell_unset(struct job *cmd, struct jobSet *junk); |
99 | 103 | ||
100 | static void checkJobs(struct jobSet * jobList); | 104 | static void checkJobs(struct jobSet *jobList); |
101 | static int getCommand(FILE * source, char * command); | 105 | static int getCommand(FILE * source, char *command); |
102 | static int parseCommand(char ** commandPtr, struct job * job, int * isBg); | 106 | static int parseCommand(char **commandPtr, struct job *job, int *isBg); |
103 | static int setupRedirections(struct childProgram * prog); | 107 | static int setupRedirections(struct childProgram *prog); |
104 | static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); | 108 | static int runCommand(struct job newJob, struct jobSet *jobList, int inBg); |
105 | static int busy_loop(FILE * input); | 109 | static int busy_loop(FILE * input); |
106 | 110 | ||
107 | 111 | ||
108 | /* Table of built-in functions */ | 112 | /* Table of built-in functions */ |
109 | static struct builtInCommand bltins[] = { | 113 | static 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 | ||
125 | static const char shell_usage[] = | 130 | static 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 | ||
130 | static char cwd[1024]; | 134 | static char cwd[1024]; |
131 | static char *prompt = "# "; | 135 | static char *prompt = "# "; |
132 | 136 | ||
133 | 137 | ||
138 | |||
134 | /* built-in 'cd <path>' handler */ | 139 | /* built-in 'cd <path>' handler */ |
135 | static int shell_cd(struct job* cmd, struct jobSet* junk) | 140 | static 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 */ |
152 | static int shell_env(struct job* dummy, struct jobSet* junk) | 157 | static 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 */ |
163 | static int shell_exit(struct job* cmd, struct jobSet* junk) | 168 | static 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 */ |
172 | static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) | 177 | static 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 */ |
218 | static int shell_help(struct job* cmd, struct jobSet* junk) | 227 | static 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 */ |
232 | static int shell_jobs(struct job* dummy, struct jobSet* jobList) | 241 | static 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 */ |
250 | static int shell_pwd(struct job* dummy, struct jobSet* junk) | 258 | static 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 */ |
258 | static int shell_set(struct job* cmd, struct jobSet* junk) | 266 | static 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) */ |
272 | static int shell_source(struct job* cmd, struct jobSet* junk) | 280 | static 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 */ |
292 | static int shell_unset(struct job* cmd, struct jobSet* junk) | 301 | static 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 */ |
303 | static void freeJob(struct job * cmd) | 312 | static 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 */ |
318 | static void removeJob(struct jobSet * jobList, struct job * job) | 330 | static 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 */ |
336 | static void checkJobs(struct jobSet * jobList) | 349 | static 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 | ||
376 | static int getCommand(FILE * source, char * command) | 390 | static 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 | ||
394 | static void globLastArgument(struct childProgram * prog, int * argcPtr, | 413 | static 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. */ |
445 | static int parseCommand(char ** commandPtr, struct job * job, int * isBg) | 466 | static 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 | ||
672 | static int runCommand(struct job newJob, struct jobSet * jobList, | 702 | static 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 | ||
771 | static int setupRedirections(struct childProgram * prog) | 802 | static 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 | ||
810 | static int busy_loop(FILE * input) | 841 | static 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 | ||
887 | int shell_main(int argc, char ** argv) | 922 | int 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 | } |
@@ -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 \ |