aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-12-27 04:35:04 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-12-27 04:35:04 +0000
commit8d42f86b146871ae4c4cafd3801a85f381249a14 (patch)
treeb963999fc54eddb65f1929b894f868e24851fc9c /shell
downloadbusybox-w32-8d42f86b146871ae4c4cafd3801a85f381249a14.tar.gz
busybox-w32-8d42f86b146871ae4c4cafd3801a85f381249a14.tar.bz2
busybox-w32-8d42f86b146871ae4c4cafd3801a85f381249a14.zip
Correcting branch name to be like previous ones
Diffstat (limited to 'shell')
-rw-r--r--shell/Config.in295
-rw-r--r--shell/Kbuild12
-rw-r--r--shell/ash.c13701
-rw-r--r--shell/bbsh.c222
-rw-r--r--shell/cmdedit.c1924
-rw-r--r--shell/cmdedit.h20
-rw-r--r--shell/hush.c2875
-rw-r--r--shell/lash.c1573
-rw-r--r--shell/msh.c5250
9 files changed, 25872 insertions, 0 deletions
diff --git a/shell/Config.in b/shell/Config.in
new file mode 100644
index 000000000..9ac233155
--- /dev/null
+++ b/shell/Config.in
@@ -0,0 +1,295 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6menu "Shells"
7
8choice
9 prompt "Choose your default shell"
10 default FEATURE_SH_IS_NONE
11 help
12 Choose a shell. The ash shell is the most bash compatible
13 and full featured one.
14
15config FEATURE_SH_IS_ASH
16 select ASH
17 bool "ash"
18
19config FEATURE_SH_IS_HUSH
20 select HUSH
21 bool "hush"
22
23config FEATURE_SH_IS_LASH
24 select LASH
25 bool "lash"
26
27config FEATURE_SH_IS_MSH
28 select MSH
29 bool "msh"
30
31config FEATURE_SH_IS_NONE
32 bool "none"
33
34endchoice
35
36config ASH
37 bool "ash"
38 default n
39 select TEST
40 help
41 Tha 'ash' shell adds about 60k in the default configuration and is
42 the most complete and most pedantically correct shell included with
43 busybox. This shell is actually a derivative of the Debian 'dash'
44 shell (by Herbert Xu), which was created by porting the 'ash' shell
45 (written by Kenneth Almquist) from NetBSD.
46
47comment "Ash Shell Options"
48 depends on ASH
49
50config ASH_JOB_CONTROL
51 bool "Job control"
52 default y
53 depends on ASH
54 help
55 Enable job control in the ash shell.
56
57config ASH_READ_NCHARS
58 bool "'read -n N' and 'read -s' support"
59 default n
60 depends on ASH
61 help
62 'read -n N' will return a value after N characters have been read.
63 'read -s' will read without echoing the user's input.
64
65config ASH_READ_TIMEOUT
66 bool "'read -t S' support."
67 default n
68 depends on ASH
69 help
70 'read -t S' will return a value after S seconds have passed.
71 This implementation will allow fractional seconds, expressed
72 as a decimal fraction, e.g. 'read -t 2.5 foo'.
73
74config ASH_ALIAS
75 bool "alias support"
76 default y
77 depends on ASH
78 help
79 Enable alias support in the ash shell.
80
81config ASH_MATH_SUPPORT
82 bool "Posix math support"
83 default y
84 depends on ASH
85 help
86 Enable math support in the ash shell.
87
88config ASH_MATH_SUPPORT_64
89 bool "Extend Posix math support to 64 bit"
90 default n
91 depends on ASH_MATH_SUPPORT
92 help
93 Enable 64-bit math support in the ash shell. This will make
94 the shell slightly larger, but will allow computation with very
95 large numbers.
96
97config ASH_GETOPTS
98 bool "Builtin getopt to parse positional parameters"
99 default n
100 depends on ASH
101 help
102 Enable getopts builtin in the ash shell.
103
104config ASH_BUILTIN_ECHO
105 bool "Builtin version of 'echo'"
106 default y
107 select ECHO
108 depends on ASH
109 help
110 Enable support for echo, built in to ash.
111
112config ASH_BUILTIN_TEST
113 bool "Builtin version of 'test'"
114 default y
115 select TEST
116 depends on ASH
117 help
118 Enable support for test, built in to ash.
119
120config ASH_CMDCMD
121 bool "'command' command to override shell builtins"
122 default n
123 depends on ASH
124 help
125 Enable support for the ash 'command' builtin, which allows
126 you to run the specified command with the specified arguments,
127 even when there is an ash builtin command with the same name.
128
129config ASH_MAIL
130 bool "Check for new mail on interactive shells"
131 default y
132 depends on ASH
133 help
134 Enable "check for new mail" in the ash shell.
135
136config ASH_OPTIMIZE_FOR_SIZE
137 bool "Optimize for size instead of speed"
138 default y
139 depends on ASH
140 help
141 Compile ash for reduced size at the price of speed.
142
143config ASH_RANDOM_SUPPORT
144 bool "Pseudorandom generator and variable $RANDOM"
145 default n
146 depends on ASH
147 help
148 Enable pseudorandom generator and dynamic variable "$RANDOM".
149 Each read of "$RANDOM" will generate a new pseudorandom value.
150 You can reset the generator by using a specified start value.
151 After "unset RANDOM" then generator will switch off and this
152 variable will no longer have special treatment.
153
154config ASH_EXPAND_PRMT
155 bool "Expand prompt string"
156 default n
157 depends on ASH
158 help
159 "PS#" may be contain volatile content, such as backquote commands.
160 This option recreates the prompt string from the environment
161 variable each time it is displayed.
162
163config HUSH
164 bool "hush"
165 default n
166 select TRUE
167 select FALSE
168 select TEST
169 help
170 hush is a very small shell (just 18k) and it has fairly complete
171 Bourne shell grammar. It even handles all the normal flow control
172 options such as if/then/elif/else/fi, for/in/do/done, while loops,
173 etc.
174
175 It does not handle case/esac, select, function, here documents ( <<
176 word ), arithmetic expansion, aliases, brace expansion, tilde
177 expansion, &> and >& redirection of stdout+stderr, etc.
178
179
180config LASH
181 bool "lash"
182 default n
183 select TRUE
184 select FALSE
185 select TEST
186 help
187 lash is the very smallest shell (adds just 10k) and it is quite
188 usable as a command prompt, but it is not suitable for any but the
189 most trivial scripting (such as an initrd that calls insmod a few
190 times) since it does not understand any Bourne shell grammar. It
191 does handle pipes, redirects, and job control though. Adding in
192 command editing makes it a very nice lightweight command prompt.
193
194
195config MSH
196 bool "msh"
197 default n
198 select TRUE
199 select FALSE
200 select TEST
201 help
202 The minix shell (adds just 30k) is quite complete and handles things
203 like for/do/done, case/esac and all the things you expect a Bourne
204 shell to do. It is not always pedantically correct about Bourne
205 shell grammar (try running the shell testscript "tests/sh.testcases"
206 on it and compare vs bash) but for most things it works quite well.
207 It also uses only vfork, so it can be used on uClinux systems.
208
209comment "Bourne Shell Options"
210 depends on MSH || LASH || HUSH || ASH
211
212config FEATURE_SH_EXTRA_QUIET
213 bool "Hide message on interactive shell startup"
214 default n
215 depends on MSH || LASH || HUSH || ASH
216 help
217 Remove the busybox introduction when starting a shell.
218
219config FEATURE_SH_STANDALONE_SHELL
220 bool "Standalone shell"
221 default n
222 depends on MSH || LASH || HUSH || ASH
223 help
224 This option causes the selected busybox shell to use busybox applets
225 in preference to executables in the PATH whenever possible. For
226 example, entering the command 'ifconfig' into the shell would cause
227 busybox to use the ifconfig busybox applet. Specifying the fully
228 qualified executable name, such as '/sbin/ifconfig' will still
229 execute the /sbin/ifconfig executable on the filesystem. This option
230 is generally used when creating a statically linked version of busybox
231 for use as a rescue shell, in the event that you screw up your system.
232
233 Note that this will *also* cause applets to take precedence
234 over shell builtins of the same name. So turning this on will
235 eliminate any performance gained by turning on the builtin "echo"
236 and "test" commands in ash.
237
238 Note that when using this option, the shell will attempt to directly
239 run '/bin/busybox'. If you do not have the busybox binary sitting in
240 that exact location with that exact name, this option will not work at
241 all.
242
243config FEATURE_COMMAND_EDITING
244 bool "Command line editing"
245 default n
246 depends on MSH || LASH || HUSH || ASH
247 help
248 Enable command editing in shell.
249
250config FEATURE_COMMAND_EDITING_VI
251 bool "vi-style line editing commands"
252 default n
253 depends on FEATURE_COMMAND_EDITING
254 help
255 Enable vi-style line editing in the shell. This mode can be
256 turned on and off with "set -o vi" and "set +o vi".
257
258config FEATURE_COMMAND_HISTORY
259 int "History size"
260 range 0 99999
261 default 15
262 depends on FEATURE_COMMAND_EDITING
263 help
264 Specify command history size in shell.
265
266config FEATURE_COMMAND_SAVEHISTORY
267 bool "History saving"
268 default n
269 depends on ASH && FEATURE_COMMAND_EDITING
270 help
271 Enable history saving in ash shell.
272
273config FEATURE_COMMAND_TAB_COMPLETION
274 bool "Tab completion"
275 default n
276 depends on FEATURE_COMMAND_EDITING
277 help
278 Enable tab completion in shell.
279
280config FEATURE_COMMAND_USERNAME_COMPLETION
281 bool "Username completion"
282 default n
283 depends on FEATURE_COMMAND_TAB_COMPLETION
284 help
285 Enable username completion in shell.
286
287config FEATURE_SH_FANCY_PROMPT
288 bool "Fancy shell prompts"
289 default n
290 depends on FEATURE_COMMAND_EDITING
291 help
292 Setting this option allows for prompts to use things like \w and
293 \$ and also using escape codes.
294
295endmenu
diff --git a/shell/Kbuild b/shell/Kbuild
new file mode 100644
index 000000000..eb0199ee2
--- /dev/null
+++ b/shell/Kbuild
@@ -0,0 +1,12 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7lib-y:=
8lib-$(CONFIG_ASH) += ash.o
9lib-$(CONFIG_HUSH) += hush.o
10lib-$(CONFIG_LASH) += lash.o
11lib-$(CONFIG_MSH) += msh.o
12lib-$(CONFIG_FEATURE_COMMAND_EDITING) += cmdedit.o
diff --git a/shell/ash.c b/shell/ash.c
new file mode 100644
index 000000000..3a9998fc0
--- /dev/null
+++ b/shell/ash.c
@@ -0,0 +1,13701 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
9 * was re-ported from NetBSD and debianized.
10 *
11 *
12 * This code is derived from software contributed to Berkeley by
13 * Kenneth Almquist.
14 *
15 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
16 *
17 * Original BSD copyright notice is retained at the end of this file.
18 */
19
20/*
21 * rewrite arith.y to micro stack based cryptic algorithm by
22 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
23 *
24 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
25 * dynamic variables.
26 *
27 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
28 * used in busybox and size optimizations,
29 * rewrote arith (see notes to this), added locale support,
30 * rewrote dynamic variables.
31 *
32 */
33
34
35/*
36 * The follow should be set to reflect the type of system you have:
37 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
38 * define SYSV if you are running under System V.
39 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
40 * define DEBUG=2 to compile in and turn on debugging.
41 *
42 * When debugging is on, debugging info will be written to ./trace and
43 * a quit signal will generate a core dump.
44 */
45#define DEBUG 0
46
47
48#define IFS_BROKEN
49
50#define PROFILE 0
51
52#include "busybox.h"
53
54#if DEBUG
55#define _GNU_SOURCE
56#endif
57
58#include <sys/types.h>
59#include <sys/ioctl.h>
60#include <sys/param.h>
61#include <sys/resource.h>
62#include <sys/stat.h>
63#include <sys/wait.h>
64
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <unistd.h>
69
70#include <stdarg.h>
71#include <stddef.h>
72#include <assert.h>
73#include <ctype.h>
74#include <dirent.h>
75#include <errno.h>
76#include <fcntl.h>
77#include <limits.h>
78#include <paths.h>
79#include <setjmp.h>
80#include <signal.h>
81/*#include <stdint.h>*/
82#include <time.h>
83#include <fnmatch.h>
84
85#ifdef CONFIG_ASH_JOB_CONTROL
86#define JOBS 1
87#else
88#undef JOBS
89#endif
90
91#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
92#include <termios.h>
93#endif
94
95#include "cmdedit.h"
96
97#ifdef __GLIBC__
98/* glibc sucks */
99static int *dash_errno;
100#undef errno
101#define errno (*dash_errno)
102#endif
103
104#if defined(__uClinux__)
105#error "Do not even bother, ash will not run on uClinux"
106#endif
107
108#if DEBUG
109#define _DIAGASSERT(assert_expr) assert(assert_expr)
110#else
111#define _DIAGASSERT(assert_expr)
112#endif
113
114
115#ifdef CONFIG_ASH_ALIAS
116/* alias.h */
117
118#define ALIASINUSE 1
119#define ALIASDEAD 2
120
121struct alias {
122 struct alias *next;
123 char *name;
124 char *val;
125 int flag;
126};
127
128static struct alias *lookupalias(const char *, int);
129static int aliascmd(int, char **);
130static int unaliascmd(int, char **);
131static void rmaliases(void);
132static int unalias(const char *);
133static void printalias(const struct alias *);
134#endif
135
136/* cd.h */
137
138
139static void setpwd(const char *, int);
140
141/* error.h */
142
143
144/*
145 * Types of operations (passed to the errmsg routine).
146 */
147
148
149static const char not_found_msg[] = "%s: not found";
150
151
152#define E_OPEN "No such file" /* opening a file */
153#define E_CREAT "Directory nonexistent" /* creating a file */
154#define E_EXEC not_found_msg+4 /* executing a program */
155
156/*
157 * We enclose jmp_buf in a structure so that we can declare pointers to
158 * jump locations. The global variable handler contains the location to
159 * jump to when an exception occurs, and the global variable exception
160 * contains a code identifying the exception. To implement nested
161 * exception handlers, the user should save the value of handler on entry
162 * to an inner scope, set handler to point to a jmploc structure for the
163 * inner scope, and restore handler on exit from the scope.
164 */
165
166struct jmploc {
167 jmp_buf loc;
168};
169
170static struct jmploc *handler;
171static int exception;
172static volatile int suppressint;
173static volatile sig_atomic_t intpending;
174
175/* exceptions */
176#define EXINT 0 /* SIGINT received */
177#define EXERROR 1 /* a generic error */
178#define EXSHELLPROC 2 /* execute a shell procedure */
179#define EXEXEC 3 /* command execution failed */
180#define EXEXIT 4 /* exit the shell */
181#define EXSIG 5 /* trapped signal in wait(1) */
182
183
184/* do we generate EXSIG events */
185static int exsig;
186/* last pending signal */
187static volatile sig_atomic_t pendingsigs;
188
189/*
190 * These macros allow the user to suspend the handling of interrupt signals
191 * over a period of time. This is similar to SIGHOLD to or sigblock, but
192 * much more efficient and portable. (But hacking the kernel is so much
193 * more fun than worrying about efficiency and portability. :-))
194 */
195
196#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
197#define INTOFF \
198 ({ \
199 suppressint++; \
200 xbarrier(); \
201 0; \
202 })
203#define SAVEINT(v) ((v) = suppressint)
204#define RESTOREINT(v) \
205 ({ \
206 xbarrier(); \
207 if ((suppressint = (v)) == 0 && intpending) onint(); \
208 0; \
209 })
210#define EXSIGON() \
211 ({ \
212 exsig++; \
213 xbarrier(); \
214 if (pendingsigs) \
215 exraise(EXSIG); \
216 0; \
217 })
218/* EXSIG is turned off by evalbltin(). */
219
220
221static void exraise(int) ATTRIBUTE_NORETURN;
222static void onint(void) ATTRIBUTE_NORETURN;
223
224static void sh_error(const char *, ...) ATTRIBUTE_NORETURN;
225static void exerror(int, const char *, ...) ATTRIBUTE_NORETURN;
226
227static void sh_warnx(const char *, ...);
228
229#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
230static void
231inton(void) {
232 if (--suppressint == 0 && intpending) {
233 onint();
234 }
235}
236#define INTON inton()
237static void forceinton(void)
238{
239 suppressint = 0;
240 if (intpending)
241 onint();
242}
243#define FORCEINTON forceinton()
244#else
245#define INTON \
246 ({ \
247 xbarrier(); \
248 if (--suppressint == 0 && intpending) onint(); \
249 0; \
250 })
251#define FORCEINTON \
252 ({ \
253 xbarrier(); \
254 suppressint = 0; \
255 if (intpending) onint(); \
256 0; \
257 })
258#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
259
260/* expand.h */
261
262struct strlist {
263 struct strlist *next;
264 char *text;
265};
266
267
268struct arglist {
269 struct strlist *list;
270 struct strlist **lastp;
271};
272
273/*
274 * expandarg() flags
275 */
276#define EXP_FULL 0x1 /* perform word splitting & file globbing */
277#define EXP_TILDE 0x2 /* do normal tilde expansion */
278#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
279#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
280#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
281#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
282#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
283#define EXP_WORD 0x80 /* expand word in parameter expansion */
284#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
285
286
287union node;
288static void expandarg(union node *, struct arglist *, int);
289#define rmescapes(p) _rmescapes((p), 0)
290static char *_rmescapes(char *, int);
291static int casematch(union node *, char *);
292
293#ifdef CONFIG_ASH_MATH_SUPPORT
294static void expari(int);
295#endif
296
297/* eval.h */
298
299static char *commandname; /* currently executing command */
300static struct strlist *cmdenviron; /* environment for builtin command */
301static int exitstatus; /* exit status of last command */
302static int back_exitstatus; /* exit status of backquoted command */
303
304
305struct backcmd { /* result of evalbackcmd */
306 int fd; /* file descriptor to read from */
307 char *buf; /* buffer */
308 int nleft; /* number of chars in buffer */
309 struct job *jp; /* job structure for command */
310};
311
312/*
313 * This file was generated by the mknodes program.
314 */
315
316#define NCMD 0
317#define NPIPE 1
318#define NREDIR 2
319#define NBACKGND 3
320#define NSUBSHELL 4
321#define NAND 5
322#define NOR 6
323#define NSEMI 7
324#define NIF 8
325#define NWHILE 9
326#define NUNTIL 10
327#define NFOR 11
328#define NCASE 12
329#define NCLIST 13
330#define NDEFUN 14
331#define NARG 15
332#define NTO 16
333#define NCLOBBER 17
334#define NFROM 18
335#define NFROMTO 19
336#define NAPPEND 20
337#define NTOFD 21
338#define NFROMFD 22
339#define NHERE 23
340#define NXHERE 24
341#define NNOT 25
342
343
344
345struct ncmd {
346 int type;
347 union node *assign;
348 union node *args;
349 union node *redirect;
350};
351
352
353struct npipe {
354 int type;
355 int backgnd;
356 struct nodelist *cmdlist;
357};
358
359
360struct nredir {
361 int type;
362 union node *n;
363 union node *redirect;
364};
365
366
367struct nbinary {
368 int type;
369 union node *ch1;
370 union node *ch2;
371};
372
373
374struct nif {
375 int type;
376 union node *test;
377 union node *ifpart;
378 union node *elsepart;
379};
380
381
382struct nfor {
383 int type;
384 union node *args;
385 union node *body;
386 char *var;
387};
388
389
390struct ncase {
391 int type;
392 union node *expr;
393 union node *cases;
394};
395
396
397struct nclist {
398 int type;
399 union node *next;
400 union node *pattern;
401 union node *body;
402};
403
404
405struct narg {
406 int type;
407 union node *next;
408 char *text;
409 struct nodelist *backquote;
410};
411
412
413struct nfile {
414 int type;
415 union node *next;
416 int fd;
417 union node *fname;
418 char *expfname;
419};
420
421
422struct ndup {
423 int type;
424 union node *next;
425 int fd;
426 int dupfd;
427 union node *vname;
428};
429
430
431struct nhere {
432 int type;
433 union node *next;
434 int fd;
435 union node *doc;
436};
437
438
439struct nnot {
440 int type;
441 union node *com;
442};
443
444
445union node {
446 int type;
447 struct ncmd ncmd;
448 struct npipe npipe;
449 struct nredir nredir;
450 struct nbinary nbinary;
451 struct nif nif;
452 struct nfor nfor;
453 struct ncase ncase;
454 struct nclist nclist;
455 struct narg narg;
456 struct nfile nfile;
457 struct ndup ndup;
458 struct nhere nhere;
459 struct nnot nnot;
460};
461
462
463struct nodelist {
464 struct nodelist *next;
465 union node *n;
466};
467
468
469struct funcnode {
470 int count;
471 union node n;
472};
473
474
475static void freefunc(struct funcnode *);
476/* parser.h */
477
478/* control characters in argument strings */
479#define CTL_FIRST '\201' /* first 'special' character */
480#define CTLESC '\201' /* escape next character */
481#define CTLVAR '\202' /* variable defn */
482#define CTLENDVAR '\203'
483#define CTLBACKQ '\204'
484#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
485/* CTLBACKQ | CTLQUOTE == '\205' */
486#define CTLARI '\206' /* arithmetic expression */
487#define CTLENDARI '\207'
488#define CTLQUOTEMARK '\210'
489#define CTL_LAST '\210' /* last 'special' character */
490
491/* variable substitution byte (follows CTLVAR) */
492#define VSTYPE 0x0f /* type of variable substitution */
493#define VSNUL 0x10 /* colon--treat the empty string as unset */
494#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
495
496/* values of VSTYPE field */
497#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
498#define VSMINUS 0x2 /* ${var-text} */
499#define VSPLUS 0x3 /* ${var+text} */
500#define VSQUESTION 0x4 /* ${var?message} */
501#define VSASSIGN 0x5 /* ${var=text} */
502#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
503#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
504#define VSTRIMLEFT 0x8 /* ${var#pattern} */
505#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
506#define VSLENGTH 0xa /* ${#var} */
507
508/* values of checkkwd variable */
509#define CHKALIAS 0x1
510#define CHKKWD 0x2
511#define CHKNL 0x4
512
513#define IBUFSIZ (BUFSIZ + 1)
514
515/*
516 * NEOF is returned by parsecmd when it encounters an end of file. It
517 * must be distinct from NULL, so we use the address of a variable that
518 * happens to be handy.
519 */
520static int plinno = 1; /* input line number */
521
522/* number of characters left in input buffer */
523static int parsenleft; /* copy of parsefile->nleft */
524static int parselleft; /* copy of parsefile->lleft */
525
526/* next character in input buffer */
527static char *parsenextc; /* copy of parsefile->nextc */
528
529struct strpush {
530 struct strpush *prev; /* preceding string on stack */
531 char *prevstring;
532 int prevnleft;
533#ifdef CONFIG_ASH_ALIAS
534 struct alias *ap; /* if push was associated with an alias */
535#endif
536 char *string; /* remember the string since it may change */
537};
538
539struct parsefile {
540 struct parsefile *prev; /* preceding file on stack */
541 int linno; /* current line */
542 int fd; /* file descriptor (or -1 if string) */
543 int nleft; /* number of chars left in this line */
544 int lleft; /* number of chars left in this buffer */
545 char *nextc; /* next char in buffer */
546 char *buf; /* input buffer */
547 struct strpush *strpush; /* for pushing strings at this level */
548 struct strpush basestrpush; /* so pushing one is fast */
549};
550
551static struct parsefile basepf; /* top level input file */
552#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
553static struct parsefile *parsefile = &basepf; /* current input file */
554
555
556static int tokpushback; /* last token pushed back */
557#define NEOF ((union node *)&tokpushback)
558static int parsebackquote; /* nonzero if we are inside backquotes */
559static int doprompt; /* if set, prompt the user */
560static int needprompt; /* true if interactive and at start of line */
561static int lasttoken; /* last token read */
562static char *wordtext; /* text of last word returned by readtoken */
563static int checkkwd;
564static struct nodelist *backquotelist;
565static union node *redirnode;
566static struct heredoc *heredoc;
567static int quoteflag; /* set if (part of) last token was quoted */
568static int startlinno; /* line # where last token started */
569
570static union node *parsecmd(int);
571static void fixredir(union node *, const char *, int);
572static const char *const *findkwd(const char *);
573static char *endofname(const char *);
574
575/* shell.h */
576
577typedef void *pointer;
578
579static char nullstr[1]; /* zero length string */
580static const char spcstr[] = " ";
581static const char snlfmt[] = "%s\n";
582static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
583static const char illnum[] = "Illegal number: %s";
584static const char homestr[] = "HOME";
585
586#if DEBUG
587#define TRACE(param) trace param
588#define TRACEV(param) tracev param
589#else
590#define TRACE(param)
591#define TRACEV(param)
592#endif
593
594#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
595#define __builtin_expect(x, expected_value) (x)
596#endif
597
598#define xlikely(x) __builtin_expect((x),1)
599
600
601#define TEOF 0
602#define TNL 1
603#define TREDIR 2
604#define TWORD 3
605#define TSEMI 4
606#define TBACKGND 5
607#define TAND 6
608#define TOR 7
609#define TPIPE 8
610#define TLP 9
611#define TRP 10
612#define TENDCASE 11
613#define TENDBQUOTE 12
614#define TNOT 13
615#define TCASE 14
616#define TDO 15
617#define TDONE 16
618#define TELIF 17
619#define TELSE 18
620#define TESAC 19
621#define TFI 20
622#define TFOR 21
623#define TIF 22
624#define TIN 23
625#define TTHEN 24
626#define TUNTIL 25
627#define TWHILE 26
628#define TBEGIN 27
629#define TEND 28
630
631/* first char is indicating which tokens mark the end of a list */
632static const char *const tokname_array[] = {
633 "\1end of file",
634 "\0newline",
635 "\0redirection",
636 "\0word",
637 "\0;",
638 "\0&",
639 "\0&&",
640 "\0||",
641 "\0|",
642 "\0(",
643 "\1)",
644 "\1;;",
645 "\1`",
646#define KWDOFFSET 13
647 /* the following are keywords */
648 "\0!",
649 "\0case",
650 "\1do",
651 "\1done",
652 "\1elif",
653 "\1else",
654 "\1esac",
655 "\1fi",
656 "\0for",
657 "\0if",
658 "\0in",
659 "\1then",
660 "\0until",
661 "\0while",
662 "\0{",
663 "\1}",
664};
665
666static const char *tokname(int tok)
667{
668 static char buf[16];
669
670 if (tok >= TSEMI)
671 buf[0] = '"';
672 sprintf(buf + (tok >= TSEMI), "%s%c",
673 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
674 return buf;
675}
676
677/* machdep.h */
678
679/*
680 * Most machines require the value returned from malloc to be aligned
681 * in some way. The following macro will get this right on many machines.
682 */
683
684#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
685/*
686 * It appears that grabstackstr() will barf with such alignments
687 * because stalloc() will return a string allocated in a new stackblock.
688 */
689#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
690
691/*
692 * This file was generated by the mksyntax program.
693 */
694
695
696/* Syntax classes */
697#define CWORD 0 /* character is nothing special */
698#define CNL 1 /* newline character */
699#define CBACK 2 /* a backslash character */
700#define CSQUOTE 3 /* single quote */
701#define CDQUOTE 4 /* double quote */
702#define CENDQUOTE 5 /* a terminating quote */
703#define CBQUOTE 6 /* backwards single quote */
704#define CVAR 7 /* a dollar sign */
705#define CENDVAR 8 /* a '}' character */
706#define CLP 9 /* a left paren in arithmetic */
707#define CRP 10 /* a right paren in arithmetic */
708#define CENDFILE 11 /* end of file */
709#define CCTL 12 /* like CWORD, except it must be escaped */
710#define CSPCL 13 /* these terminate a word */
711#define CIGN 14 /* character should be ignored */
712
713#ifdef CONFIG_ASH_ALIAS
714#define SYNBASE 130
715#define PEOF -130
716#define PEOA -129
717#define PEOA_OR_PEOF PEOA
718#else
719#define SYNBASE 129
720#define PEOF -129
721#define PEOA_OR_PEOF PEOF
722#endif
723
724#define is_digit(c) ((unsigned)((c) - '0') <= 9)
725#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
726#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
727
728/* C99 say: "char" declaration may be signed or unsigned default */
729#define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int)
730
731/*
732 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
733 * (assuming ascii char codes, as the original implementation did)
734 */
735#define is_special(c) \
736 ( (((unsigned int)c) - 33 < 32) \
737 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
738
739#define digit_val(c) ((c) - '0')
740
741/*
742 * This file was generated by the mksyntax program.
743 */
744
745#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
746#define USE_SIT_FUNCTION
747#endif
748
749/* number syntax index */
750#define BASESYNTAX 0 /* not in quotes */
751#define DQSYNTAX 1 /* in double quotes */
752#define SQSYNTAX 2 /* in single quotes */
753#define ARISYNTAX 3 /* in arithmetic */
754
755#ifdef CONFIG_ASH_MATH_SUPPORT
756static const char S_I_T[][4] = {
757#ifdef CONFIG_ASH_ALIAS
758 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
759#endif
760 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
761 {CNL, CNL, CNL, CNL}, /* 2, \n */
762 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
763 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
764 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
765 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
766 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
767 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
768 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
769 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
770 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
771#ifndef USE_SIT_FUNCTION
772 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
773 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
774 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
775#endif
776};
777#else
778static const char S_I_T[][3] = {
779#ifdef CONFIG_ASH_ALIAS
780 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
781#endif
782 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
783 {CNL, CNL, CNL}, /* 2, \n */
784 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
785 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
786 {CVAR, CVAR, CWORD}, /* 5, $ */
787 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
788 {CSPCL, CWORD, CWORD}, /* 7, ( */
789 {CSPCL, CWORD, CWORD}, /* 8, ) */
790 {CBACK, CBACK, CCTL}, /* 9, \ */
791 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
792 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
793#ifndef USE_SIT_FUNCTION
794 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
795 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
796 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
797#endif
798};
799#endif /* CONFIG_ASH_MATH_SUPPORT */
800
801#ifdef USE_SIT_FUNCTION
802
803#define U_C(c) ((unsigned char)(c))
804
805static int SIT(int c, int syntax)
806{
807 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
808#ifdef CONFIG_ASH_ALIAS
809 static const char syntax_index_table[] = {
810 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
811 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
812 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
813 11, 3 /* "}~" */
814 };
815#else
816 static const char syntax_index_table[] = {
817 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
818 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
819 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
820 10, 2 /* "}~" */
821 };
822#endif
823 const char *s;
824 int indx;
825
826 if (c == PEOF) /* 2^8+2 */
827 return CENDFILE;
828#ifdef CONFIG_ASH_ALIAS
829 if (c == PEOA) /* 2^8+1 */
830 indx = 0;
831 else
832#endif
833 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
834 return CCTL;
835 else {
836 s = strchr(spec_symbls, c);
837 if (s == 0 || *s == 0)
838 return CWORD;
839 indx = syntax_index_table[(s - spec_symbls)];
840 }
841 return S_I_T[indx][syntax];
842}
843
844#else /* USE_SIT_FUNCTION */
845
846#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
847
848#ifdef CONFIG_ASH_ALIAS
849#define CSPCL_CIGN_CIGN_CIGN 0
850#define CSPCL_CWORD_CWORD_CWORD 1
851#define CNL_CNL_CNL_CNL 2
852#define CWORD_CCTL_CCTL_CWORD 3
853#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
854#define CVAR_CVAR_CWORD_CVAR 5
855#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
856#define CSPCL_CWORD_CWORD_CLP 7
857#define CSPCL_CWORD_CWORD_CRP 8
858#define CBACK_CBACK_CCTL_CBACK 9
859#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
860#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
861#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
862#define CWORD_CWORD_CWORD_CWORD 13
863#define CCTL_CCTL_CCTL_CCTL 14
864#else
865#define CSPCL_CWORD_CWORD_CWORD 0
866#define CNL_CNL_CNL_CNL 1
867#define CWORD_CCTL_CCTL_CWORD 2
868#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
869#define CVAR_CVAR_CWORD_CVAR 4
870#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
871#define CSPCL_CWORD_CWORD_CLP 6
872#define CSPCL_CWORD_CWORD_CRP 7
873#define CBACK_CBACK_CCTL_CBACK 8
874#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
875#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
876#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
877#define CWORD_CWORD_CWORD_CWORD 12
878#define CCTL_CCTL_CCTL_CCTL 13
879#endif
880
881static const char syntax_index_table[258] = {
882 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
883 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
884#ifdef CONFIG_ASH_ALIAS
885 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
886#endif
887 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
888 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
889 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
890 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
891 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
892 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
893 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
894 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
895 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
896 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
897 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
898 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
899 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
900 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
901 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
902 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
903 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
904 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
905 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
906 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
907 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
908 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
909 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
910 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
911 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
912 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
913 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
914 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
915 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
916 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
917 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
918 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
919 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
920 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
921 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
922 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
923 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
924 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
925 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
926 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
927 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
928 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
929 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
930 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
931 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
932 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
933 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
934 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
935 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
936 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
937 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
938 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
939 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
940 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
941 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
942 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
943 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
944 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
945 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
946 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
947 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
948 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
949 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
950 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
951 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
952 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
953 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
954 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
955 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
956 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
957 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
958 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
959 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
960 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
961 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
962 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
963 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
964 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
965 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
966 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
967 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
968 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
969 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
970 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
971 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
972 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
973 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
974 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
975 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
976 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
977 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
978 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
979 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
980 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
981 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
982 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
983 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
984 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
985 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
986 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
987 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
988 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
989 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
990 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
991 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
992 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
993 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
994 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
995 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
996 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
997 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
998 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
999 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1025 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1026 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1048 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
1049 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1050 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1051 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1052 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1053 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
1054 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1055 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1056 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1057 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1058 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1059 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1060 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1061 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1062 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1063 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1064 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1072 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1073 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1074 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1075 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1076 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1077 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1078 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1079 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1107 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1108 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1109 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1112 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1140 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1141 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1142 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1143};
1144
1145#endif /* USE_SIT_FUNCTION */
1146
1147/* alias.c */
1148
1149
1150#define ATABSIZE 39
1151
1152static int funcblocksize; /* size of structures in function */
1153static int funcstringsize; /* size of strings in node */
1154static pointer funcblock; /* block to allocate function from */
1155static char *funcstring; /* block to allocate strings from */
1156
1157static const short nodesize[26] = {
1158 SHELL_ALIGN(sizeof (struct ncmd)),
1159 SHELL_ALIGN(sizeof (struct npipe)),
1160 SHELL_ALIGN(sizeof (struct nredir)),
1161 SHELL_ALIGN(sizeof (struct nredir)),
1162 SHELL_ALIGN(sizeof (struct nredir)),
1163 SHELL_ALIGN(sizeof (struct nbinary)),
1164 SHELL_ALIGN(sizeof (struct nbinary)),
1165 SHELL_ALIGN(sizeof (struct nbinary)),
1166 SHELL_ALIGN(sizeof (struct nif)),
1167 SHELL_ALIGN(sizeof (struct nbinary)),
1168 SHELL_ALIGN(sizeof (struct nbinary)),
1169 SHELL_ALIGN(sizeof (struct nfor)),
1170 SHELL_ALIGN(sizeof (struct ncase)),
1171 SHELL_ALIGN(sizeof (struct nclist)),
1172 SHELL_ALIGN(sizeof (struct narg)),
1173 SHELL_ALIGN(sizeof (struct narg)),
1174 SHELL_ALIGN(sizeof (struct nfile)),
1175 SHELL_ALIGN(sizeof (struct nfile)),
1176 SHELL_ALIGN(sizeof (struct nfile)),
1177 SHELL_ALIGN(sizeof (struct nfile)),
1178 SHELL_ALIGN(sizeof (struct nfile)),
1179 SHELL_ALIGN(sizeof (struct ndup)),
1180 SHELL_ALIGN(sizeof (struct ndup)),
1181 SHELL_ALIGN(sizeof (struct nhere)),
1182 SHELL_ALIGN(sizeof (struct nhere)),
1183 SHELL_ALIGN(sizeof (struct nnot)),
1184};
1185
1186
1187static void calcsize(union node *);
1188static void sizenodelist(struct nodelist *);
1189static union node *copynode(union node *);
1190static struct nodelist *copynodelist(struct nodelist *);
1191static char *nodesavestr(char *);
1192
1193
1194static int evalstring(char *, int mask);
1195union node; /* BLETCH for ansi C */
1196static void evaltree(union node *, int);
1197static void evalbackcmd(union node *, struct backcmd *);
1198
1199static int evalskip; /* set if we are skipping commands */
1200static int skipcount; /* number of levels to skip */
1201static int funcnest; /* depth of function calls */
1202
1203/* reasons for skipping commands (see comment on breakcmd routine) */
1204#define SKIPBREAK (1 << 0)
1205#define SKIPCONT (1 << 1)
1206#define SKIPFUNC (1 << 2)
1207#define SKIPFILE (1 << 3)
1208#define SKIPEVAL (1 << 4)
1209
1210/*
1211 * This file was generated by the mkbuiltins program.
1212 */
1213
1214#if JOBS
1215static int bgcmd(int, char **);
1216#endif
1217static int breakcmd(int, char **);
1218static int cdcmd(int, char **);
1219#ifdef CONFIG_ASH_CMDCMD
1220static int commandcmd(int, char **);
1221#endif
1222static int dotcmd(int, char **);
1223static int evalcmd(int, char **);
1224#ifdef CONFIG_ASH_BUILTIN_ECHO
1225static int echocmd(int, char **);
1226#endif
1227#ifdef CONFIG_ASH_BUILTIN_TEST
1228static int testcmd(int, char **);
1229#endif
1230static int execcmd(int, char **);
1231static int exitcmd(int, char **);
1232static int exportcmd(int, char **);
1233static int falsecmd(int, char **);
1234#if JOBS
1235static int fgcmd(int, char **);
1236#endif
1237#ifdef CONFIG_ASH_GETOPTS
1238static int getoptscmd(int, char **);
1239#endif
1240static int hashcmd(int, char **);
1241#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1242static int helpcmd(int argc, char **argv);
1243#endif
1244#if JOBS
1245static int jobscmd(int, char **);
1246#endif
1247#ifdef CONFIG_ASH_MATH_SUPPORT
1248static int letcmd(int, char **);
1249#endif
1250static int localcmd(int, char **);
1251static int pwdcmd(int, char **);
1252static int readcmd(int, char **);
1253static int returncmd(int, char **);
1254static int setcmd(int, char **);
1255static int shiftcmd(int, char **);
1256static int timescmd(int, char **);
1257static int trapcmd(int, char **);
1258static int truecmd(int, char **);
1259static int typecmd(int, char **);
1260static int umaskcmd(int, char **);
1261static int unsetcmd(int, char **);
1262static int waitcmd(int, char **);
1263static int ulimitcmd(int, char **);
1264#if JOBS
1265static int killcmd(int, char **);
1266#endif
1267
1268/* mail.h */
1269
1270#ifdef CONFIG_ASH_MAIL
1271static void chkmail(void);
1272static void changemail(const char *);
1273#endif
1274
1275/* exec.h */
1276
1277/* values of cmdtype */
1278#define CMDUNKNOWN -1 /* no entry in table for command */
1279#define CMDNORMAL 0 /* command is an executable program */
1280#define CMDFUNCTION 1 /* command is a shell function */
1281#define CMDBUILTIN 2 /* command is a shell builtin */
1282
1283struct builtincmd {
1284 const char *name;
1285 int (*builtin)(int, char **);
1286 /* unsigned flags; */
1287};
1288
1289
1290#define COMMANDCMD (builtincmd + 5 + \
1291 2 * ENABLE_ASH_BUILTIN_TEST + \
1292 ENABLE_ASH_ALIAS + \
1293 ENABLE_ASH_JOB_CONTROL)
1294#define EXECCMD (builtincmd + 7 + \
1295 2 * ENABLE_ASH_BUILTIN_TEST + \
1296 ENABLE_ASH_ALIAS + \
1297 ENABLE_ASH_JOB_CONTROL + \
1298 ENABLE_ASH_CMDCMD + \
1299 ENABLE_ASH_BUILTIN_ECHO)
1300
1301#define BUILTIN_NOSPEC "0"
1302#define BUILTIN_SPECIAL "1"
1303#define BUILTIN_REGULAR "2"
1304#define BUILTIN_SPEC_REG "3"
1305#define BUILTIN_ASSIGN "4"
1306#define BUILTIN_SPEC_ASSG "5"
1307#define BUILTIN_REG_ASSG "6"
1308#define BUILTIN_SPEC_REG_ASSG "7"
1309
1310#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1311#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1312#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1313
1314/* make sure to keep these in proper order since it is searched via bsearch() */
1315static const struct builtincmd builtincmd[] = {
1316 { BUILTIN_SPEC_REG ".", dotcmd },
1317 { BUILTIN_SPEC_REG ":", truecmd },
1318#ifdef CONFIG_ASH_BUILTIN_TEST
1319 { BUILTIN_REGULAR "[", testcmd },
1320 { BUILTIN_REGULAR "[[", testcmd },
1321#endif
1322#ifdef CONFIG_ASH_ALIAS
1323 { BUILTIN_REG_ASSG "alias", aliascmd },
1324#endif
1325#if JOBS
1326 { BUILTIN_REGULAR "bg", bgcmd },
1327#endif
1328 { BUILTIN_SPEC_REG "break", breakcmd },
1329 { BUILTIN_REGULAR "cd", cdcmd },
1330 { BUILTIN_NOSPEC "chdir", cdcmd },
1331#ifdef CONFIG_ASH_CMDCMD
1332 { BUILTIN_REGULAR "command", commandcmd },
1333#endif
1334 { BUILTIN_SPEC_REG "continue", breakcmd },
1335#ifdef CONFIG_ASH_BUILTIN_ECHO
1336 { BUILTIN_REGULAR "echo", echocmd },
1337#endif
1338 { BUILTIN_SPEC_REG "eval", evalcmd },
1339 { BUILTIN_SPEC_REG "exec", execcmd },
1340 { BUILTIN_SPEC_REG "exit", exitcmd },
1341 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1342 { BUILTIN_REGULAR "false", falsecmd },
1343#if JOBS
1344 { BUILTIN_REGULAR "fg", fgcmd },
1345#endif
1346#ifdef CONFIG_ASH_GETOPTS
1347 { BUILTIN_REGULAR "getopts", getoptscmd },
1348#endif
1349 { BUILTIN_NOSPEC "hash", hashcmd },
1350#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1351 { BUILTIN_NOSPEC "help", helpcmd },
1352#endif
1353#if JOBS
1354 { BUILTIN_REGULAR "jobs", jobscmd },
1355 { BUILTIN_REGULAR "kill", killcmd },
1356#endif
1357#ifdef CONFIG_ASH_MATH_SUPPORT
1358 { BUILTIN_NOSPEC "let", letcmd },
1359#endif
1360 { BUILTIN_ASSIGN "local", localcmd },
1361 { BUILTIN_NOSPEC "pwd", pwdcmd },
1362 { BUILTIN_REGULAR "read", readcmd },
1363 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1364 { BUILTIN_SPEC_REG "return", returncmd },
1365 { BUILTIN_SPEC_REG "set", setcmd },
1366 { BUILTIN_SPEC_REG "shift", shiftcmd },
1367 { BUILTIN_SPEC_REG "source", dotcmd },
1368#ifdef CONFIG_ASH_BUILTIN_TEST
1369 { BUILTIN_REGULAR "test", testcmd },
1370#endif
1371 { BUILTIN_SPEC_REG "times", timescmd },
1372 { BUILTIN_SPEC_REG "trap", trapcmd },
1373 { BUILTIN_REGULAR "true", truecmd },
1374 { BUILTIN_NOSPEC "type", typecmd },
1375 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1376 { BUILTIN_REGULAR "umask", umaskcmd },
1377#ifdef CONFIG_ASH_ALIAS
1378 { BUILTIN_REGULAR "unalias", unaliascmd },
1379#endif
1380 { BUILTIN_SPEC_REG "unset", unsetcmd },
1381 { BUILTIN_REGULAR "wait", waitcmd },
1382};
1383
1384#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1385
1386static const char *safe_applets[] = {
1387 "[", "test", "echo", "cat",
1388 "ln", "cp", "touch", "mkdir", "rm",
1389 "cut", "hexdump", "awk", "sort",
1390 "find", "xargs", "ls", "dd",
1391 "chown", "chmod"
1392};
1393
1394
1395struct cmdentry {
1396 int cmdtype;
1397 union param {
1398 int index;
1399 const struct builtincmd *cmd;
1400 struct funcnode *func;
1401 } u;
1402};
1403
1404
1405/* action to find_command() */
1406#define DO_ERR 0x01 /* prints errors */
1407#define DO_ABS 0x02 /* checks absolute paths */
1408#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1409#define DO_ALTPATH 0x08 /* using alternate path */
1410#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1411
1412static const char *pathopt; /* set by padvance */
1413
1414static void shellexec(char **, const char *, int)
1415 ATTRIBUTE_NORETURN;
1416static char *padvance(const char **, const char *);
1417static void find_command(char *, struct cmdentry *, int, const char *);
1418static struct builtincmd *find_builtin(const char *);
1419static void hashcd(void);
1420static void changepath(const char *);
1421static void defun(char *, union node *);
1422static void unsetfunc(const char *);
1423
1424#ifdef CONFIG_ASH_MATH_SUPPORT_64
1425typedef int64_t arith_t;
1426#define arith_t_type (long long)
1427#else
1428typedef long arith_t;
1429#define arith_t_type (long)
1430#endif
1431
1432#ifdef CONFIG_ASH_MATH_SUPPORT
1433static arith_t dash_arith(const char *);
1434static arith_t arith(const char *expr, int *perrcode);
1435#endif
1436
1437#ifdef CONFIG_ASH_RANDOM_SUPPORT
1438static unsigned long rseed;
1439static void change_random(const char *);
1440# ifndef DYNAMIC_VAR
1441# define DYNAMIC_VAR
1442# endif
1443#endif
1444
1445/* init.h */
1446
1447static void reset(void);
1448
1449/* var.h */
1450
1451/*
1452 * Shell variables.
1453 */
1454
1455/* flags */
1456#define VEXPORT 0x01 /* variable is exported */
1457#define VREADONLY 0x02 /* variable cannot be modified */
1458#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1459#define VTEXTFIXED 0x08 /* text is statically allocated */
1460#define VSTACK 0x10 /* text is allocated on the stack */
1461#define VUNSET 0x20 /* the variable is not set */
1462#define VNOFUNC 0x40 /* don't call the callback function */
1463#define VNOSET 0x80 /* do not set variable - just readonly test */
1464#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1465#ifdef DYNAMIC_VAR
1466# define VDYNAMIC 0x200 /* dynamic variable */
1467# else
1468# define VDYNAMIC 0
1469#endif
1470
1471struct var {
1472 struct var *next; /* next entry in hash list */
1473 int flags; /* flags are defined above */
1474 const char *text; /* name=value */
1475 void (*func)(const char *); /* function to be called when */
1476 /* the variable gets set/unset */
1477};
1478
1479struct localvar {
1480 struct localvar *next; /* next local variable in list */
1481 struct var *vp; /* the variable that was made local */
1482 int flags; /* saved flags */
1483 const char *text; /* saved text */
1484};
1485
1486
1487static struct localvar *localvars;
1488
1489/*
1490 * Shell variables.
1491 */
1492
1493#ifdef CONFIG_ASH_GETOPTS
1494static void getoptsreset(const char *);
1495#endif
1496
1497#ifdef CONFIG_LOCALE_SUPPORT
1498static void change_lc_all(const char *value);
1499static void change_lc_ctype(const char *value);
1500#endif
1501
1502
1503#define VTABSIZE 39
1504
1505static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1506#ifdef IFS_BROKEN
1507static const char defifsvar[] = "IFS= \t\n";
1508#define defifs (defifsvar + 4)
1509#else
1510static const char defifs[] = " \t\n";
1511#endif
1512
1513
1514static struct var varinit[] = {
1515#ifdef IFS_BROKEN
1516 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1517#else
1518 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1519#endif
1520
1521#ifdef CONFIG_ASH_MAIL
1522 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1523 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1524#endif
1525
1526 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1527 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1528 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1529 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1530#ifdef CONFIG_ASH_GETOPTS
1531 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1532#endif
1533#ifdef CONFIG_ASH_RANDOM_SUPPORT
1534 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1535#endif
1536#ifdef CONFIG_LOCALE_SUPPORT
1537 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1538 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1539#endif
1540#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1541 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1542#endif
1543};
1544
1545#define vifs varinit[0]
1546#ifdef CONFIG_ASH_MAIL
1547#define vmail (&vifs)[1]
1548#define vmpath (&vmail)[1]
1549#else
1550#define vmpath vifs
1551#endif
1552#define vpath (&vmpath)[1]
1553#define vps1 (&vpath)[1]
1554#define vps2 (&vps1)[1]
1555#define vps4 (&vps2)[1]
1556#define voptind (&vps4)[1]
1557#ifdef CONFIG_ASH_GETOPTS
1558#define vrandom (&voptind)[1]
1559#else
1560#define vrandom (&vps4)[1]
1561#endif
1562#define defpath (defpathvar + 5)
1563
1564/*
1565 * The following macros access the values of the above variables.
1566 * They have to skip over the name. They return the null string
1567 * for unset variables.
1568 */
1569
1570#define ifsval() (vifs.text + 4)
1571#define ifsset() ((vifs.flags & VUNSET) == 0)
1572#define mailval() (vmail.text + 5)
1573#define mpathval() (vmpath.text + 9)
1574#define pathval() (vpath.text + 5)
1575#define ps1val() (vps1.text + 4)
1576#define ps2val() (vps2.text + 4)
1577#define ps4val() (vps4.text + 4)
1578#define optindval() (voptind.text + 7)
1579
1580#define mpathset() ((vmpath.flags & VUNSET) == 0)
1581
1582static void setvar(const char *, const char *, int);
1583static void setvareq(char *, int);
1584static void listsetvar(struct strlist *, int);
1585static char *lookupvar(const char *);
1586static char *bltinlookup(const char *);
1587static char **listvars(int, int, char ***);
1588#define environment() listvars(VEXPORT, VUNSET, 0)
1589static int showvars(const char *, int, int);
1590static void poplocalvars(void);
1591static int unsetvar(const char *);
1592#ifdef CONFIG_ASH_GETOPTS
1593static int setvarsafe(const char *, const char *, int);
1594#endif
1595static int varcmp(const char *, const char *);
1596static struct var **hashvar(const char *);
1597
1598
1599static int varequal(const char *a, const char *b) {
1600 return !varcmp(a, b);
1601}
1602
1603
1604static int loopnest; /* current loop nesting level */
1605
1606/*
1607 * The parsefile structure pointed to by the global variable parsefile
1608 * contains information about the current file being read.
1609 */
1610
1611
1612struct redirtab {
1613 struct redirtab *next;
1614 int renamed[10];
1615 int nullredirs;
1616};
1617
1618static struct redirtab *redirlist;
1619static int nullredirs;
1620
1621extern char **environ;
1622
1623/* output.h */
1624
1625
1626static void outstr(const char *, FILE *);
1627static void outcslow(int, FILE *);
1628static void flushall(void);
1629static void flusherr(void);
1630static int out1fmt(const char *, ...)
1631 __attribute__((__format__(__printf__,1,2)));
1632static int fmtstr(char *, size_t, const char *, ...)
1633 __attribute__((__format__(__printf__,3,4)));
1634
1635static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1636
1637
1638static void out1str(const char *p)
1639{
1640 outstr(p, stdout);
1641}
1642
1643static void out2str(const char *p)
1644{
1645 outstr(p, stderr);
1646 flusherr();
1647}
1648
1649/*
1650 * Initialization code.
1651 */
1652
1653/*
1654 * This routine initializes the builtin variables.
1655 */
1656
1657static void initvar(void)
1658{
1659 struct var *vp;
1660 struct var *end;
1661 struct var **vpp;
1662
1663 /*
1664 * PS1 depends on uid
1665 */
1666#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1667 vps1.text = "PS1=\\w \\$ ";
1668#else
1669 if (!geteuid())
1670 vps1.text = "PS1=# ";
1671#endif
1672 vp = varinit;
1673 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1674 do {
1675 vpp = hashvar(vp->text);
1676 vp->next = *vpp;
1677 *vpp = vp;
1678 } while (++vp < end);
1679}
1680
1681static void init(void)
1682{
1683
1684 /* from input.c: */
1685 {
1686 basepf.nextc = basepf.buf = basebuf;
1687 }
1688
1689 /* from trap.c: */
1690 {
1691 signal(SIGCHLD, SIG_DFL);
1692 }
1693
1694 /* from var.c: */
1695 {
1696 char **envp;
1697 char ppid[32];
1698 const char *p;
1699 struct stat st1, st2;
1700
1701 initvar();
1702 for (envp = environ ; envp && *envp ; envp++) {
1703 if (strchr(*envp, '=')) {
1704 setvareq(*envp, VEXPORT|VTEXTFIXED);
1705 }
1706 }
1707
1708 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1709 setvar("PPID", ppid, 0);
1710
1711 p = lookupvar("PWD");
1712 if (p)
1713 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1714 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1715 p = 0;
1716 setpwd(p, 0);
1717 }
1718}
1719
1720/* PEOF (the end of file marker) */
1721
1722enum {
1723 INPUT_PUSH_FILE = 1,
1724 INPUT_NOFILE_OK = 2,
1725};
1726
1727/*
1728 * The input line number. Input.c just defines this variable, and saves
1729 * and restores it when files are pushed and popped. The user of this
1730 * package must set its value.
1731 */
1732
1733static int pgetc(void);
1734static int pgetc2(void);
1735static int preadbuffer(void);
1736static void pungetc(void);
1737static void pushstring(char *, void *);
1738static void popstring(void);
1739static void setinputfd(int, int);
1740static void setinputstring(char *);
1741static void popfile(void);
1742static void popallfiles(void);
1743static void closescript(void);
1744
1745
1746/* jobs.h */
1747
1748
1749/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1750#define FORK_FG 0
1751#define FORK_BG 1
1752#define FORK_NOJOB 2
1753
1754/* mode flags for showjob(s) */
1755#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1756#define SHOW_PID 0x04 /* include process pid */
1757#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1758
1759
1760/*
1761 * A job structure contains information about a job. A job is either a
1762 * single process or a set of processes contained in a pipeline. In the
1763 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1764 * array of pids.
1765 */
1766
1767struct procstat {
1768 pid_t pid; /* process id */
1769 int status; /* last process status from wait() */
1770 char *cmd; /* text of command being run */
1771};
1772
1773struct job {
1774 struct procstat ps0; /* status of process */
1775 struct procstat *ps; /* status or processes when more than one */
1776#if JOBS
1777 int stopstatus; /* status of a stopped job */
1778#endif
1779 uint32_t
1780 nprocs: 16, /* number of processes */
1781 state: 8,
1782#define JOBRUNNING 0 /* at least one proc running */
1783#define JOBSTOPPED 1 /* all procs are stopped */
1784#define JOBDONE 2 /* all procs are completed */
1785#if JOBS
1786 sigint: 1, /* job was killed by SIGINT */
1787 jobctl: 1, /* job running under job control */
1788#endif
1789 waited: 1, /* true if this entry has been waited for */
1790 used: 1, /* true if this entry is in used */
1791 changed: 1; /* true if status has changed */
1792 struct job *prev_job; /* previous job */
1793};
1794
1795static pid_t backgndpid; /* pid of last background process */
1796static int job_warning; /* user was warned about stopped jobs */
1797#if JOBS
1798static int jobctl; /* true if doing job control */
1799#endif
1800
1801static struct job *makejob(union node *, int);
1802static int forkshell(struct job *, union node *, int);
1803static int waitforjob(struct job *);
1804static int stoppedjobs(void);
1805
1806#if ! JOBS
1807#define setjobctl(on) /* do nothing */
1808#else
1809static void setjobctl(int);
1810static void showjobs(FILE *, int);
1811#endif
1812
1813/* main.h */
1814
1815
1816/* pid of main shell */
1817static int rootpid;
1818/* shell level: 0 for the main shell, 1 for its children, and so on */
1819static int shlvl;
1820#define rootshell (!shlvl)
1821
1822static void readcmdfile(char *);
1823static int cmdloop(int);
1824
1825/* memalloc.h */
1826
1827
1828struct stackmark {
1829 struct stack_block *stackp;
1830 char *stacknxt;
1831 size_t stacknleft;
1832 struct stackmark *marknext;
1833};
1834
1835/* minimum size of a block */
1836#define MINSIZE SHELL_ALIGN(504)
1837
1838struct stack_block {
1839 struct stack_block *prev;
1840 char space[MINSIZE];
1841};
1842
1843static struct stack_block stackbase;
1844static struct stack_block *stackp = &stackbase;
1845static struct stackmark *markp;
1846static char *stacknxt = stackbase.space;
1847static size_t stacknleft = MINSIZE;
1848static char *sstrend = stackbase.space + MINSIZE;
1849static int herefd = -1;
1850
1851
1852static pointer ckmalloc(size_t);
1853static pointer ckrealloc(pointer, size_t);
1854static char *savestr(const char *);
1855static pointer stalloc(size_t);
1856static void stunalloc(pointer);
1857static void setstackmark(struct stackmark *);
1858static void popstackmark(struct stackmark *);
1859static void growstackblock(void);
1860static void *growstackstr(void);
1861static char *makestrspace(size_t, char *);
1862static char *stnputs(const char *, size_t, char *);
1863static char *stputs(const char *, char *);
1864
1865
1866static char *_STPUTC(int c, char *p) {
1867 if (p == sstrend)
1868 p = growstackstr();
1869 *p++ = c;
1870 return p;
1871}
1872
1873#define stackblock() ((void *)stacknxt)
1874#define stackblocksize() stacknleft
1875#define STARTSTACKSTR(p) ((p) = stackblock())
1876#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1877#define CHECKSTRSPACE(n, p) \
1878 ({ \
1879 char *q = (p); \
1880 size_t l = (n); \
1881 size_t m = sstrend - q; \
1882 if (l > m) \
1883 (p) = makestrspace(l, q); \
1884 0; \
1885 })
1886#define USTPUTC(c, p) (*p++ = (c))
1887#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1888#define STUNPUTC(p) (--p)
1889#define STTOPC(p) p[-1]
1890#define STADJUST(amount, p) (p += (amount))
1891
1892#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1893#define ungrabstackstr(s, p) stunalloc((s))
1894#define stackstrend() ((void *)sstrend)
1895
1896#define ckfree(p) free((pointer)(p))
1897
1898/* mystring.h */
1899
1900
1901#define DOLATSTRLEN 4
1902
1903static char *prefix(const char *, const char *);
1904static int number(const char *);
1905static int is_number(const char *);
1906static char *single_quote(const char *);
1907static char *sstrdup(const char *);
1908
1909#define equal(s1, s2) (strcmp(s1, s2) == 0)
1910#define scopy(s1, s2) ((void)strcpy(s2, s1))
1911
1912/* options.h */
1913
1914struct shparam {
1915 int nparam; /* # of positional parameters (without $0) */
1916 unsigned char malloc; /* if parameter list dynamically allocated */
1917 char **p; /* parameter list */
1918#ifdef CONFIG_ASH_GETOPTS
1919 int optind; /* next parameter to be processed by getopts */
1920 int optoff; /* used by getopts */
1921#endif
1922};
1923
1924
1925#define eflag optlist[0]
1926#define fflag optlist[1]
1927#define Iflag optlist[2]
1928#define iflag optlist[3]
1929#define mflag optlist[4]
1930#define nflag optlist[5]
1931#define sflag optlist[6]
1932#define xflag optlist[7]
1933#define vflag optlist[8]
1934#define Cflag optlist[9]
1935#define aflag optlist[10]
1936#define bflag optlist[11]
1937#define uflag optlist[12]
1938#define viflag optlist[13]
1939
1940#if DEBUG
1941#define nolog optlist[14]
1942#define debug optlist[15]
1943#endif
1944
1945#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1946#define setvimode(on) viflag = 0 /* forcibly keep the option off */
1947#endif
1948
1949/* options.c */
1950
1951
1952static const char *const optletters_optnames[] = {
1953 "e" "errexit",
1954 "f" "noglob",
1955 "I" "ignoreeof",
1956 "i" "interactive",
1957 "m" "monitor",
1958 "n" "noexec",
1959 "s" "stdin",
1960 "x" "xtrace",
1961 "v" "verbose",
1962 "C" "noclobber",
1963 "a" "allexport",
1964 "b" "notify",
1965 "u" "nounset",
1966 "\0" "vi",
1967#if DEBUG
1968 "\0" "nolog",
1969 "\0" "debug",
1970#endif
1971};
1972
1973#define optletters(n) optletters_optnames[(n)][0]
1974#define optnames(n) (&optletters_optnames[(n)][1])
1975
1976#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
1977
1978static char optlist[NOPTS];
1979
1980
1981static char *arg0; /* value of $0 */
1982static struct shparam shellparam; /* $@ current positional parameters */
1983static char **argptr; /* argument list for builtin commands */
1984static char *optionarg; /* set by nextopt (like getopt) */
1985static char *optptr; /* used by nextopt */
1986
1987static char *minusc; /* argument to -c option */
1988
1989
1990static void procargs(int, char **);
1991static void optschanged(void);
1992static void setparam(char **);
1993static void freeparam(volatile struct shparam *);
1994static int shiftcmd(int, char **);
1995static int setcmd(int, char **);
1996static int nextopt(const char *);
1997
1998/* redir.h */
1999
2000/* flags passed to redirect */
2001#define REDIR_PUSH 01 /* save previous values of file descriptors */
2002#define REDIR_SAVEFD2 03 /* set preverrout */
2003
2004union node;
2005static void redirect(union node *, int);
2006static void popredir(int);
2007static void clearredir(int);
2008static int copyfd(int, int);
2009static int redirectsafe(union node *, int);
2010
2011/* show.h */
2012
2013
2014#if DEBUG
2015static void showtree(union node *);
2016static void trace(const char *, ...);
2017static void tracev(const char *, va_list);
2018static void trargs(char **);
2019static void trputc(int);
2020static void trputs(const char *);
2021static void opentrace(void);
2022#endif
2023
2024/* trap.h */
2025
2026
2027/* trap handler commands */
2028static char *trap[NSIG];
2029/* current value of signal */
2030static char sigmode[NSIG - 1];
2031/* indicates specified signal received */
2032static char gotsig[NSIG - 1];
2033
2034static void clear_traps(void);
2035static void setsignal(int);
2036static void ignoresig(int);
2037static void onsig(int);
2038static int dotrap(void);
2039static void setinteractive(int);
2040static void exitshell(void) ATTRIBUTE_NORETURN;
2041
2042
2043static int is_safe_applet(char *name)
2044{
2045 int n = sizeof(safe_applets) / sizeof(char *);
2046 int i;
2047 for (i = 0; i < n; i++)
2048 if (strcmp(safe_applets[i], name) == 0)
2049 return 1;
2050
2051 return 0;
2052}
2053
2054
2055/*
2056 * This routine is called when an error or an interrupt occurs in an
2057 * interactive shell and control is returned to the main command loop.
2058 */
2059
2060static void
2061reset(void)
2062{
2063 /* from eval.c: */
2064 {
2065 evalskip = 0;
2066 loopnest = 0;
2067 }
2068
2069 /* from input.c: */
2070 {
2071 parselleft = parsenleft = 0; /* clear input buffer */
2072 popallfiles();
2073 }
2074
2075 /* from parser.c: */
2076 {
2077 tokpushback = 0;
2078 checkkwd = 0;
2079 }
2080
2081 /* from redir.c: */
2082 {
2083 clearredir(0);
2084 }
2085
2086}
2087
2088#ifdef CONFIG_ASH_ALIAS
2089static struct alias *atab[ATABSIZE];
2090
2091static void setalias(const char *, const char *);
2092static struct alias *freealias(struct alias *);
2093static struct alias **__lookupalias(const char *);
2094
2095static void
2096setalias(const char *name, const char *val)
2097{
2098 struct alias *ap, **app;
2099
2100 app = __lookupalias(name);
2101 ap = *app;
2102 INTOFF;
2103 if (ap) {
2104 if (!(ap->flag & ALIASINUSE)) {
2105 ckfree(ap->val);
2106 }
2107 ap->val = savestr(val);
2108 ap->flag &= ~ALIASDEAD;
2109 } else {
2110 /* not found */
2111 ap = ckmalloc(sizeof (struct alias));
2112 ap->name = savestr(name);
2113 ap->val = savestr(val);
2114 ap->flag = 0;
2115 ap->next = 0;
2116 *app = ap;
2117 }
2118 INTON;
2119}
2120
2121static int
2122unalias(const char *name)
2123{
2124 struct alias **app;
2125
2126 app = __lookupalias(name);
2127
2128 if (*app) {
2129 INTOFF;
2130 *app = freealias(*app);
2131 INTON;
2132 return 0;
2133 }
2134
2135 return 1;
2136}
2137
2138static void
2139rmaliases(void)
2140{
2141 struct alias *ap, **app;
2142 int i;
2143
2144 INTOFF;
2145 for (i = 0; i < ATABSIZE; i++) {
2146 app = &atab[i];
2147 for (ap = *app; ap; ap = *app) {
2148 *app = freealias(*app);
2149 if (ap == *app) {
2150 app = &ap->next;
2151 }
2152 }
2153 }
2154 INTON;
2155}
2156
2157static struct alias *
2158lookupalias(const char *name, int check)
2159{
2160 struct alias *ap = *__lookupalias(name);
2161
2162 if (check && ap && (ap->flag & ALIASINUSE))
2163 return NULL;
2164 return ap;
2165}
2166
2167/*
2168 * TODO - sort output
2169 */
2170static int
2171aliascmd(int argc, char **argv)
2172{
2173 char *n, *v;
2174 int ret = 0;
2175 struct alias *ap;
2176
2177 if (argc == 1) {
2178 int i;
2179
2180 for (i = 0; i < ATABSIZE; i++)
2181 for (ap = atab[i]; ap; ap = ap->next) {
2182 printalias(ap);
2183 }
2184 return 0;
2185 }
2186 while ((n = *++argv) != NULL) {
2187 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2188 if ((ap = *__lookupalias(n)) == NULL) {
2189 fprintf(stderr, "%s: %s not found\n", "alias", n);
2190 ret = 1;
2191 } else
2192 printalias(ap);
2193 } else {
2194 *v++ = '\0';
2195 setalias(n, v);
2196 }
2197 }
2198
2199 return ret;
2200}
2201
2202static int
2203unaliascmd(int argc, char **argv)
2204{
2205 int i;
2206
2207 while ((i = nextopt("a")) != '\0') {
2208 if (i == 'a') {
2209 rmaliases();
2210 return 0;
2211 }
2212 }
2213 for (i = 0; *argptr; argptr++) {
2214 if (unalias(*argptr)) {
2215 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2216 i = 1;
2217 }
2218 }
2219
2220 return i;
2221}
2222
2223static struct alias *
2224freealias(struct alias *ap) {
2225 struct alias *next;
2226
2227 if (ap->flag & ALIASINUSE) {
2228 ap->flag |= ALIASDEAD;
2229 return ap;
2230 }
2231
2232 next = ap->next;
2233 ckfree(ap->name);
2234 ckfree(ap->val);
2235 ckfree(ap);
2236 return next;
2237}
2238
2239static void
2240printalias(const struct alias *ap) {
2241 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2242}
2243
2244static struct alias **
2245__lookupalias(const char *name) {
2246 unsigned int hashval;
2247 struct alias **app;
2248 const char *p;
2249 unsigned int ch;
2250
2251 p = name;
2252
2253 ch = (unsigned char)*p;
2254 hashval = ch << 4;
2255 while (ch) {
2256 hashval += ch;
2257 ch = (unsigned char)*++p;
2258 }
2259 app = &atab[hashval % ATABSIZE];
2260
2261 for (; *app; app = &(*app)->next) {
2262 if (equal(name, (*app)->name)) {
2263 break;
2264 }
2265 }
2266
2267 return app;
2268}
2269#endif /* CONFIG_ASH_ALIAS */
2270
2271
2272/* cd.c */
2273
2274/*
2275 * The cd and pwd commands.
2276 */
2277
2278#define CD_PHYSICAL 1
2279#define CD_PRINT 2
2280
2281static int docd(const char *, int);
2282static int cdopt(void);
2283
2284static char *curdir = nullstr; /* current working directory */
2285static char *physdir = nullstr; /* physical working directory */
2286
2287static int
2288cdopt(void)
2289{
2290 int flags = 0;
2291 int i, j;
2292
2293 j = 'L';
2294 while ((i = nextopt("LP"))) {
2295 if (i != j) {
2296 flags ^= CD_PHYSICAL;
2297 j = i;
2298 }
2299 }
2300
2301 return flags;
2302}
2303
2304static int
2305cdcmd(int argc, char **argv)
2306{
2307 const char *dest;
2308 const char *path;
2309 const char *p;
2310 char c;
2311 struct stat statb;
2312 int flags;
2313
2314 flags = cdopt();
2315 dest = *argptr;
2316 if (!dest)
2317 dest = bltinlookup(homestr);
2318 else if (dest[0] == '-' && dest[1] == '\0') {
2319 dest = bltinlookup("OLDPWD");
2320 flags |= CD_PRINT;
2321 }
2322 if (!dest)
2323 dest = nullstr;
2324 if (*dest == '/')
2325 goto step7;
2326 if (*dest == '.') {
2327 c = dest[1];
2328dotdot:
2329 switch (c) {
2330 case '\0':
2331 case '/':
2332 goto step6;
2333 case '.':
2334 c = dest[2];
2335 if (c != '.')
2336 goto dotdot;
2337 }
2338 }
2339 if (!*dest)
2340 dest = ".";
2341 if (!(path = bltinlookup("CDPATH"))) {
2342step6:
2343step7:
2344 p = dest;
2345 goto docd;
2346 }
2347 do {
2348 c = *path;
2349 p = padvance(&path, dest);
2350 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2351 if (c && c != ':')
2352 flags |= CD_PRINT;
2353docd:
2354 if (!docd(p, flags))
2355 goto out;
2356 break;
2357 }
2358 } while (path);
2359 sh_error("can't cd to %s", dest);
2360 /* NOTREACHED */
2361out:
2362 if (flags & CD_PRINT)
2363 out1fmt(snlfmt, curdir);
2364 return 0;
2365}
2366
2367
2368/*
2369 * Update curdir (the name of the current directory) in response to a
2370 * cd command.
2371 */
2372
2373static const char * updatepwd(const char *dir)
2374{
2375 char *new;
2376 char *p;
2377 char *cdcomppath;
2378 const char *lim;
2379
2380 cdcomppath = sstrdup(dir);
2381 STARTSTACKSTR(new);
2382 if (*dir != '/') {
2383 if (curdir == nullstr)
2384 return 0;
2385 new = stputs(curdir, new);
2386 }
2387 new = makestrspace(strlen(dir) + 2, new);
2388 lim = stackblock() + 1;
2389 if (*dir != '/') {
2390 if (new[-1] != '/')
2391 USTPUTC('/', new);
2392 if (new > lim && *lim == '/')
2393 lim++;
2394 } else {
2395 USTPUTC('/', new);
2396 cdcomppath++;
2397 if (dir[1] == '/' && dir[2] != '/') {
2398 USTPUTC('/', new);
2399 cdcomppath++;
2400 lim++;
2401 }
2402 }
2403 p = strtok(cdcomppath, "/");
2404 while (p) {
2405 switch(*p) {
2406 case '.':
2407 if (p[1] == '.' && p[2] == '\0') {
2408 while (new > lim) {
2409 STUNPUTC(new);
2410 if (new[-1] == '/')
2411 break;
2412 }
2413 break;
2414 } else if (p[1] == '\0')
2415 break;
2416 /* fall through */
2417 default:
2418 new = stputs(p, new);
2419 USTPUTC('/', new);
2420 }
2421 p = strtok(0, "/");
2422 }
2423 if (new > lim)
2424 STUNPUTC(new);
2425 *new = 0;
2426 return stackblock();
2427}
2428
2429/*
2430 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2431 * know that the current directory has changed.
2432 */
2433
2434static int
2435docd(const char *dest, int flags)
2436{
2437 const char *dir = 0;
2438 int err;
2439
2440 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2441
2442 INTOFF;
2443 if (!(flags & CD_PHYSICAL)) {
2444 dir = updatepwd(dest);
2445 if (dir)
2446 dest = dir;
2447 }
2448 err = chdir(dest);
2449 if (err)
2450 goto out;
2451 setpwd(dir, 1);
2452 hashcd();
2453out:
2454 INTON;
2455 return err;
2456}
2457
2458/*
2459 * Find out what the current directory is. If we already know the current
2460 * directory, this routine returns immediately.
2461 */
2462static char * getpwd(void)
2463{
2464 char *dir = getcwd(0, 0);
2465 return dir ? dir : nullstr;
2466}
2467
2468static int
2469pwdcmd(int argc, char **argv)
2470{
2471 int flags;
2472 const char *dir = curdir;
2473
2474 flags = cdopt();
2475 if (flags) {
2476 if (physdir == nullstr)
2477 setpwd(dir, 0);
2478 dir = physdir;
2479 }
2480 out1fmt(snlfmt, dir);
2481 return 0;
2482}
2483
2484static void
2485setpwd(const char *val, int setold)
2486{
2487 char *oldcur, *dir;
2488
2489 oldcur = dir = curdir;
2490
2491 if (setold) {
2492 setvar("OLDPWD", oldcur, VEXPORT);
2493 }
2494 INTOFF;
2495 if (physdir != nullstr) {
2496 if (physdir != oldcur)
2497 free(physdir);
2498 physdir = nullstr;
2499 }
2500 if (oldcur == val || !val) {
2501 char *s = getpwd();
2502 physdir = s;
2503 if (!val)
2504 dir = s;
2505 } else
2506 dir = savestr(val);
2507 if (oldcur != dir && oldcur != nullstr) {
2508 free(oldcur);
2509 }
2510 curdir = dir;
2511 INTON;
2512 setvar("PWD", dir, VEXPORT);
2513}
2514
2515/* error.c */
2516
2517/*
2518 * Errors and exceptions.
2519 */
2520
2521/*
2522 * Code to handle exceptions in C.
2523 */
2524
2525
2526
2527static void exverror(int, const char *, va_list)
2528 ATTRIBUTE_NORETURN;
2529
2530/*
2531 * Called to raise an exception. Since C doesn't include exceptions, we
2532 * just do a longjmp to the exception handler. The type of exception is
2533 * stored in the global variable "exception".
2534 */
2535
2536static void
2537exraise(int e)
2538{
2539#if DEBUG
2540 if (handler == NULL)
2541 abort();
2542#endif
2543 INTOFF;
2544
2545 exception = e;
2546 longjmp(handler->loc, 1);
2547}
2548
2549
2550/*
2551 * Called from trap.c when a SIGINT is received. (If the user specifies
2552 * that SIGINT is to be trapped or ignored using the trap builtin, then
2553 * this routine is not called.) Suppressint is nonzero when interrupts
2554 * are held using the INTOFF macro. (The test for iflag is just
2555 * defensive programming.)
2556 */
2557
2558static void
2559onint(void) {
2560 int i;
2561
2562 intpending = 0;
2563 i = EXSIG;
2564 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2565 if (!(rootshell && iflag)) {
2566 signal(SIGINT, SIG_DFL);
2567 raise(SIGINT);
2568 }
2569 i = EXINT;
2570 }
2571 exraise(i);
2572 /* NOTREACHED */
2573}
2574
2575static void
2576exvwarning(const char *msg, va_list ap)
2577{
2578 FILE *errs;
2579
2580 errs = stderr;
2581 fprintf(errs, "%s: ", arg0);
2582 if (commandname) {
2583 const char *fmt = (!iflag || parsefile->fd) ?
2584 "%s: %d: " : "%s: ";
2585 fprintf(errs, fmt, commandname, startlinno);
2586 }
2587 vfprintf(errs, msg, ap);
2588 outcslow('\n', errs);
2589}
2590
2591/*
2592 * Exverror is called to raise the error exception. If the second argument
2593 * is not NULL then error prints an error message using printf style
2594 * formatting. It then raises the error exception.
2595 */
2596static void
2597exverror(int cond, const char *msg, va_list ap)
2598{
2599#if DEBUG
2600 if (msg) {
2601 TRACE(("exverror(%d, \"", cond));
2602 TRACEV((msg, ap));
2603 TRACE(("\") pid=%d\n", getpid()));
2604 } else
2605 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2606 if (msg)
2607#endif
2608 exvwarning(msg, ap);
2609
2610 flushall();
2611 exraise(cond);
2612 /* NOTREACHED */
2613}
2614
2615
2616static void
2617sh_error(const char *msg, ...)
2618{
2619 va_list ap;
2620
2621 va_start(ap, msg);
2622 exverror(EXERROR, msg, ap);
2623 /* NOTREACHED */
2624 va_end(ap);
2625}
2626
2627
2628static void
2629exerror(int cond, const char *msg, ...)
2630{
2631 va_list ap;
2632
2633 va_start(ap, msg);
2634 exverror(cond, msg, ap);
2635 /* NOTREACHED */
2636 va_end(ap);
2637}
2638
2639/*
2640 * error/warning routines for external builtins
2641 */
2642
2643static void
2644sh_warnx(const char *fmt, ...)
2645{
2646 va_list ap;
2647
2648 va_start(ap, fmt);
2649 exvwarning(fmt, ap);
2650 va_end(ap);
2651}
2652
2653
2654/*
2655 * Return a string describing an error. The returned string may be a
2656 * pointer to a static buffer that will be overwritten on the next call.
2657 * Action describes the operation that got the error.
2658 */
2659
2660static const char *
2661errmsg(int e, const char *em)
2662{
2663 if(e == ENOENT || e == ENOTDIR) {
2664
2665 return em;
2666 }
2667 return strerror(e);
2668}
2669
2670
2671/* eval.c */
2672
2673/*
2674 * Evaluate a command.
2675 */
2676
2677/* flags in argument to evaltree */
2678#define EV_EXIT 01 /* exit after evaluating tree */
2679#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2680#define EV_BACKCMD 04 /* command executing within back quotes */
2681
2682
2683static void evalloop(union node *, int);
2684static void evalfor(union node *, int);
2685static void evalcase(union node *, int);
2686static void evalsubshell(union node *, int);
2687static void expredir(union node *);
2688static void evalpipe(union node *, int);
2689static void evalcommand(union node *, int);
2690static int evalbltin(const struct builtincmd *, int, char **);
2691static int evalfun(struct funcnode *, int, char **, int);
2692static void prehash(union node *);
2693static int bltincmd(int, char **);
2694
2695
2696static const struct builtincmd bltin = {
2697 "\0\0", bltincmd
2698};
2699
2700
2701/*
2702 * Called to reset things after an exception.
2703 */
2704
2705/*
2706 * The eval command.
2707 */
2708
2709static int
2710evalcmd(int argc, char **argv)
2711{
2712 char *p;
2713 char *concat;
2714 char **ap;
2715
2716 if (argc > 1) {
2717 p = argv[1];
2718 if (argc > 2) {
2719 STARTSTACKSTR(concat);
2720 ap = argv + 2;
2721 for (;;) {
2722 concat = stputs(p, concat);
2723 if ((p = *ap++) == NULL)
2724 break;
2725 STPUTC(' ', concat);
2726 }
2727 STPUTC('\0', concat);
2728 p = grabstackstr(concat);
2729 }
2730 evalstring(p, ~SKIPEVAL);
2731
2732 }
2733 return exitstatus;
2734}
2735
2736
2737/*
2738 * Execute a command or commands contained in a string.
2739 */
2740
2741static int
2742evalstring(char *s, int mask)
2743{
2744 union node *n;
2745 struct stackmark smark;
2746 int skip;
2747
2748 setinputstring(s);
2749 setstackmark(&smark);
2750
2751 skip = 0;
2752 while ((n = parsecmd(0)) != NEOF) {
2753 evaltree(n, 0);
2754 popstackmark(&smark);
2755 skip = evalskip;
2756 if (skip)
2757 break;
2758 }
2759 popfile();
2760
2761 skip &= mask;
2762 evalskip = skip;
2763 return skip;
2764}
2765
2766
2767
2768/*
2769 * Evaluate a parse tree. The value is left in the global variable
2770 * exitstatus.
2771 */
2772
2773static void
2774evaltree(union node *n, int flags)
2775{
2776 int checkexit = 0;
2777 void (*evalfn)(union node *, int);
2778 unsigned isor;
2779 int status;
2780 if (n == NULL) {
2781 TRACE(("evaltree(NULL) called\n"));
2782 goto out;
2783 }
2784 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2785 getpid(), n, n->type, flags));
2786 switch (n->type) {
2787 default:
2788#if DEBUG
2789 out1fmt("Node type = %d\n", n->type);
2790 fflush(stdout);
2791 break;
2792#endif
2793 case NNOT:
2794 evaltree(n->nnot.com, EV_TESTED);
2795 status = !exitstatus;
2796 goto setstatus;
2797 case NREDIR:
2798 expredir(n->nredir.redirect);
2799 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2800 if (!status) {
2801 evaltree(n->nredir.n, flags & EV_TESTED);
2802 status = exitstatus;
2803 }
2804 popredir(0);
2805 goto setstatus;
2806 case NCMD:
2807 evalfn = evalcommand;
2808checkexit:
2809 if (eflag && !(flags & EV_TESTED))
2810 checkexit = ~0;
2811 goto calleval;
2812 case NFOR:
2813 evalfn = evalfor;
2814 goto calleval;
2815 case NWHILE:
2816 case NUNTIL:
2817 evalfn = evalloop;
2818 goto calleval;
2819 case NSUBSHELL:
2820 case NBACKGND:
2821 evalfn = evalsubshell;
2822 goto calleval;
2823 case NPIPE:
2824 evalfn = evalpipe;
2825 goto checkexit;
2826 case NCASE:
2827 evalfn = evalcase;
2828 goto calleval;
2829 case NAND:
2830 case NOR:
2831 case NSEMI:
2832#if NAND + 1 != NOR
2833#error NAND + 1 != NOR
2834#endif
2835#if NOR + 1 != NSEMI
2836#error NOR + 1 != NSEMI
2837#endif
2838 isor = n->type - NAND;
2839 evaltree(
2840 n->nbinary.ch1,
2841 (flags | ((isor >> 1) - 1)) & EV_TESTED
2842 );
2843 if (!exitstatus == isor)
2844 break;
2845 if (!evalskip) {
2846 n = n->nbinary.ch2;
2847evaln:
2848 evalfn = evaltree;
2849calleval:
2850 evalfn(n, flags);
2851 break;
2852 }
2853 break;
2854 case NIF:
2855 evaltree(n->nif.test, EV_TESTED);
2856 if (evalskip)
2857 break;
2858 if (exitstatus == 0) {
2859 n = n->nif.ifpart;
2860 goto evaln;
2861 } else if (n->nif.elsepart) {
2862 n = n->nif.elsepart;
2863 goto evaln;
2864 }
2865 goto success;
2866 case NDEFUN:
2867 defun(n->narg.text, n->narg.next);
2868success:
2869 status = 0;
2870setstatus:
2871 exitstatus = status;
2872 break;
2873 }
2874out:
2875 if ((checkexit & exitstatus))
2876 evalskip |= SKIPEVAL;
2877 else if (pendingsigs && dotrap())
2878 goto exexit;
2879
2880 if (flags & EV_EXIT) {
2881exexit:
2882 exraise(EXEXIT);
2883 }
2884}
2885
2886
2887#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2888static
2889#endif
2890void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2891
2892
2893static void
2894evalloop(union node *n, int flags)
2895{
2896 int status;
2897
2898 loopnest++;
2899 status = 0;
2900 flags &= EV_TESTED;
2901 for (;;) {
2902 int i;
2903
2904 evaltree(n->nbinary.ch1, EV_TESTED);
2905 if (evalskip) {
2906skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2907 evalskip = 0;
2908 continue;
2909 }
2910 if (evalskip == SKIPBREAK && --skipcount <= 0)
2911 evalskip = 0;
2912 break;
2913 }
2914 i = exitstatus;
2915 if (n->type != NWHILE)
2916 i = !i;
2917 if (i != 0)
2918 break;
2919 evaltree(n->nbinary.ch2, flags);
2920 status = exitstatus;
2921 if (evalskip)
2922 goto skipping;
2923 }
2924 loopnest--;
2925 exitstatus = status;
2926}
2927
2928
2929
2930static void
2931evalfor(union node *n, int flags)
2932{
2933 struct arglist arglist;
2934 union node *argp;
2935 struct strlist *sp;
2936 struct stackmark smark;
2937
2938 setstackmark(&smark);
2939 arglist.lastp = &arglist.list;
2940 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2941 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2942 /* XXX */
2943 if (evalskip)
2944 goto out;
2945 }
2946 *arglist.lastp = NULL;
2947
2948 exitstatus = 0;
2949 loopnest++;
2950 flags &= EV_TESTED;
2951 for (sp = arglist.list ; sp ; sp = sp->next) {
2952 setvar(n->nfor.var, sp->text, 0);
2953 evaltree(n->nfor.body, flags);
2954 if (evalskip) {
2955 if (evalskip == SKIPCONT && --skipcount <= 0) {
2956 evalskip = 0;
2957 continue;
2958 }
2959 if (evalskip == SKIPBREAK && --skipcount <= 0)
2960 evalskip = 0;
2961 break;
2962 }
2963 }
2964 loopnest--;
2965out:
2966 popstackmark(&smark);
2967}
2968
2969
2970
2971static void
2972evalcase(union node *n, int flags)
2973{
2974 union node *cp;
2975 union node *patp;
2976 struct arglist arglist;
2977 struct stackmark smark;
2978
2979 setstackmark(&smark);
2980 arglist.lastp = &arglist.list;
2981 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2982 exitstatus = 0;
2983 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2984 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2985 if (casematch(patp, arglist.list->text)) {
2986 if (evalskip == 0) {
2987 evaltree(cp->nclist.body, flags);
2988 }
2989 goto out;
2990 }
2991 }
2992 }
2993out:
2994 popstackmark(&smark);
2995}
2996
2997
2998
2999/*
3000 * Kick off a subshell to evaluate a tree.
3001 */
3002
3003static void
3004evalsubshell(union node *n, int flags)
3005{
3006 struct job *jp;
3007 int backgnd = (n->type == NBACKGND);
3008 int status;
3009
3010 expredir(n->nredir.redirect);
3011 if (!backgnd && flags & EV_EXIT && !trap[0])
3012 goto nofork;
3013 INTOFF;
3014 jp = makejob(n, 1);
3015 if (forkshell(jp, n, backgnd) == 0) {
3016 INTON;
3017 flags |= EV_EXIT;
3018 if (backgnd)
3019 flags &=~ EV_TESTED;
3020nofork:
3021 redirect(n->nredir.redirect, 0);
3022 evaltreenr(n->nredir.n, flags);
3023 /* never returns */
3024 }
3025 status = 0;
3026 if (! backgnd)
3027 status = waitforjob(jp);
3028 exitstatus = status;
3029 INTON;
3030}
3031
3032
3033
3034/*
3035 * Compute the names of the files in a redirection list.
3036 */
3037
3038static void
3039expredir(union node *n)
3040{
3041 union node *redir;
3042
3043 for (redir = n ; redir ; redir = redir->nfile.next) {
3044 struct arglist fn;
3045 memset(&fn, 0, sizeof(struct arglist));
3046 fn.lastp = &fn.list;
3047 switch (redir->type) {
3048 case NFROMTO:
3049 case NFROM:
3050 case NTO:
3051 case NCLOBBER:
3052 case NAPPEND:
3053 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3054 redir->nfile.expfname = fn.list->text;
3055 break;
3056 case NFROMFD:
3057 case NTOFD:
3058 if (redir->ndup.vname) {
3059 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3060 if (fn.list != NULL)
3061 fixredir(redir, fn.list->text, 1);
3062 else
3063 sh_error("redir error");
3064 }
3065 break;
3066 }
3067 }
3068}
3069
3070
3071
3072/*
3073 * Evaluate a pipeline. All the processes in the pipeline are children
3074 * of the process creating the pipeline. (This differs from some versions
3075 * of the shell, which make the last process in a pipeline the parent
3076 * of all the rest.)
3077 */
3078
3079static void
3080evalpipe(union node *n, int flags)
3081{
3082 struct job *jp;
3083 struct nodelist *lp;
3084 int pipelen;
3085 int prevfd;
3086 int pip[2];
3087
3088 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3089 pipelen = 0;
3090 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3091 pipelen++;
3092 flags |= EV_EXIT;
3093 INTOFF;
3094 jp = makejob(n, pipelen);
3095 prevfd = -1;
3096 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3097 prehash(lp->n);
3098 pip[1] = -1;
3099 if (lp->next) {
3100 if (pipe(pip) < 0) {
3101 close(prevfd);
3102 sh_error("Pipe call failed");
3103 }
3104 }
3105 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3106 INTON;
3107 if (pip[1] >= 0) {
3108 close(pip[0]);
3109 }
3110 if (prevfd > 0) {
3111 dup2(prevfd, 0);
3112 close(prevfd);
3113 }
3114 if (pip[1] > 1) {
3115 dup2(pip[1], 1);
3116 close(pip[1]);
3117 }
3118 evaltreenr(lp->n, flags);
3119 /* never returns */
3120 }
3121 if (prevfd >= 0)
3122 close(prevfd);
3123 prevfd = pip[0];
3124 close(pip[1]);
3125 }
3126 if (n->npipe.backgnd == 0) {
3127 exitstatus = waitforjob(jp);
3128 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3129 }
3130 INTON;
3131}
3132
3133
3134
3135/*
3136 * Execute a command inside back quotes. If it's a builtin command, we
3137 * want to save its output in a block obtained from malloc. Otherwise
3138 * we fork off a subprocess and get the output of the command via a pipe.
3139 * Should be called with interrupts off.
3140 */
3141
3142static void
3143evalbackcmd(union node *n, struct backcmd *result)
3144{
3145 int saveherefd;
3146
3147 result->fd = -1;
3148 result->buf = NULL;
3149 result->nleft = 0;
3150 result->jp = NULL;
3151 if (n == NULL) {
3152 goto out;
3153 }
3154
3155 saveherefd = herefd;
3156 herefd = -1;
3157
3158 {
3159 int pip[2];
3160 struct job *jp;
3161
3162 if (pipe(pip) < 0)
3163 sh_error("Pipe call failed");
3164 jp = makejob(n, 1);
3165 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3166 FORCEINTON;
3167 close(pip[0]);
3168 if (pip[1] != 1) {
3169 close(1);
3170 copyfd(pip[1], 1);
3171 close(pip[1]);
3172 }
3173 eflag = 0;
3174 evaltreenr(n, EV_EXIT);
3175 /* NOTREACHED */
3176 }
3177 close(pip[1]);
3178 result->fd = pip[0];
3179 result->jp = jp;
3180 }
3181 herefd = saveherefd;
3182out:
3183 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3184 result->fd, result->buf, result->nleft, result->jp));
3185}
3186
3187#ifdef CONFIG_ASH_CMDCMD
3188static char ** parse_command_args(char **argv, const char **path)
3189{
3190 char *cp, c;
3191
3192 for (;;) {
3193 cp = *++argv;
3194 if (!cp)
3195 return 0;
3196 if (*cp++ != '-')
3197 break;
3198 if (!(c = *cp++))
3199 break;
3200 if (c == '-' && !*cp) {
3201 argv++;
3202 break;
3203 }
3204 do {
3205 switch (c) {
3206 case 'p':
3207 *path = defpath;
3208 break;
3209 default:
3210 /* run 'typecmd' for other options */
3211 return 0;
3212 }
3213 } while ((c = *cp++));
3214 }
3215 return argv;
3216}
3217#endif
3218
3219static int isassignment(const char *p)
3220{
3221 const char *q = endofname(p);
3222 if (p == q)
3223 return 0;
3224 return *q == '=';
3225}
3226
3227#ifdef CONFIG_ASH_EXPAND_PRMT
3228static const char *expandstr(const char *ps);
3229#else
3230#define expandstr(s) s
3231#endif
3232
3233/*
3234 * Execute a simple command.
3235 */
3236
3237static void
3238evalcommand(union node *cmd, int flags)
3239{
3240 struct stackmark smark;
3241 union node *argp;
3242 struct arglist arglist;
3243 struct arglist varlist;
3244 char **argv;
3245 int argc;
3246 const struct strlist *sp;
3247 struct cmdentry cmdentry;
3248 struct job *jp;
3249 char *lastarg;
3250 const char *path;
3251 int spclbltin;
3252 int cmd_is_exec;
3253 int status;
3254 char **nargv;
3255 struct builtincmd *bcmd;
3256 int pseudovarflag = 0;
3257
3258 /* First expand the arguments. */
3259 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3260 setstackmark(&smark);
3261 back_exitstatus = 0;
3262
3263 cmdentry.cmdtype = CMDBUILTIN;
3264 cmdentry.u.cmd = &bltin;
3265 varlist.lastp = &varlist.list;
3266 *varlist.lastp = NULL;
3267 arglist.lastp = &arglist.list;
3268 *arglist.lastp = NULL;
3269
3270 argc = 0;
3271 if (cmd->ncmd.args)
3272 {
3273 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3274 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3275 }
3276
3277 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3278 struct strlist **spp;
3279
3280 spp = arglist.lastp;
3281 if (pseudovarflag && isassignment(argp->narg.text))
3282 expandarg(argp, &arglist, EXP_VARTILDE);
3283 else
3284 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3285
3286 for (sp = *spp; sp; sp = sp->next)
3287 argc++;
3288 }
3289
3290 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3291 for (sp = arglist.list ; sp ; sp = sp->next) {
3292 TRACE(("evalcommand arg: %s\n", sp->text));
3293 *nargv++ = sp->text;
3294 }
3295 *nargv = NULL;
3296
3297 lastarg = NULL;
3298 if (iflag && funcnest == 0 && argc > 0)
3299 lastarg = nargv[-1];
3300
3301 preverrout_fd = 2;
3302 expredir(cmd->ncmd.redirect);
3303 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3304
3305 path = vpath.text;
3306 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3307 struct strlist **spp;
3308 char *p;
3309
3310 spp = varlist.lastp;
3311 expandarg(argp, &varlist, EXP_VARTILDE);
3312
3313 /*
3314 * Modify the command lookup path, if a PATH= assignment
3315 * is present
3316 */
3317 p = (*spp)->text;
3318 if (varequal(p, path))
3319 path = p;
3320 }
3321
3322 /* Print the command if xflag is set. */
3323 if (xflag) {
3324 int n;
3325 const char *p = " %s";
3326
3327 p++;
3328 dprintf(preverrout_fd, p, expandstr(ps4val()));
3329
3330 sp = varlist.list;
3331 for(n = 0; n < 2; n++) {
3332 while (sp) {
3333 dprintf(preverrout_fd, p, sp->text);
3334 sp = sp->next;
3335 if(*p == '%') {
3336 p--;
3337 }
3338 }
3339 sp = arglist.list;
3340 }
3341 full_write(preverrout_fd, "\n", 1);
3342 }
3343
3344 cmd_is_exec = 0;
3345 spclbltin = -1;
3346
3347 /* Now locate the command. */
3348 if (argc) {
3349 const char *oldpath;
3350 int cmd_flag = DO_ERR;
3351
3352 path += 5;
3353 oldpath = path;
3354 for (;;) {
3355 find_command(argv[0], &cmdentry, cmd_flag, path);
3356 if (cmdentry.cmdtype == CMDUNKNOWN) {
3357 status = 127;
3358 flusherr();
3359 goto bail;
3360 }
3361
3362 /* implement bltin and command here */
3363 if (cmdentry.cmdtype != CMDBUILTIN)
3364 break;
3365 if (spclbltin < 0)
3366 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3367 if (cmdentry.u.cmd == EXECCMD)
3368 cmd_is_exec++;
3369#ifdef CONFIG_ASH_CMDCMD
3370 if (cmdentry.u.cmd == COMMANDCMD) {
3371
3372 path = oldpath;
3373 nargv = parse_command_args(argv, &path);
3374 if (!nargv)
3375 break;
3376 argc -= nargv - argv;
3377 argv = nargv;
3378 cmd_flag |= DO_NOFUNC;
3379 } else
3380#endif
3381 break;
3382 }
3383 }
3384
3385 if (status) {
3386 /* We have a redirection error. */
3387 if (spclbltin > 0)
3388 exraise(EXERROR);
3389bail:
3390 exitstatus = status;
3391 goto out;
3392 }
3393
3394 /* Execute the command. */
3395 switch (cmdentry.cmdtype) {
3396 default:
3397 /* Fork off a child process if necessary. */
3398 if (!(flags & EV_EXIT) || trap[0]) {
3399 INTOFF;
3400 jp = makejob(cmd, 1);
3401 if (forkshell(jp, cmd, FORK_FG) != 0) {
3402 exitstatus = waitforjob(jp);
3403 INTON;
3404 break;
3405 }
3406 FORCEINTON;
3407 }
3408 listsetvar(varlist.list, VEXPORT|VSTACK);
3409 shellexec(argv, path, cmdentry.u.index);
3410 /* NOTREACHED */
3411
3412 case CMDBUILTIN:
3413 cmdenviron = varlist.list;
3414 if (cmdenviron) {
3415 struct strlist *list = cmdenviron;
3416 int i = VNOSET;
3417 if (spclbltin > 0 || argc == 0) {
3418 i = 0;
3419 if (cmd_is_exec && argc > 1)
3420 i = VEXPORT;
3421 }
3422 listsetvar(list, i);
3423 }
3424 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3425 int exit_status;
3426 int i, j;
3427
3428 i = exception;
3429 if (i == EXEXIT)
3430 goto raise;
3431
3432 exit_status = 2;
3433 j = 0;
3434 if (i == EXINT)
3435 j = SIGINT;
3436 if (i == EXSIG)
3437 j = pendingsigs;
3438 if (j)
3439 exit_status = j + 128;
3440 exitstatus = exit_status;
3441
3442 if (i == EXINT || spclbltin > 0) {
3443raise:
3444 longjmp(handler->loc, 1);
3445 }
3446 FORCEINTON;
3447 }
3448 break;
3449
3450 case CMDFUNCTION:
3451 listsetvar(varlist.list, 0);
3452 if (evalfun(cmdentry.u.func, argc, argv, flags))
3453 goto raise;
3454 break;
3455 }
3456
3457out:
3458 popredir(cmd_is_exec);
3459 if (lastarg)
3460 /* dsl: I think this is intended to be used to support
3461 * '_' in 'vi' command mode during line editing...
3462 * However I implemented that within libedit itself.
3463 */
3464 setvar("_", lastarg, 0);
3465 popstackmark(&smark);
3466}
3467
3468static int
3469evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3470 char *volatile savecmdname;
3471 struct jmploc *volatile savehandler;
3472 struct jmploc jmploc;
3473 int i;
3474
3475 savecmdname = commandname;
3476 if ((i = setjmp(jmploc.loc)))
3477 goto cmddone;
3478 savehandler = handler;
3479 handler = &jmploc;
3480 commandname = argv[0];
3481 argptr = argv + 1;
3482 optptr = NULL; /* initialize nextopt */
3483 exitstatus = (*cmd->builtin)(argc, argv);
3484 flushall();
3485cmddone:
3486 exitstatus |= ferror(stdout);
3487 clearerr(stdout);
3488 commandname = savecmdname;
3489 exsig = 0;
3490 handler = savehandler;
3491
3492 return i;
3493}
3494
3495static int
3496evalfun(struct funcnode *func, int argc, char **argv, int flags)
3497{
3498 volatile struct shparam saveparam;
3499 struct localvar *volatile savelocalvars;
3500 struct jmploc *volatile savehandler;
3501 struct jmploc jmploc;
3502 int e;
3503
3504 saveparam = shellparam;
3505 savelocalvars = localvars;
3506 if ((e = setjmp(jmploc.loc))) {
3507 goto funcdone;
3508 }
3509 INTOFF;
3510 savehandler = handler;
3511 handler = &jmploc;
3512 localvars = NULL;
3513 shellparam.malloc = 0;
3514 func->count++;
3515 funcnest++;
3516 INTON;
3517 shellparam.nparam = argc - 1;
3518 shellparam.p = argv + 1;
3519#ifdef CONFIG_ASH_GETOPTS
3520 shellparam.optind = 1;
3521 shellparam.optoff = -1;
3522#endif
3523 evaltree(&func->n, flags & EV_TESTED);
3524funcdone:
3525 INTOFF;
3526 funcnest--;
3527 freefunc(func);
3528 poplocalvars();
3529 localvars = savelocalvars;
3530 freeparam(&shellparam);
3531 shellparam = saveparam;
3532 handler = savehandler;
3533 INTON;
3534 evalskip &= ~SKIPFUNC;
3535 return e;
3536}
3537
3538
3539static int goodname(const char *p)
3540{
3541 return !*endofname(p);
3542}
3543
3544/*
3545 * Search for a command. This is called before we fork so that the
3546 * location of the command will be available in the parent as well as
3547 * the child. The check for "goodname" is an overly conservative
3548 * check that the name will not be subject to expansion.
3549 */
3550
3551static void
3552prehash(union node *n)
3553{
3554 struct cmdentry entry;
3555
3556 if (n->type == NCMD && n->ncmd.args)
3557 if (goodname(n->ncmd.args->narg.text))
3558 find_command(n->ncmd.args->narg.text, &entry, 0,
3559 pathval());
3560}
3561
3562
3563
3564/*
3565 * Builtin commands. Builtin commands whose functions are closely
3566 * tied to evaluation are implemented here.
3567 */
3568
3569/*
3570 * No command given.
3571 */
3572
3573static int
3574bltincmd(int argc, char **argv)
3575{
3576 /*
3577 * Preserve exitstatus of a previous possible redirection
3578 * as POSIX mandates
3579 */
3580 return back_exitstatus;
3581}
3582
3583
3584/*
3585 * Handle break and continue commands. Break, continue, and return are
3586 * all handled by setting the evalskip flag. The evaluation routines
3587 * above all check this flag, and if it is set they start skipping
3588 * commands rather than executing them. The variable skipcount is
3589 * the number of loops to break/continue, or the number of function
3590 * levels to return. (The latter is always 1.) It should probably
3591 * be an error to break out of more loops than exist, but it isn't
3592 * in the standard shell so we don't make it one here.
3593 */
3594
3595static int
3596breakcmd(int argc, char **argv)
3597{
3598 int n = argc > 1 ? number(argv[1]) : 1;
3599
3600 if (n <= 0)
3601 sh_error(illnum, argv[1]);
3602 if (n > loopnest)
3603 n = loopnest;
3604 if (n > 0) {
3605 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3606 skipcount = n;
3607 }
3608 return 0;
3609}
3610
3611
3612/*
3613 * The return command.
3614 */
3615
3616static int
3617returncmd(int argc, char **argv)
3618{
3619 /*
3620 * If called outside a function, do what ksh does;
3621 * skip the rest of the file.
3622 */
3623 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
3624 return argv[1] ? number(argv[1]) : exitstatus;
3625}
3626
3627
3628static int
3629falsecmd(int argc, char **argv)
3630{
3631 return 1;
3632}
3633
3634
3635static int
3636truecmd(int argc, char **argv)
3637{
3638 return 0;
3639}
3640
3641
3642static int
3643execcmd(int argc, char **argv)
3644{
3645 if (argc > 1) {
3646 iflag = 0; /* exit on error */
3647 mflag = 0;
3648 optschanged();
3649 shellexec(argv + 1, pathval(), 0);
3650 }
3651 return 0;
3652}
3653
3654
3655/* exec.c */
3656
3657/*
3658 * When commands are first encountered, they are entered in a hash table.
3659 * This ensures that a full path search will not have to be done for them
3660 * on each invocation.
3661 *
3662 * We should investigate converting to a linear search, even though that
3663 * would make the command name "hash" a misnomer.
3664 */
3665
3666#define CMDTABLESIZE 31 /* should be prime */
3667#define ARB 1 /* actual size determined at run time */
3668
3669
3670
3671struct tblentry {
3672 struct tblentry *next; /* next entry in hash chain */
3673 union param param; /* definition of builtin function */
3674 short cmdtype; /* index identifying command */
3675 char rehash; /* if set, cd done since entry created */
3676 char cmdname[ARB]; /* name of command */
3677};
3678
3679
3680static struct tblentry *cmdtable[CMDTABLESIZE];
3681static int builtinloc = -1; /* index in path of %builtin, or -1 */
3682
3683
3684static void tryexec(char *, char **, char **);
3685static void clearcmdentry(int);
3686static struct tblentry *cmdlookup(const char *, int);
3687static void delete_cmd_entry(void);
3688
3689
3690/*
3691 * Exec a program. Never returns. If you change this routine, you may
3692 * have to change the find_command routine as well.
3693 */
3694
3695static void
3696shellexec(char **argv, const char *path, int idx)
3697{
3698 char *cmdname;
3699 int e;
3700 char **envp;
3701 int exerrno;
3702
3703 clearredir(1);
3704 envp = environment();
3705 if (strchr(argv[0], '/') != NULL
3706 || is_safe_applet(argv[0])
3707#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3708 || find_applet_by_name(argv[0])
3709#endif
3710 ) {
3711 tryexec(argv[0], argv, envp);
3712 e = errno;
3713 } else {
3714 e = ENOENT;
3715 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3716 if (--idx < 0 && pathopt == NULL) {
3717 tryexec(cmdname, argv, envp);
3718 if (errno != ENOENT && errno != ENOTDIR)
3719 e = errno;
3720 }
3721 stunalloc(cmdname);
3722 }
3723 }
3724
3725 /* Map to POSIX errors */
3726 switch (e) {
3727 case EACCES:
3728 exerrno = 126;
3729 break;
3730 case ENOENT:
3731 exerrno = 127;
3732 break;
3733 default:
3734 exerrno = 2;
3735 break;
3736 }
3737 exitstatus = exerrno;
3738 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3739 argv[0], e, suppressint ));
3740 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3741 /* NOTREACHED */
3742}
3743
3744
3745static void
3746tryexec(char *cmd, char **argv, char **envp)
3747{
3748 int repeated = 0;
3749 struct BB_applet *a;
3750 int argc = 0;
3751 char **c;
3752
3753 if(strchr(cmd, '/') == NULL && is_safe_applet(cmd) && (a = find_applet_by_name(cmd)) != NULL) {
3754 c = argv;
3755 while (*c != NULL) {
3756 c++; argc++;
3757 }
3758 applet_name = cmd;
3759 exit(a->main(argc, argv));
3760 }
3761#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3762 if(find_applet_by_name(cmd) != NULL) {
3763 /* re-exec ourselves with the new arguments */
3764 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp);
3765 /* If they called chroot or otherwise made the binary no longer
3766 * executable, fall through */
3767 }
3768#endif
3769
3770repeat:
3771#ifdef SYSV
3772 do {
3773 execve(cmd, argv, envp);
3774 } while (errno == EINTR);
3775#else
3776 execve(cmd, argv, envp);
3777#endif
3778 if (repeated++) {
3779 ckfree(argv);
3780 } else if (errno == ENOEXEC) {
3781 char **ap;
3782 char **new;
3783
3784 for (ap = argv; *ap; ap++)
3785 ;
3786 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3787 ap[1] = cmd;
3788 *ap = cmd = (char *)DEFAULT_SHELL;
3789 ap += 2;
3790 argv++;
3791 while ((*ap++ = *argv++))
3792 ;
3793 argv = new;
3794 goto repeat;
3795 }
3796}
3797
3798
3799
3800/*
3801 * Do a path search. The variable path (passed by reference) should be
3802 * set to the start of the path before the first call; padvance will update
3803 * this value as it proceeds. Successive calls to padvance will return
3804 * the possible path expansions in sequence. If an option (indicated by
3805 * a percent sign) appears in the path entry then the global variable
3806 * pathopt will be set to point to it; otherwise pathopt will be set to
3807 * NULL.
3808 */
3809
3810static char *
3811padvance(const char **path, const char *name)
3812{
3813 const char *p;
3814 char *q;
3815 const char *start;
3816 size_t len;
3817
3818 if (*path == NULL)
3819 return NULL;
3820 start = *path;
3821 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3822 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3823 while (stackblocksize() < len)
3824 growstackblock();
3825 q = stackblock();
3826 if (p != start) {
3827 memcpy(q, start, p - start);
3828 q += p - start;
3829 *q++ = '/';
3830 }
3831 strcpy(q, name);
3832 pathopt = NULL;
3833 if (*p == '%') {
3834 pathopt = ++p;
3835 while (*p && *p != ':') p++;
3836 }
3837 if (*p == ':')
3838 *path = p + 1;
3839 else
3840 *path = NULL;
3841 return stalloc(len);
3842}
3843
3844
3845/*** Command hashing code ***/
3846
3847static void
3848printentry(struct tblentry *cmdp)
3849{
3850 int idx;
3851 const char *path;
3852 char *name;
3853
3854 idx = cmdp->param.index;
3855 path = pathval();
3856 do {
3857 name = padvance(&path, cmdp->cmdname);
3858 stunalloc(name);
3859 } while (--idx >= 0);
3860 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3861}
3862
3863
3864static int
3865hashcmd(int argc, char **argv)
3866{
3867 struct tblentry **pp;
3868 struct tblentry *cmdp;
3869 int c;
3870 struct cmdentry entry;
3871 char *name;
3872
3873 while ((c = nextopt("r")) != '\0') {
3874 clearcmdentry(0);
3875 return 0;
3876 }
3877 if (*argptr == NULL) {
3878 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3879 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3880 if (cmdp->cmdtype == CMDNORMAL)
3881 printentry(cmdp);
3882 }
3883 }
3884 return 0;
3885 }
3886 c = 0;
3887 while ((name = *argptr) != NULL) {
3888 if ((cmdp = cmdlookup(name, 0)) != NULL
3889 && (cmdp->cmdtype == CMDNORMAL
3890 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3891 delete_cmd_entry();
3892 find_command(name, &entry, DO_ERR, pathval());
3893 if (entry.cmdtype == CMDUNKNOWN)
3894 c = 1;
3895 argptr++;
3896 }
3897 return c;
3898}
3899
3900
3901/*
3902 * Resolve a command name. If you change this routine, you may have to
3903 * change the shellexec routine as well.
3904 */
3905
3906static void
3907find_command(char *name, struct cmdentry *entry, int act, const char *path)
3908{
3909 struct tblentry *cmdp;
3910 int idx;
3911 int prev;
3912 char *fullname;
3913 struct stat statb;
3914 int e;
3915 int updatetbl;
3916 struct builtincmd *bcmd;
3917
3918 /* If name contains a slash, don't use PATH or hash table */
3919 if (strchr(name, '/') != NULL) {
3920 entry->u.index = -1;
3921 if (act & DO_ABS) {
3922 while (stat(name, &statb) < 0) {
3923#ifdef SYSV
3924 if (errno == EINTR)
3925 continue;
3926#endif
3927 entry->cmdtype = CMDUNKNOWN;
3928 return;
3929 }
3930 }
3931 entry->cmdtype = CMDNORMAL;
3932 return;
3933 }
3934
3935#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3936 if (find_applet_by_name(name)) {
3937 entry->cmdtype = CMDNORMAL;
3938 entry->u.index = -1;
3939 return;
3940 }
3941#endif
3942
3943 if (is_safe_applet(name)) {
3944 entry->cmdtype = CMDNORMAL;
3945 entry->u.index = -1;
3946 return;
3947 }
3948
3949 updatetbl = (path == pathval());
3950 if (!updatetbl) {
3951 act |= DO_ALTPATH;
3952 if (strstr(path, "%builtin") != NULL)
3953 act |= DO_ALTBLTIN;
3954 }
3955
3956 /* If name is in the table, check answer will be ok */
3957 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3958 int bit;
3959
3960 switch (cmdp->cmdtype) {
3961 default:
3962#if DEBUG
3963 abort();
3964#endif
3965 case CMDNORMAL:
3966 bit = DO_ALTPATH;
3967 break;
3968 case CMDFUNCTION:
3969 bit = DO_NOFUNC;
3970 break;
3971 case CMDBUILTIN:
3972 bit = DO_ALTBLTIN;
3973 break;
3974 }
3975 if (act & bit) {
3976 updatetbl = 0;
3977 cmdp = NULL;
3978 } else if (cmdp->rehash == 0)
3979 /* if not invalidated by cd, we're done */
3980 goto success;
3981 }
3982
3983 /* If %builtin not in path, check for builtin next */
3984 bcmd = find_builtin(name);
3985 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3986 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3987 )))
3988 goto builtin_success;
3989
3990 /* We have to search path. */
3991 prev = -1; /* where to start */
3992 if (cmdp && cmdp->rehash) { /* doing a rehash */
3993 if (cmdp->cmdtype == CMDBUILTIN)
3994 prev = builtinloc;
3995 else
3996 prev = cmdp->param.index;
3997 }
3998
3999 e = ENOENT;
4000 idx = -1;
4001loop:
4002 while ((fullname = padvance(&path, name)) != NULL) {
4003 stunalloc(fullname);
4004 idx++;
4005 if (pathopt) {
4006 if (prefix(pathopt, "builtin")) {
4007 if (bcmd)
4008 goto builtin_success;
4009 continue;
4010 } else if (!(act & DO_NOFUNC) &&
4011 prefix(pathopt, "func")) {
4012 /* handled below */
4013 } else {
4014 /* ignore unimplemented options */
4015 continue;
4016 }
4017 }
4018 /* if rehash, don't redo absolute path names */
4019 if (fullname[0] == '/' && idx <= prev) {
4020 if (idx < prev)
4021 continue;
4022 TRACE(("searchexec \"%s\": no change\n", name));
4023 goto success;
4024 }
4025 while (stat(fullname, &statb) < 0) {
4026#ifdef SYSV
4027 if (errno == EINTR)
4028 continue;
4029#endif
4030 if (errno != ENOENT && errno != ENOTDIR)
4031 e = errno;
4032 goto loop;
4033 }
4034 e = EACCES; /* if we fail, this will be the error */
4035 if (!S_ISREG(statb.st_mode))
4036 continue;
4037 if (pathopt) { /* this is a %func directory */
4038 stalloc(strlen(fullname) + 1);
4039 readcmdfile(fullname);
4040 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4041 cmdp->cmdtype != CMDFUNCTION)
4042 sh_error("%s not defined in %s", name, fullname);
4043 stunalloc(fullname);
4044 goto success;
4045 }
4046 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4047 if (!updatetbl) {
4048 entry->cmdtype = CMDNORMAL;
4049 entry->u.index = idx;
4050 return;
4051 }
4052 INTOFF;
4053 cmdp = cmdlookup(name, 1);
4054 cmdp->cmdtype = CMDNORMAL;
4055 cmdp->param.index = idx;
4056 INTON;
4057 goto success;
4058 }
4059
4060 /* We failed. If there was an entry for this command, delete it */
4061 if (cmdp && updatetbl)
4062 delete_cmd_entry();
4063 if (act & DO_ERR)
4064 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4065 entry->cmdtype = CMDUNKNOWN;
4066 return;
4067
4068builtin_success:
4069 if (!updatetbl) {
4070 entry->cmdtype = CMDBUILTIN;
4071 entry->u.cmd = bcmd;
4072 return;
4073 }
4074 INTOFF;
4075 cmdp = cmdlookup(name, 1);
4076 cmdp->cmdtype = CMDBUILTIN;
4077 cmdp->param.cmd = bcmd;
4078 INTON;
4079success:
4080 cmdp->rehash = 0;
4081 entry->cmdtype = cmdp->cmdtype;
4082 entry->u = cmdp->param;
4083}
4084
4085
4086/*
4087 * Wrapper around strcmp for qsort/bsearch/...
4088 */
4089static int pstrcmp(const void *a, const void *b)
4090{
4091 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4092}
4093
4094/*
4095 * Search the table of builtin commands.
4096 */
4097
4098static struct builtincmd *
4099find_builtin(const char *name)
4100{
4101 struct builtincmd *bp;
4102
4103 bp = bsearch(
4104 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4105 pstrcmp
4106 );
4107 return bp;
4108}
4109
4110
4111
4112/*
4113 * Called when a cd is done. Marks all commands so the next time they
4114 * are executed they will be rehashed.
4115 */
4116
4117static void
4118hashcd(void)
4119{
4120 struct tblentry **pp;
4121 struct tblentry *cmdp;
4122
4123 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4124 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4125 if (cmdp->cmdtype == CMDNORMAL || (
4126 cmdp->cmdtype == CMDBUILTIN &&
4127 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4128 builtinloc > 0
4129 ))
4130 cmdp->rehash = 1;
4131 }
4132 }
4133}
4134
4135
4136
4137/*
4138 * Fix command hash table when PATH changed.
4139 * Called before PATH is changed. The argument is the new value of PATH;
4140 * pathval() still returns the old value at this point.
4141 * Called with interrupts off.
4142 */
4143
4144static void
4145changepath(const char *newval)
4146{
4147 const char *old, *new;
4148 int idx;
4149 int firstchange;
4150 int idx_bltin;
4151
4152 old = pathval();
4153 new = newval;
4154 firstchange = 9999; /* assume no change */
4155 idx = 0;
4156 idx_bltin = -1;
4157 for (;;) {
4158 if (*old != *new) {
4159 firstchange = idx;
4160 if ((*old == '\0' && *new == ':')
4161 || (*old == ':' && *new == '\0'))
4162 firstchange++;
4163 old = new; /* ignore subsequent differences */
4164 }
4165 if (*new == '\0')
4166 break;
4167 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4168 idx_bltin = idx;
4169 if (*new == ':') {
4170 idx++;
4171 }
4172 new++, old++;
4173 }
4174 if (builtinloc < 0 && idx_bltin >= 0)
4175 builtinloc = idx_bltin; /* zap builtins */
4176 if (builtinloc >= 0 && idx_bltin < 0)
4177 firstchange = 0;
4178 clearcmdentry(firstchange);
4179 builtinloc = idx_bltin;
4180}
4181
4182
4183/*
4184 * Clear out command entries. The argument specifies the first entry in
4185 * PATH which has changed.
4186 */
4187
4188static void
4189clearcmdentry(int firstchange)
4190{
4191 struct tblentry **tblp;
4192 struct tblentry **pp;
4193 struct tblentry *cmdp;
4194
4195 INTOFF;
4196 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4197 pp = tblp;
4198 while ((cmdp = *pp) != NULL) {
4199 if ((cmdp->cmdtype == CMDNORMAL &&
4200 cmdp->param.index >= firstchange)
4201 || (cmdp->cmdtype == CMDBUILTIN &&
4202 builtinloc >= firstchange)) {
4203 *pp = cmdp->next;
4204 ckfree(cmdp);
4205 } else {
4206 pp = &cmdp->next;
4207 }
4208 }
4209 }
4210 INTON;
4211}
4212
4213
4214
4215/*
4216 * Locate a command in the command hash table. If "add" is nonzero,
4217 * add the command to the table if it is not already present. The
4218 * variable "lastcmdentry" is set to point to the address of the link
4219 * pointing to the entry, so that delete_cmd_entry can delete the
4220 * entry.
4221 *
4222 * Interrupts must be off if called with add != 0.
4223 */
4224
4225static struct tblentry **lastcmdentry;
4226
4227
4228static struct tblentry *
4229cmdlookup(const char *name, int add)
4230{
4231 unsigned int hashval;
4232 const char *p;
4233 struct tblentry *cmdp;
4234 struct tblentry **pp;
4235
4236 p = name;
4237 hashval = (unsigned char)*p << 4;
4238 while (*p)
4239 hashval += (unsigned char)*p++;
4240 hashval &= 0x7FFF;
4241 pp = &cmdtable[hashval % CMDTABLESIZE];
4242 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4243 if (equal(cmdp->cmdname, name))
4244 break;
4245 pp = &cmdp->next;
4246 }
4247 if (add && cmdp == NULL) {
4248 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4249 + strlen(name) + 1);
4250 cmdp->next = NULL;
4251 cmdp->cmdtype = CMDUNKNOWN;
4252 strcpy(cmdp->cmdname, name);
4253 }
4254 lastcmdentry = pp;
4255 return cmdp;
4256}
4257
4258/*
4259 * Delete the command entry returned on the last lookup.
4260 */
4261
4262static void
4263delete_cmd_entry(void)
4264{
4265 struct tblentry *cmdp;
4266
4267 INTOFF;
4268 cmdp = *lastcmdentry;
4269 *lastcmdentry = cmdp->next;
4270 if (cmdp->cmdtype == CMDFUNCTION)
4271 freefunc(cmdp->param.func);
4272 ckfree(cmdp);
4273 INTON;
4274}
4275
4276
4277/*
4278 * Add a new command entry, replacing any existing command entry for
4279 * the same name - except special builtins.
4280 */
4281
4282static void addcmdentry(char *name, struct cmdentry *entry)
4283{
4284 struct tblentry *cmdp;
4285
4286 cmdp = cmdlookup(name, 1);
4287 if (cmdp->cmdtype == CMDFUNCTION) {
4288 freefunc(cmdp->param.func);
4289 }
4290 cmdp->cmdtype = entry->cmdtype;
4291 cmdp->param = entry->u;
4292 cmdp->rehash = 0;
4293}
4294
4295/*
4296 * Make a copy of a parse tree.
4297 */
4298
4299static struct funcnode * copyfunc(union node *n)
4300{
4301 struct funcnode *f;
4302 size_t blocksize;
4303
4304 funcblocksize = offsetof(struct funcnode, n);
4305 funcstringsize = 0;
4306 calcsize(n);
4307 blocksize = funcblocksize;
4308 f = ckmalloc(blocksize + funcstringsize);
4309 funcblock = (char *) f + offsetof(struct funcnode, n);
4310 funcstring = (char *) f + blocksize;
4311 copynode(n);
4312 f->count = 0;
4313 return f;
4314}
4315
4316/*
4317 * Define a shell function.
4318 */
4319
4320static void
4321defun(char *name, union node *func)
4322{
4323 struct cmdentry entry;
4324
4325 INTOFF;
4326 entry.cmdtype = CMDFUNCTION;
4327 entry.u.func = copyfunc(func);
4328 addcmdentry(name, &entry);
4329 INTON;
4330}
4331
4332
4333/*
4334 * Delete a function if it exists.
4335 */
4336
4337static void
4338unsetfunc(const char *name)
4339{
4340 struct tblentry *cmdp;
4341
4342 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4343 cmdp->cmdtype == CMDFUNCTION)
4344 delete_cmd_entry();
4345}
4346
4347/*
4348 * Locate and print what a word is...
4349 */
4350
4351
4352#ifdef CONFIG_ASH_CMDCMD
4353static int
4354describe_command(char *command, int describe_command_verbose)
4355#else
4356#define describe_command_verbose 1
4357static int
4358describe_command(char *command)
4359#endif
4360{
4361 struct cmdentry entry;
4362 struct tblentry *cmdp;
4363#ifdef CONFIG_ASH_ALIAS
4364 const struct alias *ap;
4365#endif
4366 const char *path = pathval();
4367
4368 if (describe_command_verbose) {
4369 out1str(command);
4370 }
4371
4372 /* First look at the keywords */
4373 if (findkwd(command)) {
4374 out1str(describe_command_verbose ? " is a shell keyword" : command);
4375 goto out;
4376 }
4377
4378#ifdef CONFIG_ASH_ALIAS
4379 /* Then look at the aliases */
4380 if ((ap = lookupalias(command, 0)) != NULL) {
4381 if (describe_command_verbose) {
4382 out1fmt(" is an alias for %s", ap->val);
4383 } else {
4384 out1str("alias ");
4385 printalias(ap);
4386 return 0;
4387 }
4388 goto out;
4389 }
4390#endif
4391 /* Then check if it is a tracked alias */
4392 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4393 entry.cmdtype = cmdp->cmdtype;
4394 entry.u = cmdp->param;
4395 } else {
4396 /* Finally use brute force */
4397 find_command(command, &entry, DO_ABS, path);
4398 }
4399
4400 switch (entry.cmdtype) {
4401 case CMDNORMAL: {
4402 int j = entry.u.index;
4403 char *p;
4404 if (j == -1) {
4405 p = command;
4406 } else {
4407 do {
4408 p = padvance(&path, command);
4409 stunalloc(p);
4410 } while (--j >= 0);
4411 }
4412 if (describe_command_verbose) {
4413 out1fmt(" is%s %s",
4414 (cmdp ? " a tracked alias for" : nullstr), p
4415 );
4416 } else {
4417 out1str(p);
4418 }
4419 break;
4420 }
4421
4422 case CMDFUNCTION:
4423 if (describe_command_verbose) {
4424 out1str(" is a shell function");
4425 } else {
4426 out1str(command);
4427 }
4428 break;
4429
4430 case CMDBUILTIN:
4431 if (describe_command_verbose) {
4432 out1fmt(" is a %sshell builtin",
4433 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4434 "special " : nullstr
4435 );
4436 } else {
4437 out1str(command);
4438 }
4439 break;
4440
4441 default:
4442 if (describe_command_verbose) {
4443 out1str(": not found\n");
4444 }
4445 return 127;
4446 }
4447
4448out:
4449 outstr("\n", stdout);
4450 return 0;
4451}
4452
4453static int
4454typecmd(int argc, char **argv)
4455{
4456 int i;
4457 int err = 0;
4458
4459 for (i = 1; i < argc; i++) {
4460#ifdef CONFIG_ASH_CMDCMD
4461 err |= describe_command(argv[i], 1);
4462#else
4463 err |= describe_command(argv[i]);
4464#endif
4465 }
4466 return err;
4467}
4468
4469#ifdef CONFIG_ASH_CMDCMD
4470static int
4471commandcmd(int argc, char **argv)
4472{
4473 int c;
4474 enum {
4475 VERIFY_BRIEF = 1,
4476 VERIFY_VERBOSE = 2,
4477 } verify = 0;
4478
4479 while ((c = nextopt("pvV")) != '\0')
4480 if (c == 'V')
4481 verify |= VERIFY_VERBOSE;
4482 else if (c == 'v')
4483 verify |= VERIFY_BRIEF;
4484#if DEBUG
4485 else if (c != 'p')
4486 abort();
4487#endif
4488 if (verify)
4489 return describe_command(*argptr, verify - VERIFY_BRIEF);
4490
4491 return 0;
4492}
4493#endif
4494
4495/* expand.c */
4496
4497/*
4498 * Routines to expand arguments to commands. We have to deal with
4499 * backquotes, shell variables, and file metacharacters.
4500 */
4501
4502/*
4503 * _rmescape() flags
4504 */
4505#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4506#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4507#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4508#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4509#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4510
4511/*
4512 * Structure specifying which parts of the string should be searched
4513 * for IFS characters.
4514 */
4515
4516struct ifsregion {
4517 struct ifsregion *next; /* next region in list */
4518 int begoff; /* offset of start of region */
4519 int endoff; /* offset of end of region */
4520 int nulonly; /* search for nul bytes only */
4521};
4522
4523/* output of current string */
4524static char *expdest;
4525/* list of back quote expressions */
4526static struct nodelist *argbackq;
4527/* first struct in list of ifs regions */
4528static struct ifsregion ifsfirst;
4529/* last struct in list */
4530static struct ifsregion *ifslastp;
4531/* holds expanded arg list */
4532static struct arglist exparg;
4533
4534static void argstr(char *, int);
4535static char *exptilde(char *, char *, int);
4536static void expbackq(union node *, int, int);
4537static const char *subevalvar(char *, char *, int, int, int, int, int);
4538static char *evalvar(char *, int);
4539static void strtodest(const char *, int, int);
4540static void memtodest(const char *p, size_t len, int syntax, int quotes);
4541static ssize_t varvalue(char *, int, int);
4542static void recordregion(int, int, int);
4543static void removerecordregions(int);
4544static void ifsbreakup(char *, struct arglist *);
4545static void ifsfree(void);
4546static void expandmeta(struct strlist *, int);
4547static int patmatch(char *, const char *);
4548
4549static int cvtnum(arith_t);
4550static size_t esclen(const char *, const char *);
4551static char *scanleft(char *, char *, char *, char *, int, int);
4552static char *scanright(char *, char *, char *, char *, int, int);
4553static void varunset(const char *, const char *, const char *, int)
4554 ATTRIBUTE_NORETURN;
4555
4556
4557#define pmatch(a, b) !fnmatch((a), (b), 0)
4558/*
4559 * Prepare a pattern for a expmeta (internal glob(3)) call.
4560 *
4561 * Returns an stalloced string.
4562 */
4563
4564static char * preglob(const char *pattern, int quoted, int flag) {
4565 flag |= RMESCAPE_GLOB;
4566 if (quoted) {
4567 flag |= RMESCAPE_QUOTED;
4568 }
4569 return _rmescapes((char *)pattern, flag);
4570}
4571
4572
4573static size_t
4574esclen(const char *start, const char *p) {
4575 size_t esc = 0;
4576
4577 while (p > start && *--p == CTLESC) {
4578 esc++;
4579 }
4580 return esc;
4581}
4582
4583
4584/*
4585 * Expand shell variables and backquotes inside a here document.
4586 */
4587
4588static void expandhere(union node *arg, int fd)
4589{
4590 herefd = fd;
4591 expandarg(arg, (struct arglist *)NULL, 0);
4592 full_write(fd, stackblock(), expdest - (char *)stackblock());
4593}
4594
4595
4596/*
4597 * Perform variable substitution and command substitution on an argument,
4598 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4599 * perform splitting and file name expansion. When arglist is NULL, perform
4600 * here document expansion.
4601 */
4602
4603void
4604expandarg(union node *arg, struct arglist *arglist, int flag)
4605{
4606 struct strlist *sp;
4607 char *p;
4608
4609 argbackq = arg->narg.backquote;
4610 STARTSTACKSTR(expdest);
4611 ifsfirst.next = NULL;
4612 ifslastp = NULL;
4613 argstr(arg->narg.text, flag);
4614 p = _STPUTC('\0', expdest);
4615 expdest = p - 1;
4616 if (arglist == NULL) {
4617 return; /* here document expanded */
4618 }
4619 p = grabstackstr(p);
4620 exparg.lastp = &exparg.list;
4621 /*
4622 * TODO - EXP_REDIR
4623 */
4624 if (flag & EXP_FULL) {
4625 ifsbreakup(p, &exparg);
4626 *exparg.lastp = NULL;
4627 exparg.lastp = &exparg.list;
4628 expandmeta(exparg.list, flag);
4629 } else {
4630 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4631 rmescapes(p);
4632 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4633 sp->text = p;
4634 *exparg.lastp = sp;
4635 exparg.lastp = &sp->next;
4636 }
4637 if (ifsfirst.next)
4638 ifsfree();
4639 *exparg.lastp = NULL;
4640 if (exparg.list) {
4641 *arglist->lastp = exparg.list;
4642 arglist->lastp = exparg.lastp;
4643 }
4644}
4645
4646
4647/*
4648 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4649 * characters to allow for further processing. Otherwise treat
4650 * $@ like $* since no splitting will be performed.
4651 */
4652
4653static void
4654argstr(char *p, int flag)
4655{
4656 static const char spclchars[] = {
4657 '=',
4658 ':',
4659 CTLQUOTEMARK,
4660 CTLENDVAR,
4661 CTLESC,
4662 CTLVAR,
4663 CTLBACKQ,
4664 CTLBACKQ | CTLQUOTE,
4665#ifdef CONFIG_ASH_MATH_SUPPORT
4666 CTLENDARI,
4667#endif
4668 0
4669 };
4670 const char *reject = spclchars;
4671 int c;
4672 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4673 int breakall = flag & EXP_WORD;
4674 int inquotes;
4675 size_t length;
4676 int startloc;
4677
4678 if (!(flag & EXP_VARTILDE)) {
4679 reject += 2;
4680 } else if (flag & EXP_VARTILDE2) {
4681 reject++;
4682 }
4683 inquotes = 0;
4684 length = 0;
4685 if (flag & EXP_TILDE) {
4686 char *q;
4687
4688 flag &= ~EXP_TILDE;
4689tilde:
4690 q = p;
4691 if (*q == CTLESC && (flag & EXP_QWORD))
4692 q++;
4693 if (*q == '~')
4694 p = exptilde(p, q, flag);
4695 }
4696start:
4697 startloc = expdest - (char *)stackblock();
4698 for (;;) {
4699 length += strcspn(p + length, reject);
4700 c = p[length];
4701 if (c && (!(c & 0x80)
4702#ifdef CONFIG_ASH_MATH_SUPPORT
4703 || c == CTLENDARI
4704#endif
4705 )) {
4706 /* c == '=' || c == ':' || c == CTLENDARI */
4707 length++;
4708 }
4709 if (length > 0) {
4710 int newloc;
4711 expdest = stnputs(p, length, expdest);
4712 newloc = expdest - (char *)stackblock();
4713 if (breakall && !inquotes && newloc > startloc) {
4714 recordregion(startloc, newloc, 0);
4715 }
4716 startloc = newloc;
4717 }
4718 p += length + 1;
4719 length = 0;
4720
4721 switch (c) {
4722 case '\0':
4723 goto breakloop;
4724 case '=':
4725 if (flag & EXP_VARTILDE2) {
4726 p--;
4727 continue;
4728 }
4729 flag |= EXP_VARTILDE2;
4730 reject++;
4731 /* fall through */
4732 case ':':
4733 /*
4734 * sort of a hack - expand tildes in variable
4735 * assignments (after the first '=' and after ':'s).
4736 */
4737 if (*--p == '~') {
4738 goto tilde;
4739 }
4740 continue;
4741 }
4742
4743 switch (c) {
4744 case CTLENDVAR: /* ??? */
4745 goto breakloop;
4746 case CTLQUOTEMARK:
4747 /* "$@" syntax adherence hack */
4748 if (
4749 !inquotes &&
4750 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4751 (p[4] == CTLQUOTEMARK || (
4752 p[4] == CTLENDVAR &&
4753 p[5] == CTLQUOTEMARK
4754 ))
4755 ) {
4756 p = evalvar(p + 1, flag) + 1;
4757 goto start;
4758 }
4759 inquotes = !inquotes;
4760addquote:
4761 if (quotes) {
4762 p--;
4763 length++;
4764 startloc++;
4765 }
4766 break;
4767 case CTLESC:
4768 startloc++;
4769 length++;
4770 goto addquote;
4771 case CTLVAR:
4772 p = evalvar(p, flag);
4773 goto start;
4774 case CTLBACKQ:
4775 c = 0;
4776 case CTLBACKQ|CTLQUOTE:
4777 expbackq(argbackq->n, c, quotes);
4778 argbackq = argbackq->next;
4779 goto start;
4780#ifdef CONFIG_ASH_MATH_SUPPORT
4781 case CTLENDARI:
4782 p--;
4783 expari(quotes);
4784 goto start;
4785#endif
4786 }
4787 }
4788breakloop:
4789 ;
4790}
4791
4792static char *
4793exptilde(char *startp, char *p, int flag)
4794{
4795 char c;
4796 char *name;
4797 struct passwd *pw;
4798 const char *home;
4799 int quotes = flag & (EXP_FULL | EXP_CASE);
4800 int startloc;
4801
4802 name = p + 1;
4803
4804 while ((c = *++p) != '\0') {
4805 switch(c) {
4806 case CTLESC:
4807 return startp;
4808 case CTLQUOTEMARK:
4809 return startp;
4810 case ':':
4811 if (flag & EXP_VARTILDE)
4812 goto done;
4813 break;
4814 case '/':
4815 case CTLENDVAR:
4816 goto done;
4817 }
4818 }
4819done:
4820 *p = '\0';
4821 if (*name == '\0') {
4822 home = lookupvar(homestr);
4823 } else {
4824 if ((pw = getpwnam(name)) == NULL)
4825 goto lose;
4826 home = pw->pw_dir;
4827 }
4828 if (!home || !*home)
4829 goto lose;
4830 *p = c;
4831 startloc = expdest - (char *)stackblock();
4832 strtodest(home, SQSYNTAX, quotes);
4833 recordregion(startloc, expdest - (char *)stackblock(), 0);
4834 return p;
4835lose:
4836 *p = c;
4837 return startp;
4838}
4839
4840
4841static void
4842removerecordregions(int endoff)
4843{
4844 if (ifslastp == NULL)
4845 return;
4846
4847 if (ifsfirst.endoff > endoff) {
4848 while (ifsfirst.next != NULL) {
4849 struct ifsregion *ifsp;
4850 INTOFF;
4851 ifsp = ifsfirst.next->next;
4852 ckfree(ifsfirst.next);
4853 ifsfirst.next = ifsp;
4854 INTON;
4855 }
4856 if (ifsfirst.begoff > endoff)
4857 ifslastp = NULL;
4858 else {
4859 ifslastp = &ifsfirst;
4860 ifsfirst.endoff = endoff;
4861 }
4862 return;
4863 }
4864
4865 ifslastp = &ifsfirst;
4866 while (ifslastp->next && ifslastp->next->begoff < endoff)
4867 ifslastp=ifslastp->next;
4868 while (ifslastp->next != NULL) {
4869 struct ifsregion *ifsp;
4870 INTOFF;
4871 ifsp = ifslastp->next->next;
4872 ckfree(ifslastp->next);
4873 ifslastp->next = ifsp;
4874 INTON;
4875 }
4876 if (ifslastp->endoff > endoff)
4877 ifslastp->endoff = endoff;
4878}
4879
4880
4881#ifdef CONFIG_ASH_MATH_SUPPORT
4882/*
4883 * Expand arithmetic expression. Backup to start of expression,
4884 * evaluate, place result in (backed up) result, adjust string position.
4885 */
4886void
4887expari(int quotes)
4888{
4889 char *p, *start;
4890 int begoff;
4891 int flag;
4892 int len;
4893
4894 /* ifsfree(); */
4895
4896 /*
4897 * This routine is slightly over-complicated for
4898 * efficiency. Next we scan backwards looking for the
4899 * start of arithmetic.
4900 */
4901 start = stackblock();
4902 p = expdest - 1;
4903 *p = '\0';
4904 p--;
4905 do {
4906 int esc;
4907
4908 while (*p != CTLARI) {
4909 p--;
4910#if DEBUG
4911 if (p < start) {
4912 sh_error("missing CTLARI (shouldn't happen)");
4913 }
4914#endif
4915 }
4916
4917 esc = esclen(start, p);
4918 if (!(esc % 2)) {
4919 break;
4920 }
4921
4922 p -= esc + 1;
4923 } while (1);
4924
4925 begoff = p - start;
4926
4927 removerecordregions(begoff);
4928
4929 flag = p[1];
4930
4931 expdest = p;
4932
4933 if (quotes)
4934 rmescapes(p + 2);
4935
4936 len = cvtnum(dash_arith(p + 2));
4937
4938 if (flag != '"')
4939 recordregion(begoff, begoff + len, 0);
4940}
4941#endif
4942
4943/*
4944 * Expand stuff in backwards quotes.
4945 */
4946
4947static void
4948expbackq(union node *cmd, int quoted, int quotes)
4949{
4950 struct backcmd in;
4951 int i;
4952 char buf[128];
4953 char *p;
4954 char *dest;
4955 int startloc;
4956 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4957 struct stackmark smark;
4958
4959 INTOFF;
4960 setstackmark(&smark);
4961 dest = expdest;
4962 startloc = dest - (char *)stackblock();
4963 grabstackstr(dest);
4964 evalbackcmd(cmd, (struct backcmd *) &in);
4965 popstackmark(&smark);
4966
4967 p = in.buf;
4968 i = in.nleft;
4969 if (i == 0)
4970 goto read;
4971 for (;;) {
4972 memtodest(p, i, syntax, quotes);
4973read:
4974 if (in.fd < 0)
4975 break;
4976 i = safe_read(in.fd, buf, sizeof buf);
4977 TRACE(("expbackq: read returns %d\n", i));
4978 if (i <= 0)
4979 break;
4980 p = buf;
4981 }
4982
4983 if (in.buf)
4984 ckfree(in.buf);
4985 if (in.fd >= 0) {
4986 close(in.fd);
4987 back_exitstatus = waitforjob(in.jp);
4988 }
4989 INTON;
4990
4991 /* Eat all trailing newlines */
4992 dest = expdest;
4993 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4994 STUNPUTC(dest);
4995 expdest = dest;
4996
4997 if (quoted == 0)
4998 recordregion(startloc, dest - (char *)stackblock(), 0);
4999 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5000 (dest - (char *)stackblock()) - startloc,
5001 (dest - (char *)stackblock()) - startloc,
5002 stackblock() + startloc));
5003}
5004
5005
5006static char *
5007scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5008 int zero)
5009{
5010 char *loc;
5011 char *loc2;
5012 char c;
5013
5014 loc = startp;
5015 loc2 = rmesc;
5016 do {
5017 int match;
5018 const char *s = loc2;
5019 c = *loc2;
5020 if (zero) {
5021 *loc2 = '\0';
5022 s = rmesc;
5023 }
5024 match = pmatch(str, s);
5025 *loc2 = c;
5026 if (match)
5027 return loc;
5028 if (quotes && *loc == CTLESC)
5029 loc++;
5030 loc++;
5031 loc2++;
5032 } while (c);
5033 return 0;
5034}
5035
5036
5037static char *
5038scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5039 int zero)
5040{
5041 int esc = 0;
5042 char *loc;
5043 char *loc2;
5044
5045 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5046 int match;
5047 char c = *loc2;
5048 const char *s = loc2;
5049 if (zero) {
5050 *loc2 = '\0';
5051 s = rmesc;
5052 }
5053 match = pmatch(str, s);
5054 *loc2 = c;
5055 if (match)
5056 return loc;
5057 loc--;
5058 if (quotes) {
5059 if (--esc < 0) {
5060 esc = esclen(startp, loc);
5061 }
5062 if (esc % 2) {
5063 esc--;
5064 loc--;
5065 }
5066 }
5067 }
5068 return 0;
5069}
5070
5071static const char *
5072subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5073{
5074 char *startp;
5075 char *loc;
5076 int saveherefd = herefd;
5077 struct nodelist *saveargbackq = argbackq;
5078 int amount;
5079 char *rmesc, *rmescend;
5080 int zero;
5081 char *(*scan)(char *, char *, char *, char *, int , int);
5082
5083 herefd = -1;
5084 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5085 STPUTC('\0', expdest);
5086 herefd = saveherefd;
5087 argbackq = saveargbackq;
5088 startp = stackblock() + startloc;
5089
5090 switch (subtype) {
5091 case VSASSIGN:
5092 setvar(str, startp, 0);
5093 amount = startp - expdest;
5094 STADJUST(amount, expdest);
5095 return startp;
5096
5097 case VSQUESTION:
5098 varunset(p, str, startp, varflags);
5099 /* NOTREACHED */
5100 }
5101
5102 subtype -= VSTRIMRIGHT;
5103#if DEBUG
5104 if (subtype < 0 || subtype > 3)
5105 abort();
5106#endif
5107
5108 rmesc = startp;
5109 rmescend = stackblock() + strloc;
5110 if (quotes) {
5111 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5112 if (rmesc != startp) {
5113 rmescend = expdest;
5114 startp = stackblock() + startloc;
5115 }
5116 }
5117 rmescend--;
5118 str = stackblock() + strloc;
5119 preglob(str, varflags & VSQUOTE, 0);
5120
5121 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5122 zero = subtype >> 1;
5123 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5124 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5125
5126 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5127 if (loc) {
5128 if (zero) {
5129 memmove(startp, loc, str - loc);
5130 loc = startp + (str - loc) - 1;
5131 }
5132 *loc = '\0';
5133 amount = loc - expdest;
5134 STADJUST(amount, expdest);
5135 }
5136 return loc;
5137}
5138
5139
5140/*
5141 * Expand a variable, and return a pointer to the next character in the
5142 * input string.
5143 */
5144static char *
5145evalvar(char *p, int flag)
5146{
5147 int subtype;
5148 int varflags;
5149 char *var;
5150 int patloc;
5151 int c;
5152 int startloc;
5153 ssize_t varlen;
5154 int easy;
5155 int quotes;
5156 int quoted;
5157
5158 quotes = flag & (EXP_FULL | EXP_CASE);
5159 varflags = *p++;
5160 subtype = varflags & VSTYPE;
5161 quoted = varflags & VSQUOTE;
5162 var = p;
5163 easy = (!quoted || (*var == '@' && shellparam.nparam));
5164 startloc = expdest - (char *)stackblock();
5165 p = strchr(p, '=') + 1;
5166
5167again:
5168 varlen = varvalue(var, varflags, flag);
5169 if (varflags & VSNUL)
5170 varlen--;
5171
5172 if (subtype == VSPLUS) {
5173 varlen = -1 - varlen;
5174 goto vsplus;
5175 }
5176
5177 if (subtype == VSMINUS) {
5178vsplus:
5179 if (varlen < 0) {
5180 argstr(
5181 p, flag | EXP_TILDE |
5182 (quoted ? EXP_QWORD : EXP_WORD)
5183 );
5184 goto end;
5185 }
5186 if (easy)
5187 goto record;
5188 goto end;
5189 }
5190
5191 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5192 if (varlen < 0) {
5193 if (subevalvar(p, var, 0, subtype, startloc,
5194 varflags, 0)) {
5195 varflags &= ~VSNUL;
5196 /*
5197 * Remove any recorded regions beyond
5198 * start of variable
5199 */
5200 removerecordregions(startloc);
5201 goto again;
5202 }
5203 goto end;
5204 }
5205 if (easy)
5206 goto record;
5207 goto end;
5208 }
5209
5210 if (varlen < 0 && uflag)
5211 varunset(p, var, 0, 0);
5212
5213 if (subtype == VSLENGTH) {
5214 cvtnum(varlen > 0 ? varlen : 0);
5215 goto record;
5216 }
5217
5218 if (subtype == VSNORMAL) {
5219 if (!easy)
5220 goto end;
5221record:
5222 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5223 goto end;
5224 }
5225
5226#if DEBUG
5227 switch (subtype) {
5228 case VSTRIMLEFT:
5229 case VSTRIMLEFTMAX:
5230 case VSTRIMRIGHT:
5231 case VSTRIMRIGHTMAX:
5232 break;
5233 default:
5234 abort();
5235 }
5236#endif
5237
5238 if (varlen >= 0) {
5239 /*
5240 * Terminate the string and start recording the pattern
5241 * right after it
5242 */
5243 STPUTC('\0', expdest);
5244 patloc = expdest - (char *)stackblock();
5245 if (subevalvar(p, NULL, patloc, subtype,
5246 startloc, varflags, quotes) == 0) {
5247 int amount = expdest - (
5248 (char *)stackblock() + patloc - 1
5249 );
5250 STADJUST(-amount, expdest);
5251 }
5252 /* Remove any recorded regions beyond start of variable */
5253 removerecordregions(startloc);
5254 goto record;
5255 }
5256
5257end:
5258 if (subtype != VSNORMAL) { /* skip to end of alternative */
5259 int nesting = 1;
5260 for (;;) {
5261 if ((c = *p++) == CTLESC)
5262 p++;
5263 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5264 if (varlen >= 0)
5265 argbackq = argbackq->next;
5266 } else if (c == CTLVAR) {
5267 if ((*p++ & VSTYPE) != VSNORMAL)
5268 nesting++;
5269 } else if (c == CTLENDVAR) {
5270 if (--nesting == 0)
5271 break;
5272 }
5273 }
5274 }
5275 return p;
5276}
5277
5278
5279/*
5280 * Put a string on the stack.
5281 */
5282
5283static void
5284memtodest(const char *p, size_t len, int syntax, int quotes) {
5285 char *q = expdest;
5286
5287 q = makestrspace(len * 2, q);
5288
5289 while (len--) {
5290 int c = SC2INT(*p++);
5291 if (!c)
5292 continue;
5293 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5294 USTPUTC(CTLESC, q);
5295 USTPUTC(c, q);
5296 }
5297
5298 expdest = q;
5299}
5300
5301
5302static void
5303strtodest(const char *p, int syntax, int quotes)
5304{
5305 memtodest(p, strlen(p), syntax, quotes);
5306}
5307
5308
5309/*
5310 * Add the value of a specialized variable to the stack string.
5311 */
5312
5313static ssize_t
5314varvalue(char *name, int varflags, int flags)
5315{
5316 int num;
5317 char *p;
5318 int i;
5319 int sep = 0;
5320 int sepq = 0;
5321 ssize_t len = 0;
5322 char **ap;
5323 int syntax;
5324 int quoted = varflags & VSQUOTE;
5325 int subtype = varflags & VSTYPE;
5326 int quotes = flags & (EXP_FULL | EXP_CASE);
5327
5328 if (quoted && (flags & EXP_FULL))
5329 sep = 1 << CHAR_BIT;
5330
5331 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5332 switch (*name) {
5333 case '$':
5334 num = rootpid;
5335 goto numvar;
5336 case '?':
5337 num = exitstatus;
5338 goto numvar;
5339 case '#':
5340 num = shellparam.nparam;
5341 goto numvar;
5342 case '!':
5343 num = backgndpid;
5344 if (num == 0)
5345 return -1;
5346numvar:
5347 len = cvtnum(num);
5348 break;
5349 case '-':
5350 p = makestrspace(NOPTS, expdest);
5351 for (i = NOPTS - 1; i >= 0; i--) {
5352 if (optlist[i]) {
5353 USTPUTC(optletters(i), p);
5354 len++;
5355 }
5356 }
5357 expdest = p;
5358 break;
5359 case '@':
5360 if (sep)
5361 goto param;
5362 /* fall through */
5363 case '*':
5364 sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
5365 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5366 sepq = 1;
5367param:
5368 if (!(ap = shellparam.p))
5369 return -1;
5370 while ((p = *ap++)) {
5371 size_t partlen;
5372
5373 partlen = strlen(p);
5374 len += partlen;
5375
5376 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5377 memtodest(p, partlen, syntax, quotes);
5378
5379 if (*ap && sep) {
5380 char *q;
5381
5382 len++;
5383 if (subtype == VSPLUS || subtype == VSLENGTH) {
5384 continue;
5385 }
5386 q = expdest;
5387 if (sepq)
5388 STPUTC(CTLESC, q);
5389 STPUTC(sep, q);
5390 expdest = q;
5391 }
5392 }
5393 return len;
5394 case '0':
5395 case '1':
5396 case '2':
5397 case '3':
5398 case '4':
5399 case '5':
5400 case '6':
5401 case '7':
5402 case '8':
5403 case '9':
5404 num = atoi(name);
5405 if (num < 0 || num > shellparam.nparam)
5406 return -1;
5407 p = num ? shellparam.p[num - 1] : arg0;
5408 goto value;
5409 default:
5410 p = lookupvar(name);
5411value:
5412 if (!p)
5413 return -1;
5414
5415 len = strlen(p);
5416 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5417 memtodest(p, len, syntax, quotes);
5418 return len;
5419 }
5420
5421 if (subtype == VSPLUS || subtype == VSLENGTH)
5422 STADJUST(-len, expdest);
5423 return len;
5424}
5425
5426
5427/*
5428 * Record the fact that we have to scan this region of the
5429 * string for IFS characters.
5430 */
5431
5432static void
5433recordregion(int start, int end, int nulonly)
5434{
5435 struct ifsregion *ifsp;
5436
5437 if (ifslastp == NULL) {
5438 ifsp = &ifsfirst;
5439 } else {
5440 INTOFF;
5441 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5442 ifsp->next = NULL;
5443 ifslastp->next = ifsp;
5444 INTON;
5445 }
5446 ifslastp = ifsp;
5447 ifslastp->begoff = start;
5448 ifslastp->endoff = end;
5449 ifslastp->nulonly = nulonly;
5450}
5451
5452
5453/*
5454 * Break the argument string into pieces based upon IFS and add the
5455 * strings to the argument list. The regions of the string to be
5456 * searched for IFS characters have been stored by recordregion.
5457 */
5458static void
5459ifsbreakup(char *string, struct arglist *arglist)
5460{
5461 struct ifsregion *ifsp;
5462 struct strlist *sp;
5463 char *start;
5464 char *p;
5465 char *q;
5466 const char *ifs, *realifs;
5467 int ifsspc;
5468 int nulonly;
5469
5470
5471 start = string;
5472 if (ifslastp != NULL) {
5473 ifsspc = 0;
5474 nulonly = 0;
5475 realifs = ifsset() ? ifsval() : defifs;
5476 ifsp = &ifsfirst;
5477 do {
5478 p = string + ifsp->begoff;
5479 nulonly = ifsp->nulonly;
5480 ifs = nulonly ? nullstr : realifs;
5481 ifsspc = 0;
5482 while (p < string + ifsp->endoff) {
5483 q = p;
5484 if (*p == CTLESC)
5485 p++;
5486 if (strchr(ifs, *p)) {
5487 if (!nulonly)
5488 ifsspc = (strchr(defifs, *p) != NULL);
5489 /* Ignore IFS whitespace at start */
5490 if (q == start && ifsspc) {
5491 p++;
5492 start = p;
5493 continue;
5494 }
5495 *q = '\0';
5496 sp = (struct strlist *)stalloc(sizeof *sp);
5497 sp->text = start;
5498 *arglist->lastp = sp;
5499 arglist->lastp = &sp->next;
5500 p++;
5501 if (!nulonly) {
5502 for (;;) {
5503 if (p >= string + ifsp->endoff) {
5504 break;
5505 }
5506 q = p;
5507 if (*p == CTLESC)
5508 p++;
5509 if (strchr(ifs, *p) == NULL ) {
5510 p = q;
5511 break;
5512 } else if (strchr(defifs, *p) == NULL) {
5513 if (ifsspc) {
5514 p++;
5515 ifsspc = 0;
5516 } else {
5517 p = q;
5518 break;
5519 }
5520 } else
5521 p++;
5522 }
5523 }
5524 start = p;
5525 } else
5526 p++;
5527 }
5528 } while ((ifsp = ifsp->next) != NULL);
5529 if (nulonly)
5530 goto add;
5531 }
5532
5533 if (!*start)
5534 return;
5535
5536add:
5537 sp = (struct strlist *)stalloc(sizeof *sp);
5538 sp->text = start;
5539 *arglist->lastp = sp;
5540 arglist->lastp = &sp->next;
5541}
5542
5543static void
5544ifsfree(void)
5545{
5546 struct ifsregion *p;
5547
5548 INTOFF;
5549 p = ifsfirst.next;
5550 do {
5551 struct ifsregion *ifsp;
5552 ifsp = p->next;
5553 ckfree(p);
5554 p = ifsp;
5555 } while (p);
5556 ifslastp = NULL;
5557 ifsfirst.next = NULL;
5558 INTON;
5559}
5560
5561static void expmeta(char *, char *);
5562static struct strlist *expsort(struct strlist *);
5563static struct strlist *msort(struct strlist *, int);
5564
5565static char *expdir;
5566
5567
5568static void
5569expandmeta(struct strlist *str, int flag)
5570{
5571 static const char metachars[] = {
5572 '*', '?', '[', 0
5573 };
5574 /* TODO - EXP_REDIR */
5575
5576 while (str) {
5577 struct strlist **savelastp;
5578 struct strlist *sp;
5579 char *p;
5580
5581 if (fflag)
5582 goto nometa;
5583 if (!strpbrk(str->text, metachars))
5584 goto nometa;
5585 savelastp = exparg.lastp;
5586
5587 INTOFF;
5588 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5589 {
5590 int i = strlen(str->text);
5591 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5592 }
5593
5594 expmeta(expdir, p);
5595 ckfree(expdir);
5596 if (p != str->text)
5597 ckfree(p);
5598 INTON;
5599 if (exparg.lastp == savelastp) {
5600 /*
5601 * no matches
5602 */
5603nometa:
5604 *exparg.lastp = str;
5605 rmescapes(str->text);
5606 exparg.lastp = &str->next;
5607 } else {
5608 *exparg.lastp = NULL;
5609 *savelastp = sp = expsort(*savelastp);
5610 while (sp->next != NULL)
5611 sp = sp->next;
5612 exparg.lastp = &sp->next;
5613 }
5614 str = str->next;
5615 }
5616}
5617
5618/*
5619 * Add a file name to the list.
5620 */
5621
5622static void
5623addfname(const char *name)
5624{
5625 struct strlist *sp;
5626
5627 sp = (struct strlist *)stalloc(sizeof *sp);
5628 sp->text = sstrdup(name);
5629 *exparg.lastp = sp;
5630 exparg.lastp = &sp->next;
5631}
5632
5633
5634/*
5635 * Do metacharacter (i.e. *, ?, [...]) expansion.
5636 */
5637
5638static void
5639expmeta(char *enddir, char *name)
5640{
5641 char *p;
5642 const char *cp;
5643 char *start;
5644 char *endname;
5645 int metaflag;
5646 struct stat statb;
5647 DIR *dirp;
5648 struct dirent *dp;
5649 int atend;
5650 int matchdot;
5651
5652 metaflag = 0;
5653 start = name;
5654 for (p = name; *p; p++) {
5655 if (*p == '*' || *p == '?')
5656 metaflag = 1;
5657 else if (*p == '[') {
5658 char *q = p + 1;
5659 if (*q == '!')
5660 q++;
5661 for (;;) {
5662 if (*q == '\\')
5663 q++;
5664 if (*q == '/' || *q == '\0')
5665 break;
5666 if (*++q == ']') {
5667 metaflag = 1;
5668 break;
5669 }
5670 }
5671 } else if (*p == '\\')
5672 p++;
5673 else if (*p == '/') {
5674 if (metaflag)
5675 goto out;
5676 start = p + 1;
5677 }
5678 }
5679out:
5680 if (metaflag == 0) { /* we've reached the end of the file name */
5681 if (enddir != expdir)
5682 metaflag++;
5683 p = name;
5684 do {
5685 if (*p == '\\')
5686 p++;
5687 *enddir++ = *p;
5688 } while (*p++);
5689 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5690 addfname(expdir);
5691 return;
5692 }
5693 endname = p;
5694 if (name < start) {
5695 p = name;
5696 do {
5697 if (*p == '\\')
5698 p++;
5699 *enddir++ = *p++;
5700 } while (p < start);
5701 }
5702 if (enddir == expdir) {
5703 cp = ".";
5704 } else if (enddir == expdir + 1 && *expdir == '/') {
5705 cp = "/";
5706 } else {
5707 cp = expdir;
5708 enddir[-1] = '\0';
5709 }
5710 if ((dirp = opendir(cp)) == NULL)
5711 return;
5712 if (enddir != expdir)
5713 enddir[-1] = '/';
5714 if (*endname == 0) {
5715 atend = 1;
5716 } else {
5717 atend = 0;
5718 *endname++ = '\0';
5719 }
5720 matchdot = 0;
5721 p = start;
5722 if (*p == '\\')
5723 p++;
5724 if (*p == '.')
5725 matchdot++;
5726 while (! intpending && (dp = readdir(dirp)) != NULL) {
5727 if (dp->d_name[0] == '.' && ! matchdot)
5728 continue;
5729 if (pmatch(start, dp->d_name)) {
5730 if (atend) {
5731 scopy(dp->d_name, enddir);
5732 addfname(expdir);
5733 } else {
5734 for (p = enddir, cp = dp->d_name;
5735 (*p++ = *cp++) != '\0';)
5736 continue;
5737 p[-1] = '/';
5738 expmeta(p, endname);
5739 }
5740 }
5741 }
5742 closedir(dirp);
5743 if (! atend)
5744 endname[-1] = '/';
5745}
5746
5747/*
5748 * Sort the results of file name expansion. It calculates the number of
5749 * strings to sort and then calls msort (short for merge sort) to do the
5750 * work.
5751 */
5752
5753static struct strlist *
5754expsort(struct strlist *str)
5755{
5756 int len;
5757 struct strlist *sp;
5758
5759 len = 0;
5760 for (sp = str ; sp ; sp = sp->next)
5761 len++;
5762 return msort(str, len);
5763}
5764
5765
5766static struct strlist *
5767msort(struct strlist *list, int len)
5768{
5769 struct strlist *p, *q = NULL;
5770 struct strlist **lpp;
5771 int half;
5772 int n;
5773
5774 if (len <= 1)
5775 return list;
5776 half = len >> 1;
5777 p = list;
5778 for (n = half ; --n >= 0 ; ) {
5779 q = p;
5780 p = p->next;
5781 }
5782 q->next = NULL; /* terminate first half of list */
5783 q = msort(list, half); /* sort first half of list */
5784 p = msort(p, len - half); /* sort second half */
5785 lpp = &list;
5786 for (;;) {
5787#ifdef CONFIG_LOCALE_SUPPORT
5788 if (strcoll(p->text, q->text) < 0)
5789#else
5790 if (strcmp(p->text, q->text) < 0)
5791#endif
5792 {
5793 *lpp = p;
5794 lpp = &p->next;
5795 if ((p = *lpp) == NULL) {
5796 *lpp = q;
5797 break;
5798 }
5799 } else {
5800 *lpp = q;
5801 lpp = &q->next;
5802 if ((q = *lpp) == NULL) {
5803 *lpp = p;
5804 break;
5805 }
5806 }
5807 }
5808 return list;
5809}
5810
5811
5812/*
5813 * Returns true if the pattern matches the string.
5814 */
5815
5816static int patmatch(char *pattern, const char *string)
5817{
5818 return pmatch(preglob(pattern, 0, 0), string);
5819}
5820
5821
5822/*
5823 * Remove any CTLESC characters from a string.
5824 */
5825
5826static char *
5827_rmescapes(char *str, int flag)
5828{
5829 char *p, *q, *r;
5830 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5831 unsigned inquotes;
5832 int notescaped;
5833 int globbing;
5834
5835 p = strpbrk(str, qchars);
5836 if (!p) {
5837 return str;
5838 }
5839 q = p;
5840 r = str;
5841 if (flag & RMESCAPE_ALLOC) {
5842 size_t len = p - str;
5843 size_t fulllen = len + strlen(p) + 1;
5844
5845 if (flag & RMESCAPE_GROW) {
5846 r = makestrspace(fulllen, expdest);
5847 } else if (flag & RMESCAPE_HEAP) {
5848 r = ckmalloc(fulllen);
5849 } else {
5850 r = stalloc(fulllen);
5851 }
5852 q = r;
5853 if (len > 0) {
5854 q = mempcpy(q, str, len);
5855 }
5856 }
5857 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5858 globbing = flag & RMESCAPE_GLOB;
5859 notescaped = globbing;
5860 while (*p) {
5861 if (*p == CTLQUOTEMARK) {
5862 inquotes = ~inquotes;
5863 p++;
5864 notescaped = globbing;
5865 continue;
5866 }
5867 if (*p == '\\') {
5868 /* naked back slash */
5869 notescaped = 0;
5870 goto copy;
5871 }
5872 if (*p == CTLESC) {
5873 p++;
5874 if (notescaped && inquotes && *p != '/') {
5875 *q++ = '\\';
5876 }
5877 }
5878 notescaped = globbing;
5879copy:
5880 *q++ = *p++;
5881 }
5882 *q = '\0';
5883 if (flag & RMESCAPE_GROW) {
5884 expdest = r;
5885 STADJUST(q - r + 1, expdest);
5886 }
5887 return r;
5888}
5889
5890
5891/*
5892 * See if a pattern matches in a case statement.
5893 */
5894
5895int
5896casematch(union node *pattern, char *val)
5897{
5898 struct stackmark smark;
5899 int result;
5900
5901 setstackmark(&smark);
5902 argbackq = pattern->narg.backquote;
5903 STARTSTACKSTR(expdest);
5904 ifslastp = NULL;
5905 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5906 STACKSTRNUL(expdest);
5907 result = patmatch(stackblock(), val);
5908 popstackmark(&smark);
5909 return result;
5910}
5911
5912/*
5913 * Our own itoa().
5914 */
5915
5916static int
5917cvtnum(arith_t num)
5918{
5919 int len;
5920
5921 expdest = makestrspace(32, expdest);
5922#ifdef CONFIG_ASH_MATH_SUPPORT_64
5923 len = fmtstr(expdest, 32, "%lld", (long long) num);
5924#else
5925 len = fmtstr(expdest, 32, "%ld", num);
5926#endif
5927 STADJUST(len, expdest);
5928 return len;
5929}
5930
5931static void
5932varunset(const char *end, const char *var, const char *umsg, int varflags)
5933{
5934 const char *msg;
5935 const char *tail;
5936
5937 tail = nullstr;
5938 msg = "parameter not set";
5939 if (umsg) {
5940 if (*end == CTLENDVAR) {
5941 if (varflags & VSNUL)
5942 tail = " or null";
5943 } else
5944 msg = umsg;
5945 }
5946 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5947}
5948
5949
5950/* input.c */
5951
5952/*
5953 * This implements the input routines used by the parser.
5954 */
5955
5956#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5957
5958static void pushfile(void);
5959
5960/*
5961 * Read a character from the script, returning PEOF on end of file.
5962 * Nul characters in the input are silently discarded.
5963 */
5964
5965
5966#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
5967
5968#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5969#define pgetc_macro() pgetc()
5970static int
5971pgetc(void)
5972{
5973 return pgetc_as_macro();
5974}
5975#else
5976#define pgetc_macro() pgetc_as_macro()
5977static int
5978pgetc(void)
5979{
5980 return pgetc_macro();
5981}
5982#endif
5983
5984
5985/*
5986 * Same as pgetc(), but ignores PEOA.
5987 */
5988#ifdef CONFIG_ASH_ALIAS
5989static int pgetc2(void)
5990{
5991 int c;
5992
5993 do {
5994 c = pgetc_macro();
5995 } while (c == PEOA);
5996 return c;
5997}
5998#else
5999static int pgetc2(void)
6000{
6001 return pgetc_macro();
6002}
6003#endif
6004
6005/*
6006 * Read a line from the script.
6007 */
6008
6009static char * pfgets(char *line, int len)
6010{
6011 char *p = line;
6012 int nleft = len;
6013 int c;
6014
6015 while (--nleft > 0) {
6016 c = pgetc2();
6017 if (c == PEOF) {
6018 if (p == line)
6019 return NULL;
6020 break;
6021 }
6022 *p++ = c;
6023 if (c == '\n')
6024 break;
6025 }
6026 *p = '\0';
6027 return line;
6028}
6029
6030
6031
6032#ifdef CONFIG_FEATURE_COMMAND_EDITING
6033#ifdef CONFIG_ASH_EXPAND_PRMT
6034static char *cmdedit_prompt;
6035#else
6036static const char *cmdedit_prompt;
6037#endif
6038static void putprompt(const char *s)
6039{
6040#ifdef CONFIG_ASH_EXPAND_PRMT
6041 free(cmdedit_prompt);
6042 cmdedit_prompt = xstrdup(s);
6043#else
6044 cmdedit_prompt = s;
6045#endif
6046}
6047#else
6048static void putprompt(const char *s)
6049{
6050 out2str(s);
6051}
6052#endif
6053
6054static int preadfd(void)
6055{
6056 int nr;
6057 char *buf = parsefile->buf;
6058 parsenextc = buf;
6059
6060retry:
6061#ifdef CONFIG_FEATURE_COMMAND_EDITING
6062 if (!iflag || parsefile->fd)
6063 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6064 else {
6065#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
6066 cmdedit_path_lookup = pathval();
6067#endif
6068 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6069 if(nr == 0) {
6070 /* Ctrl+C presend */
6071 if(trap[SIGINT]) {
6072 buf[0] = '\n';
6073 buf[1] = 0;
6074 raise(SIGINT);
6075 return 1;
6076 }
6077 goto retry;
6078 }
6079 if(nr < 0 && errno == 0) {
6080 /* Ctrl+D presend */
6081 nr = 0;
6082 }
6083 }
6084#else
6085 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6086#endif
6087
6088 if (nr < 0) {
6089 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6090 int flags = fcntl(0, F_GETFL, 0);
6091 if (flags >= 0 && flags & O_NONBLOCK) {
6092 flags &=~ O_NONBLOCK;
6093 if (fcntl(0, F_SETFL, flags) >= 0) {
6094 out2str("sh: turning off NDELAY mode\n");
6095 goto retry;
6096 }
6097 }
6098 }
6099 }
6100 return nr;
6101}
6102
6103/*
6104 * Refill the input buffer and return the next input character:
6105 *
6106 * 1) If a string was pushed back on the input, pop it;
6107 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6108 * from a string so we can't refill the buffer, return EOF.
6109 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6110 * 4) Process input up to the next newline, deleting nul characters.
6111 */
6112
6113int
6114preadbuffer(void)
6115{
6116 char *q;
6117 int more;
6118 char savec;
6119
6120 while (parsefile->strpush) {
6121#ifdef CONFIG_ASH_ALIAS
6122 if (parsenleft == -1 && parsefile->strpush->ap &&
6123 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6124 return PEOA;
6125 }
6126#endif
6127 popstring();
6128 if (--parsenleft >= 0)
6129 return SC2INT(*parsenextc++);
6130 }
6131 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6132 return PEOF;
6133 flushall();
6134
6135 more = parselleft;
6136 if (more <= 0) {
6137again:
6138 if ((more = preadfd()) <= 0) {
6139 parselleft = parsenleft = EOF_NLEFT;
6140 return PEOF;
6141 }
6142 }
6143
6144 q = parsenextc;
6145
6146 /* delete nul characters */
6147 for (;;) {
6148 int c;
6149
6150 more--;
6151 c = *q;
6152
6153 if (!c)
6154 memmove(q, q + 1, more);
6155 else {
6156 q++;
6157 if (c == '\n') {
6158 parsenleft = q - parsenextc - 1;
6159 break;
6160 }
6161 }
6162
6163 if (more <= 0) {
6164 parsenleft = q - parsenextc - 1;
6165 if (parsenleft < 0)
6166 goto again;
6167 break;
6168 }
6169 }
6170 parselleft = more;
6171
6172 savec = *q;
6173 *q = '\0';
6174
6175 if (vflag) {
6176 out2str(parsenextc);
6177 }
6178
6179 *q = savec;
6180
6181 return SC2INT(*parsenextc++);
6182}
6183
6184/*
6185 * Undo the last call to pgetc. Only one character may be pushed back.
6186 * PEOF may be pushed back.
6187 */
6188
6189void
6190pungetc(void)
6191{
6192 parsenleft++;
6193 parsenextc--;
6194}
6195
6196/*
6197 * Push a string back onto the input at this current parsefile level.
6198 * We handle aliases this way.
6199 */
6200void
6201pushstring(char *s, void *ap)
6202{
6203 struct strpush *sp;
6204 size_t len;
6205
6206 len = strlen(s);
6207 INTOFF;
6208/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6209 if (parsefile->strpush) {
6210 sp = ckmalloc(sizeof (struct strpush));
6211 sp->prev = parsefile->strpush;
6212 parsefile->strpush = sp;
6213 } else
6214 sp = parsefile->strpush = &(parsefile->basestrpush);
6215 sp->prevstring = parsenextc;
6216 sp->prevnleft = parsenleft;
6217#ifdef CONFIG_ASH_ALIAS
6218 sp->ap = (struct alias *)ap;
6219 if (ap) {
6220 ((struct alias *)ap)->flag |= ALIASINUSE;
6221 sp->string = s;
6222 }
6223#endif
6224 parsenextc = s;
6225 parsenleft = len;
6226 INTON;
6227}
6228
6229void
6230popstring(void)
6231{
6232 struct strpush *sp = parsefile->strpush;
6233
6234 INTOFF;
6235#ifdef CONFIG_ASH_ALIAS
6236 if (sp->ap) {
6237 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6238 checkkwd |= CHKALIAS;
6239 }
6240 if (sp->string != sp->ap->val) {
6241 ckfree(sp->string);
6242 }
6243 sp->ap->flag &= ~ALIASINUSE;
6244 if (sp->ap->flag & ALIASDEAD) {
6245 unalias(sp->ap->name);
6246 }
6247 }
6248#endif
6249 parsenextc = sp->prevstring;
6250 parsenleft = sp->prevnleft;
6251/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6252 parsefile->strpush = sp->prev;
6253 if (sp != &(parsefile->basestrpush))
6254 ckfree(sp);
6255 INTON;
6256}
6257
6258/*
6259 * Set the input to take input from a file. If push is set, push the
6260 * old input onto the stack first.
6261 */
6262
6263static int
6264setinputfile(const char *fname, int flags)
6265{
6266 int fd;
6267 int fd2;
6268
6269 INTOFF;
6270 if ((fd = open(fname, O_RDONLY)) < 0) {
6271 if (flags & INPUT_NOFILE_OK)
6272 goto out;
6273 sh_error("Can't open %s", fname);
6274 }
6275 if (fd < 10) {
6276 fd2 = copyfd(fd, 10);
6277 close(fd);
6278 if (fd2 < 0)
6279 sh_error("Out of file descriptors");
6280 fd = fd2;
6281 }
6282 setinputfd(fd, flags & INPUT_PUSH_FILE);
6283out:
6284 INTON;
6285 return fd;
6286}
6287
6288
6289/*
6290 * Like setinputfile, but takes an open file descriptor. Call this with
6291 * interrupts off.
6292 */
6293
6294static void
6295setinputfd(int fd, int push)
6296{
6297 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6298 if (push) {
6299 pushfile();
6300 parsefile->buf = 0;
6301 }
6302 parsefile->fd = fd;
6303 if (parsefile->buf == NULL)
6304 parsefile->buf = ckmalloc(IBUFSIZ);
6305 parselleft = parsenleft = 0;
6306 plinno = 1;
6307}
6308
6309
6310/*
6311 * Like setinputfile, but takes input from a string.
6312 */
6313
6314static void
6315setinputstring(char *string)
6316{
6317 INTOFF;
6318 pushfile();
6319 parsenextc = string;
6320 parsenleft = strlen(string);
6321 parsefile->buf = NULL;
6322 plinno = 1;
6323 INTON;
6324}
6325
6326
6327/*
6328 * To handle the "." command, a stack of input files is used. Pushfile
6329 * adds a new entry to the stack and popfile restores the previous level.
6330 */
6331
6332static void
6333pushfile(void)
6334{
6335 struct parsefile *pf;
6336
6337 parsefile->nleft = parsenleft;
6338 parsefile->lleft = parselleft;
6339 parsefile->nextc = parsenextc;
6340 parsefile->linno = plinno;
6341 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6342 pf->prev = parsefile;
6343 pf->fd = -1;
6344 pf->strpush = NULL;
6345 pf->basestrpush.prev = NULL;
6346 parsefile = pf;
6347}
6348
6349
6350static void
6351popfile(void)
6352{
6353 struct parsefile *pf = parsefile;
6354
6355 INTOFF;
6356 if (pf->fd >= 0)
6357 close(pf->fd);
6358 if (pf->buf)
6359 ckfree(pf->buf);
6360 while (pf->strpush)
6361 popstring();
6362 parsefile = pf->prev;
6363 ckfree(pf);
6364 parsenleft = parsefile->nleft;
6365 parselleft = parsefile->lleft;
6366 parsenextc = parsefile->nextc;
6367 plinno = parsefile->linno;
6368 INTON;
6369}
6370
6371
6372/*
6373 * Return to top level.
6374 */
6375
6376static void
6377popallfiles(void)
6378{
6379 while (parsefile != &basepf)
6380 popfile();
6381}
6382
6383
6384/*
6385 * Close the file(s) that the shell is reading commands from. Called
6386 * after a fork is done.
6387 */
6388
6389static void
6390closescript(void)
6391{
6392 popallfiles();
6393 if (parsefile->fd > 0) {
6394 close(parsefile->fd);
6395 parsefile->fd = 0;
6396 }
6397}
6398
6399/* jobs.c */
6400
6401/* mode flags for set_curjob */
6402#define CUR_DELETE 2
6403#define CUR_RUNNING 1
6404#define CUR_STOPPED 0
6405
6406/* mode flags for dowait */
6407#define DOWAIT_NORMAL 0
6408#define DOWAIT_BLOCK 1
6409
6410/* array of jobs */
6411static struct job *jobtab;
6412/* size of array */
6413static unsigned njobs;
6414#if JOBS
6415/* pgrp of shell on invocation */
6416static int initialpgrp;
6417static int ttyfd = -1;
6418#endif
6419/* current job */
6420static struct job *curjob;
6421/* number of presumed living untracked jobs */
6422static int jobless;
6423
6424static void set_curjob(struct job *, unsigned);
6425#if JOBS
6426static int restartjob(struct job *, int);
6427static void xtcsetpgrp(int, pid_t);
6428static char *commandtext(union node *);
6429static void cmdlist(union node *, int);
6430static void cmdtxt(union node *);
6431static void cmdputs(const char *);
6432static void showpipe(struct job *, FILE *);
6433#endif
6434static int sprint_status(char *, int, int);
6435static void freejob(struct job *);
6436static struct job *getjob(const char *, int);
6437static struct job *growjobtab(void);
6438static void forkchild(struct job *, union node *, int);
6439static void forkparent(struct job *, union node *, int, pid_t);
6440static int dowait(int, struct job *);
6441static int getstatus(struct job *);
6442
6443static void
6444set_curjob(struct job *jp, unsigned mode)
6445{
6446 struct job *jp1;
6447 struct job **jpp, **curp;
6448
6449 /* first remove from list */
6450 jpp = curp = &curjob;
6451 do {
6452 jp1 = *jpp;
6453 if (jp1 == jp)
6454 break;
6455 jpp = &jp1->prev_job;
6456 } while (1);
6457 *jpp = jp1->prev_job;
6458
6459 /* Then re-insert in correct position */
6460 jpp = curp;
6461 switch (mode) {
6462 default:
6463#if DEBUG
6464 abort();
6465#endif
6466 case CUR_DELETE:
6467 /* job being deleted */
6468 break;
6469 case CUR_RUNNING:
6470 /* newly created job or backgrounded job,
6471 put after all stopped jobs. */
6472 do {
6473 jp1 = *jpp;
6474#if JOBS
6475 if (!jp1 || jp1->state != JOBSTOPPED)
6476#endif
6477 break;
6478 jpp = &jp1->prev_job;
6479 } while (1);
6480 /* FALLTHROUGH */
6481#if JOBS
6482 case CUR_STOPPED:
6483#endif
6484 /* newly stopped job - becomes curjob */
6485 jp->prev_job = *jpp;
6486 *jpp = jp;
6487 break;
6488 }
6489}
6490
6491#if JOBS
6492/*
6493 * Turn job control on and off.
6494 *
6495 * Note: This code assumes that the third arg to ioctl is a character
6496 * pointer, which is true on Berkeley systems but not System V. Since
6497 * System V doesn't have job control yet, this isn't a problem now.
6498 *
6499 * Called with interrupts off.
6500 */
6501
6502void
6503setjobctl(int on)
6504{
6505 int fd;
6506 int pgrp;
6507
6508 if (on == jobctl || rootshell == 0)
6509 return;
6510 if (on) {
6511 int ofd;
6512 ofd = fd = open(_PATH_TTY, O_RDWR);
6513 if (fd < 0) {
6514 fd += 3;
6515 while (!isatty(fd) && --fd >= 0)
6516 ;
6517 }
6518 fd = fcntl(fd, F_DUPFD, 10);
6519 close(ofd);
6520 if (fd < 0)
6521 goto out;
6522 fcntl(fd, F_SETFD, FD_CLOEXEC);
6523 do { /* while we are in the background */
6524 if ((pgrp = tcgetpgrp(fd)) < 0) {
6525out:
6526 sh_warnx("can't access tty; job control turned off");
6527 mflag = on = 0;
6528 goto close;
6529 }
6530 if (pgrp == getpgrp())
6531 break;
6532 killpg(0, SIGTTIN);
6533 } while (1);
6534 initialpgrp = pgrp;
6535
6536 setsignal(SIGTSTP);
6537 setsignal(SIGTTOU);
6538 setsignal(SIGTTIN);
6539 pgrp = rootpid;
6540 setpgid(0, pgrp);
6541 xtcsetpgrp(fd, pgrp);
6542 } else {
6543 /* turning job control off */
6544 fd = ttyfd;
6545 pgrp = initialpgrp;
6546 xtcsetpgrp(fd, pgrp);
6547 setpgid(0, pgrp);
6548 setsignal(SIGTSTP);
6549 setsignal(SIGTTOU);
6550 setsignal(SIGTTIN);
6551close:
6552 close(fd);
6553 fd = -1;
6554 }
6555 ttyfd = fd;
6556 jobctl = on;
6557}
6558
6559static int
6560killcmd(int argc, char **argv)
6561{
6562 int signo = -1;
6563 int list = 0;
6564 int i;
6565 pid_t pid;
6566 struct job *jp;
6567
6568 if (argc <= 1) {
6569usage:
6570 sh_error(
6571"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6572"kill -l [exitstatus]"
6573 );
6574 }
6575
6576 if (**++argv == '-') {
6577 signo = get_signum(*argv + 1);
6578 if (signo < 0) {
6579 int c;
6580
6581 while ((c = nextopt("ls:")) != '\0')
6582 switch (c) {
6583 default:
6584#if DEBUG
6585 abort();
6586#endif
6587 case 'l':
6588 list = 1;
6589 break;
6590 case 's':
6591 signo = get_signum(optionarg);
6592 if (signo < 0) {
6593 sh_error(
6594 "invalid signal number or name: %s",
6595 optionarg
6596 );
6597 }
6598 break;
6599 }
6600 argv = argptr;
6601 } else
6602 argv++;
6603 }
6604
6605 if (!list && signo < 0)
6606 signo = SIGTERM;
6607
6608 if ((signo < 0 || !*argv) ^ list) {
6609 goto usage;
6610 }
6611
6612 if (list) {
6613 const char *name;
6614
6615 if (!*argv) {
6616 for (i = 1; i < NSIG; i++) {
6617 name = get_signame(i);
6618 if (isdigit(*name))
6619 out1fmt(snlfmt, name);
6620 }
6621 return 0;
6622 }
6623 name = get_signame(signo);
6624 if (isdigit(*name))
6625 out1fmt(snlfmt, name);
6626 else
6627 sh_error("invalid signal number or exit status: %s", *argptr);
6628 return 0;
6629 }
6630
6631 i = 0;
6632 do {
6633 if (**argv == '%') {
6634 jp = getjob(*argv, 0);
6635 pid = -jp->ps[0].pid;
6636 } else {
6637 pid = **argv == '-' ?
6638 -number(*argv + 1) : number(*argv);
6639 }
6640 if (kill(pid, signo) != 0) {
6641 sh_warnx("(%d) - %m", pid);
6642 i = 1;
6643 }
6644 } while (*++argv);
6645
6646 return i;
6647}
6648#endif /* JOBS */
6649
6650#if defined(JOBS) || DEBUG
6651static int
6652jobno(const struct job *jp)
6653{
6654 return jp - jobtab + 1;
6655}
6656#endif
6657
6658#if JOBS
6659static int
6660fgcmd(int argc, char **argv)
6661{
6662 struct job *jp;
6663 FILE *out;
6664 int mode;
6665 int retval;
6666
6667 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6668 nextopt(nullstr);
6669 argv = argptr;
6670 out = stdout;
6671 do {
6672 jp = getjob(*argv, 1);
6673 if (mode == FORK_BG) {
6674 set_curjob(jp, CUR_RUNNING);
6675 fprintf(out, "[%d] ", jobno(jp));
6676 }
6677 outstr(jp->ps->cmd, out);
6678 showpipe(jp, out);
6679 retval = restartjob(jp, mode);
6680 } while (*argv && *++argv);
6681 return retval;
6682}
6683
6684static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6685
6686
6687static int
6688restartjob(struct job *jp, int mode)
6689{
6690 struct procstat *ps;
6691 int i;
6692 int status;
6693 pid_t pgid;
6694
6695 INTOFF;
6696 if (jp->state == JOBDONE)
6697 goto out;
6698 jp->state = JOBRUNNING;
6699 pgid = jp->ps->pid;
6700 if (mode == FORK_FG)
6701 xtcsetpgrp(ttyfd, pgid);
6702 killpg(pgid, SIGCONT);
6703 ps = jp->ps;
6704 i = jp->nprocs;
6705 do {
6706 if (WIFSTOPPED(ps->status)) {
6707 ps->status = -1;
6708 }
6709 } while (ps++, --i);
6710out:
6711 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6712 INTON;
6713 return status;
6714}
6715#endif
6716
6717static int
6718sprint_status(char *s, int status, int sigonly)
6719{
6720 int col;
6721 int st;
6722
6723 col = 0;
6724 if (!WIFEXITED(status)) {
6725#if JOBS
6726 if (WIFSTOPPED(status))
6727 st = WSTOPSIG(status);
6728 else
6729#endif
6730 st = WTERMSIG(status);
6731 if (sigonly) {
6732 if (st == SIGINT || st == SIGPIPE)
6733 goto out;
6734#if JOBS
6735 if (WIFSTOPPED(status))
6736 goto out;
6737#endif
6738 }
6739 st &= 0x7f;
6740 col = fmtstr(s, 32, strsignal(st));
6741 if (WCOREDUMP(status)) {
6742 col += fmtstr(s + col, 16, " (core dumped)");
6743 }
6744 } else if (!sigonly) {
6745 st = WEXITSTATUS(status);
6746 if (st)
6747 col = fmtstr(s, 16, "Done(%d)", st);
6748 else
6749 col = fmtstr(s, 16, "Done");
6750 }
6751
6752out:
6753 return col;
6754}
6755
6756#if JOBS
6757static void
6758showjob(FILE *out, struct job *jp, int mode)
6759{
6760 struct procstat *ps;
6761 struct procstat *psend;
6762 int col;
6763 int indent;
6764 char s[80];
6765
6766 ps = jp->ps;
6767
6768 if (mode & SHOW_PGID) {
6769 /* just output process (group) id of pipeline */
6770 fprintf(out, "%d\n", ps->pid);
6771 return;
6772 }
6773
6774 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6775 indent = col;
6776
6777 if (jp == curjob)
6778 s[col - 2] = '+';
6779 else if (curjob && jp == curjob->prev_job)
6780 s[col - 2] = '-';
6781
6782 if (mode & SHOW_PID)
6783 col += fmtstr(s + col, 16, "%d ", ps->pid);
6784
6785 psend = ps + jp->nprocs;
6786
6787 if (jp->state == JOBRUNNING) {
6788 scopy("Running", s + col);
6789 col += strlen("Running");
6790 } else {
6791 int status = psend[-1].status;
6792#if JOBS
6793 if (jp->state == JOBSTOPPED)
6794 status = jp->stopstatus;
6795#endif
6796 col += sprint_status(s + col, status, 0);
6797 }
6798
6799 goto start;
6800
6801 do {
6802 /* for each process */
6803 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6804
6805start:
6806 fprintf(out, "%s%*c%s",
6807 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6808 );
6809 if (!(mode & SHOW_PID)) {
6810 showpipe(jp, out);
6811 break;
6812 }
6813 if (++ps == psend) {
6814 outcslow('\n', out);
6815 break;
6816 }
6817 } while (1);
6818
6819 jp->changed = 0;
6820
6821 if (jp->state == JOBDONE) {
6822 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6823 freejob(jp);
6824 }
6825}
6826
6827
6828static int
6829jobscmd(int argc, char **argv)
6830{
6831 int mode, m;
6832 FILE *out;
6833
6834 mode = 0;
6835 while ((m = nextopt("lp")))
6836 if (m == 'l')
6837 mode = SHOW_PID;
6838 else
6839 mode = SHOW_PGID;
6840
6841 out = stdout;
6842 argv = argptr;
6843 if (*argv)
6844 do
6845 showjob(out, getjob(*argv,0), mode);
6846 while (*++argv);
6847 else
6848 showjobs(out, mode);
6849
6850 return 0;
6851}
6852
6853
6854/*
6855 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6856 * statuses have changed since the last call to showjobs.
6857 */
6858
6859static void
6860showjobs(FILE *out, int mode)
6861{
6862 struct job *jp;
6863
6864 TRACE(("showjobs(%x) called\n", mode));
6865
6866 /* If not even one one job changed, there is nothing to do */
6867 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6868 continue;
6869
6870 for (jp = curjob; jp; jp = jp->prev_job) {
6871 if (!(mode & SHOW_CHANGED) || jp->changed)
6872 showjob(out, jp, mode);
6873 }
6874}
6875#endif /* JOBS */
6876
6877/*
6878 * Mark a job structure as unused.
6879 */
6880
6881static void
6882freejob(struct job *jp)
6883{
6884 struct procstat *ps;
6885 int i;
6886
6887 INTOFF;
6888 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6889 if (ps->cmd != nullstr)
6890 ckfree(ps->cmd);
6891 }
6892 if (jp->ps != &jp->ps0)
6893 ckfree(jp->ps);
6894 jp->used = 0;
6895 set_curjob(jp, CUR_DELETE);
6896 INTON;
6897}
6898
6899
6900static int
6901waitcmd(int argc, char **argv)
6902{
6903 struct job *job;
6904 int retval;
6905 struct job *jp;
6906
6907 EXSIGON();
6908
6909 nextopt(nullstr);
6910 retval = 0;
6911
6912 argv = argptr;
6913 if (!*argv) {
6914 /* wait for all jobs */
6915 for (;;) {
6916 jp = curjob;
6917 while (1) {
6918 if (!jp) {
6919 /* no running procs */
6920 goto out;
6921 }
6922 if (jp->state == JOBRUNNING)
6923 break;
6924 jp->waited = 1;
6925 jp = jp->prev_job;
6926 }
6927 dowait(DOWAIT_BLOCK, 0);
6928 }
6929 }
6930
6931 retval = 127;
6932 do {
6933 if (**argv != '%') {
6934 pid_t pid = number(*argv);
6935 job = curjob;
6936 goto start;
6937 do {
6938 if (job->ps[job->nprocs - 1].pid == pid)
6939 break;
6940 job = job->prev_job;
6941start:
6942 if (!job)
6943 goto repeat;
6944 } while (1);
6945 } else
6946 job = getjob(*argv, 0);
6947 /* loop until process terminated or stopped */
6948 while (job->state == JOBRUNNING)
6949 dowait(DOWAIT_BLOCK, 0);
6950 job->waited = 1;
6951 retval = getstatus(job);
6952repeat:
6953 ;
6954 } while (*++argv);
6955
6956out:
6957 return retval;
6958}
6959
6960
6961/*
6962 * Convert a job name to a job structure.
6963 */
6964
6965static struct job *
6966getjob(const char *name, int getctl)
6967{
6968 struct job *jp;
6969 struct job *found;
6970 const char *err_msg = "No such job: %s";
6971 unsigned num;
6972 int c;
6973 const char *p;
6974 char *(*match)(const char *, const char *);
6975
6976 jp = curjob;
6977 p = name;
6978 if (!p)
6979 goto currentjob;
6980
6981 if (*p != '%')
6982 goto err;
6983
6984 c = *++p;
6985 if (!c)
6986 goto currentjob;
6987
6988 if (!p[1]) {
6989 if (c == '+' || c == '%') {
6990currentjob:
6991 err_msg = "No current job";
6992 goto check;
6993 } else if (c == '-') {
6994 if (jp)
6995 jp = jp->prev_job;
6996 err_msg = "No previous job";
6997check:
6998 if (!jp)
6999 goto err;
7000 goto gotit;
7001 }
7002 }
7003
7004 if (is_number(p)) {
7005 num = atoi(p);
7006 if (num < njobs) {
7007 jp = jobtab + num - 1;
7008 if (jp->used)
7009 goto gotit;
7010 goto err;
7011 }
7012 }
7013
7014 match = prefix;
7015 if (*p == '?') {
7016 match = strstr;
7017 p++;
7018 }
7019
7020 found = 0;
7021 while (1) {
7022 if (!jp)
7023 goto err;
7024 if (match(jp->ps[0].cmd, p)) {
7025 if (found)
7026 goto err;
7027 found = jp;
7028 err_msg = "%s: ambiguous";
7029 }
7030 jp = jp->prev_job;
7031 }
7032
7033gotit:
7034#if JOBS
7035 err_msg = "job %s not created under job control";
7036 if (getctl && jp->jobctl == 0)
7037 goto err;
7038#endif
7039 return jp;
7040err:
7041 sh_error(err_msg, name);
7042}
7043
7044
7045/*
7046 * Return a new job structure.
7047 * Called with interrupts off.
7048 */
7049
7050static struct job *
7051makejob(union node *node, int nprocs)
7052{
7053 int i;
7054 struct job *jp;
7055
7056 for (i = njobs, jp = jobtab ; ; jp++) {
7057 if (--i < 0) {
7058 jp = growjobtab();
7059 break;
7060 }
7061 if (jp->used == 0)
7062 break;
7063 if (jp->state != JOBDONE || !jp->waited)
7064 continue;
7065#if JOBS
7066 if (jobctl)
7067 continue;
7068#endif
7069 freejob(jp);
7070 break;
7071 }
7072 memset(jp, 0, sizeof(*jp));
7073#if JOBS
7074 if (jobctl)
7075 jp->jobctl = 1;
7076#endif
7077 jp->prev_job = curjob;
7078 curjob = jp;
7079 jp->used = 1;
7080 jp->ps = &jp->ps0;
7081 if (nprocs > 1) {
7082 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7083 }
7084 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7085 jobno(jp)));
7086 return jp;
7087}
7088
7089static struct job *
7090growjobtab(void)
7091{
7092 size_t len;
7093 ptrdiff_t offset;
7094 struct job *jp, *jq;
7095
7096 len = njobs * sizeof(*jp);
7097 jq = jobtab;
7098 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7099
7100 offset = (char *)jp - (char *)jq;
7101 if (offset) {
7102 /* Relocate pointers */
7103 size_t l = len;
7104
7105 jq = (struct job *)((char *)jq + l);
7106 while (l) {
7107 l -= sizeof(*jp);
7108 jq--;
7109#define joff(p) ((struct job *)((char *)(p) + l))
7110#define jmove(p) (p) = (void *)((char *)(p) + offset)
7111 if (xlikely(joff(jp)->ps == &jq->ps0))
7112 jmove(joff(jp)->ps);
7113 if (joff(jp)->prev_job)
7114 jmove(joff(jp)->prev_job);
7115 }
7116 if (curjob)
7117 jmove(curjob);
7118#undef joff
7119#undef jmove
7120 }
7121
7122 njobs += 4;
7123 jobtab = jp;
7124 jp = (struct job *)((char *)jp + len);
7125 jq = jp + 3;
7126 do {
7127 jq->used = 0;
7128 } while (--jq >= jp);
7129 return jp;
7130}
7131
7132
7133/*
7134 * Fork off a subshell. If we are doing job control, give the subshell its
7135 * own process group. Jp is a job structure that the job is to be added to.
7136 * N is the command that will be evaluated by the child. Both jp and n may
7137 * be NULL. The mode parameter can be one of the following:
7138 * FORK_FG - Fork off a foreground process.
7139 * FORK_BG - Fork off a background process.
7140 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7141 * process group even if job control is on.
7142 *
7143 * When job control is turned off, background processes have their standard
7144 * input redirected to /dev/null (except for the second and later processes
7145 * in a pipeline).
7146 *
7147 * Called with interrupts off.
7148 */
7149
7150static void forkchild(struct job *jp, union node *n, int mode)
7151{
7152 int oldlvl;
7153
7154 TRACE(("Child shell %d\n", getpid()));
7155 oldlvl = shlvl;
7156 shlvl++;
7157
7158 closescript();
7159 clear_traps();
7160#if JOBS
7161 /* do job control only in root shell */
7162 jobctl = 0;
7163 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
7164 pid_t pgrp;
7165
7166 if (jp->nprocs == 0)
7167 pgrp = getpid();
7168 else
7169 pgrp = jp->ps[0].pid;
7170 /* This can fail because we are doing it in the parent also */
7171 (void)setpgid(0, pgrp);
7172 if (mode == FORK_FG)
7173 xtcsetpgrp(ttyfd, pgrp);
7174 setsignal(SIGTSTP);
7175 setsignal(SIGTTOU);
7176 } else
7177#endif
7178 if (mode == FORK_BG) {
7179 ignoresig(SIGINT);
7180 ignoresig(SIGQUIT);
7181 if (jp->nprocs == 0) {
7182 close(0);
7183 if (open(bb_dev_null, O_RDONLY) != 0)
7184 sh_error("Can't open %s", bb_dev_null);
7185 }
7186 }
7187 if (!oldlvl && iflag) {
7188 setsignal(SIGINT);
7189 setsignal(SIGQUIT);
7190 setsignal(SIGTERM);
7191 }
7192 for (jp = curjob; jp; jp = jp->prev_job)
7193 freejob(jp);
7194 jobless = 0;
7195}
7196
7197static void forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7198{
7199 TRACE(("In parent shell: child = %d\n", pid));
7200 if (!jp) {
7201 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7202 jobless++;
7203 return;
7204 }
7205#if JOBS
7206 if (mode != FORK_NOJOB && jp->jobctl) {
7207 int pgrp;
7208
7209 if (jp->nprocs == 0)
7210 pgrp = pid;
7211 else
7212 pgrp = jp->ps[0].pid;
7213 /* This can fail because we are doing it in the child also */
7214 (void)setpgid(pid, pgrp);
7215 }
7216#endif
7217 if (mode == FORK_BG) {
7218 backgndpid = pid; /* set $! */
7219 set_curjob(jp, CUR_RUNNING);
7220 }
7221 if (jp) {
7222 struct procstat *ps = &jp->ps[jp->nprocs++];
7223 ps->pid = pid;
7224 ps->status = -1;
7225 ps->cmd = nullstr;
7226#if JOBS
7227 if (jobctl && n)
7228 ps->cmd = commandtext(n);
7229#endif
7230 }
7231}
7232
7233static int
7234forkshell(struct job *jp, union node *n, int mode)
7235{
7236 int pid;
7237
7238 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7239 pid = fork();
7240 if (pid < 0) {
7241 TRACE(("Fork failed, errno=%d", errno));
7242 if (jp)
7243 freejob(jp);
7244 sh_error("Cannot fork");
7245 }
7246 if (pid == 0)
7247 forkchild(jp, n, mode);
7248 else
7249 forkparent(jp, n, mode, pid);
7250 return pid;
7251}
7252
7253/*
7254 * Wait for job to finish.
7255 *
7256 * Under job control we have the problem that while a child process is
7257 * running interrupts generated by the user are sent to the child but not
7258 * to the shell. This means that an infinite loop started by an inter-
7259 * active user may be hard to kill. With job control turned off, an
7260 * interactive user may place an interactive program inside a loop. If
7261 * the interactive program catches interrupts, the user doesn't want
7262 * these interrupts to also abort the loop. The approach we take here
7263 * is to have the shell ignore interrupt signals while waiting for a
7264 * foreground process to terminate, and then send itself an interrupt
7265 * signal if the child process was terminated by an interrupt signal.
7266 * Unfortunately, some programs want to do a bit of cleanup and then
7267 * exit on interrupt; unless these processes terminate themselves by
7268 * sending a signal to themselves (instead of calling exit) they will
7269 * confuse this approach.
7270 *
7271 * Called with interrupts off.
7272 */
7273
7274int
7275waitforjob(struct job *jp)
7276{
7277 int st;
7278
7279 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7280 while (jp->state == JOBRUNNING) {
7281 dowait(DOWAIT_BLOCK, jp);
7282 }
7283 st = getstatus(jp);
7284#if JOBS
7285 if (jp->jobctl) {
7286 xtcsetpgrp(ttyfd, rootpid);
7287 /*
7288 * This is truly gross.
7289 * If we're doing job control, then we did a TIOCSPGRP which
7290 * caused us (the shell) to no longer be in the controlling
7291 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7292 * intuit from the subprocess exit status whether a SIGINT
7293 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7294 */
7295 if (jp->sigint)
7296 raise(SIGINT);
7297 }
7298 if (jp->state == JOBDONE)
7299#endif
7300 freejob(jp);
7301 return st;
7302}
7303
7304
7305/*
7306 * Do a wait system call. If job control is compiled in, we accept
7307 * stopped processes. If block is zero, we return a value of zero
7308 * rather than blocking.
7309 *
7310 * System V doesn't have a non-blocking wait system call. It does
7311 * have a SIGCLD signal that is sent to a process when one of it's
7312 * children dies. The obvious way to use SIGCLD would be to install
7313 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7314 * was received, and have waitproc bump another counter when it got
7315 * the status of a process. Waitproc would then know that a wait
7316 * system call would not block if the two counters were different.
7317 * This approach doesn't work because if a process has children that
7318 * have not been waited for, System V will send it a SIGCLD when it
7319 * installs a signal handler for SIGCLD. What this means is that when
7320 * a child exits, the shell will be sent SIGCLD signals continuously
7321 * until is runs out of stack space, unless it does a wait call before
7322 * restoring the signal handler. The code below takes advantage of
7323 * this (mis)feature by installing a signal handler for SIGCLD and
7324 * then checking to see whether it was called. If there are any
7325 * children to be waited for, it will be.
7326 *
7327 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7328 * waits at all. In this case, the user will not be informed when
7329 * a background process until the next time she runs a real program
7330 * (as opposed to running a builtin command or just typing return),
7331 * and the jobs command may give out of date information.
7332 */
7333
7334static int waitproc(int block, int *status)
7335{
7336 int flags = 0;
7337
7338#if JOBS
7339 if (jobctl)
7340 flags |= WUNTRACED;
7341#endif
7342 if (block == 0)
7343 flags |= WNOHANG;
7344 return wait3(status, flags, (struct rusage *)NULL);
7345}
7346
7347/*
7348 * Wait for a process to terminate.
7349 */
7350
7351static int
7352dowait(int block, struct job *job)
7353{
7354 int pid;
7355 int status;
7356 struct job *jp;
7357 struct job *thisjob;
7358 int state;
7359
7360 TRACE(("dowait(%d) called\n", block));
7361 pid = waitproc(block, &status);
7362 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7363 if (pid <= 0)
7364 return pid;
7365 INTOFF;
7366 thisjob = NULL;
7367 for (jp = curjob; jp; jp = jp->prev_job) {
7368 struct procstat *sp;
7369 struct procstat *spend;
7370 if (jp->state == JOBDONE)
7371 continue;
7372 state = JOBDONE;
7373 spend = jp->ps + jp->nprocs;
7374 sp = jp->ps;
7375 do {
7376 if (sp->pid == pid) {
7377 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7378 sp->status = status;
7379 thisjob = jp;
7380 }
7381 if (sp->status == -1)
7382 state = JOBRUNNING;
7383#if JOBS
7384 if (state == JOBRUNNING)
7385 continue;
7386 if (WIFSTOPPED(sp->status)) {
7387 jp->stopstatus = sp->status;
7388 state = JOBSTOPPED;
7389 }
7390#endif
7391 } while (++sp < spend);
7392 if (thisjob)
7393 goto gotjob;
7394 }
7395#if JOBS
7396 if (!WIFSTOPPED(status))
7397#endif
7398
7399 jobless--;
7400 goto out;
7401
7402gotjob:
7403 if (state != JOBRUNNING) {
7404 thisjob->changed = 1;
7405
7406 if (thisjob->state != state) {
7407 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7408 thisjob->state = state;
7409#if JOBS
7410 if (state == JOBSTOPPED) {
7411 set_curjob(thisjob, CUR_STOPPED);
7412 }
7413#endif
7414 }
7415 }
7416
7417out:
7418 INTON;
7419
7420 if (thisjob && thisjob == job) {
7421 char s[48 + 1];
7422 int len;
7423
7424 len = sprint_status(s, status, 1);
7425 if (len) {
7426 s[len] = '\n';
7427 s[len + 1] = 0;
7428 out2str(s);
7429 }
7430 }
7431 return pid;
7432}
7433
7434
7435/*
7436 * return 1 if there are stopped jobs, otherwise 0
7437 */
7438
7439int
7440stoppedjobs(void)
7441{
7442 struct job *jp;
7443 int retval;
7444
7445 retval = 0;
7446 if (job_warning)
7447 goto out;
7448 jp = curjob;
7449 if (jp && jp->state == JOBSTOPPED) {
7450 out2str("You have stopped jobs.\n");
7451 job_warning = 2;
7452 retval++;
7453 }
7454
7455out:
7456 return retval;
7457}
7458
7459/*
7460 * Return a string identifying a command (to be printed by the
7461 * jobs command).
7462 */
7463
7464#if JOBS
7465static char *cmdnextc;
7466
7467static char *
7468commandtext(union node *n)
7469{
7470 char *name;
7471
7472 STARTSTACKSTR(cmdnextc);
7473 cmdtxt(n);
7474 name = stackblock();
7475 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7476 name, cmdnextc, cmdnextc));
7477 return savestr(name);
7478}
7479
7480static void
7481cmdtxt(union node *n)
7482{
7483 union node *np;
7484 struct nodelist *lp;
7485 const char *p;
7486 char s[2];
7487
7488 if (!n)
7489 return;
7490 switch (n->type) {
7491 default:
7492#if DEBUG
7493 abort();
7494#endif
7495 case NPIPE:
7496 lp = n->npipe.cmdlist;
7497 for (;;) {
7498 cmdtxt(lp->n);
7499 lp = lp->next;
7500 if (!lp)
7501 break;
7502 cmdputs(" | ");
7503 }
7504 break;
7505 case NSEMI:
7506 p = "; ";
7507 goto binop;
7508 case NAND:
7509 p = " && ";
7510 goto binop;
7511 case NOR:
7512 p = " || ";
7513binop:
7514 cmdtxt(n->nbinary.ch1);
7515 cmdputs(p);
7516 n = n->nbinary.ch2;
7517 goto donode;
7518 case NREDIR:
7519 case NBACKGND:
7520 n = n->nredir.n;
7521 goto donode;
7522 case NNOT:
7523 cmdputs("!");
7524 n = n->nnot.com;
7525donode:
7526 cmdtxt(n);
7527 break;
7528 case NIF:
7529 cmdputs("if ");
7530 cmdtxt(n->nif.test);
7531 cmdputs("; then ");
7532 n = n->nif.ifpart;
7533 if (n->nif.elsepart) {
7534 cmdtxt(n);
7535 cmdputs("; else ");
7536 n = n->nif.elsepart;
7537 }
7538 p = "; fi";
7539 goto dotail;
7540 case NSUBSHELL:
7541 cmdputs("(");
7542 n = n->nredir.n;
7543 p = ")";
7544 goto dotail;
7545 case NWHILE:
7546 p = "while ";
7547 goto until;
7548 case NUNTIL:
7549 p = "until ";
7550until:
7551 cmdputs(p);
7552 cmdtxt(n->nbinary.ch1);
7553 n = n->nbinary.ch2;
7554 p = "; done";
7555dodo:
7556 cmdputs("; do ");
7557dotail:
7558 cmdtxt(n);
7559 goto dotail2;
7560 case NFOR:
7561 cmdputs("for ");
7562 cmdputs(n->nfor.var);
7563 cmdputs(" in ");
7564 cmdlist(n->nfor.args, 1);
7565 n = n->nfor.body;
7566 p = "; done";
7567 goto dodo;
7568 case NDEFUN:
7569 cmdputs(n->narg.text);
7570 p = "() { ... }";
7571 goto dotail2;
7572 case NCMD:
7573 cmdlist(n->ncmd.args, 1);
7574 cmdlist(n->ncmd.redirect, 0);
7575 break;
7576 case NARG:
7577 p = n->narg.text;
7578dotail2:
7579 cmdputs(p);
7580 break;
7581 case NHERE:
7582 case NXHERE:
7583 p = "<<...";
7584 goto dotail2;
7585 case NCASE:
7586 cmdputs("case ");
7587 cmdputs(n->ncase.expr->narg.text);
7588 cmdputs(" in ");
7589 for (np = n->ncase.cases; np; np = np->nclist.next) {
7590 cmdtxt(np->nclist.pattern);
7591 cmdputs(") ");
7592 cmdtxt(np->nclist.body);
7593 cmdputs(";; ");
7594 }
7595 p = "esac";
7596 goto dotail2;
7597 case NTO:
7598 p = ">";
7599 goto redir;
7600 case NCLOBBER:
7601 p = ">|";
7602 goto redir;
7603 case NAPPEND:
7604 p = ">>";
7605 goto redir;
7606 case NTOFD:
7607 p = ">&";
7608 goto redir;
7609 case NFROM:
7610 p = "<";
7611 goto redir;
7612 case NFROMFD:
7613 p = "<&";
7614 goto redir;
7615 case NFROMTO:
7616 p = "<>";
7617redir:
7618 s[0] = n->nfile.fd + '0';
7619 s[1] = '\0';
7620 cmdputs(s);
7621 cmdputs(p);
7622 if (n->type == NTOFD || n->type == NFROMFD) {
7623 s[0] = n->ndup.dupfd + '0';
7624 p = s;
7625 goto dotail2;
7626 } else {
7627 n = n->nfile.fname;
7628 goto donode;
7629 }
7630 }
7631}
7632
7633static void
7634cmdlist(union node *np, int sep)
7635{
7636 for (; np; np = np->narg.next) {
7637 if (!sep)
7638 cmdputs(spcstr);
7639 cmdtxt(np);
7640 if (sep && np->narg.next)
7641 cmdputs(spcstr);
7642 }
7643}
7644
7645static void
7646cmdputs(const char *s)
7647{
7648 const char *p, *str;
7649 char c, cc[2] = " ";
7650 char *nextc;
7651 int subtype = 0;
7652 int quoted = 0;
7653 static const char vstype[VSTYPE + 1][4] = {
7654 "", "}", "-", "+", "?", "=",
7655 "%", "%%", "#", "##"
7656 };
7657 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7658 p = s;
7659 while ((c = *p++) != 0) {
7660 str = 0;
7661 switch (c) {
7662 case CTLESC:
7663 c = *p++;
7664 break;
7665 case CTLVAR:
7666 subtype = *p++;
7667 if ((subtype & VSTYPE) == VSLENGTH)
7668 str = "${#";
7669 else
7670 str = "${";
7671 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7672 quoted ^= 1;
7673 c = '"';
7674 } else
7675 goto dostr;
7676 break;
7677 case CTLENDVAR:
7678 str = "\"}" + !(quoted & 1);
7679 quoted >>= 1;
7680 subtype = 0;
7681 goto dostr;
7682 case CTLBACKQ:
7683 str = "$(...)";
7684 goto dostr;
7685 case CTLBACKQ+CTLQUOTE:
7686 str = "\"$(...)\"";
7687 goto dostr;
7688#ifdef CONFIG_ASH_MATH_SUPPORT
7689 case CTLARI:
7690 str = "$((";
7691 goto dostr;
7692 case CTLENDARI:
7693 str = "))";
7694 goto dostr;
7695#endif
7696 case CTLQUOTEMARK:
7697 quoted ^= 1;
7698 c = '"';
7699 break;
7700 case '=':
7701 if (subtype == 0)
7702 break;
7703 if ((subtype & VSTYPE) != VSNORMAL)
7704 quoted <<= 1;
7705 str = vstype[subtype & VSTYPE];
7706 if (subtype & VSNUL)
7707 c = ':';
7708 else
7709 goto checkstr;
7710 break;
7711 case '\'':
7712 case '\\':
7713 case '"':
7714 case '$':
7715 /* These can only happen inside quotes */
7716 cc[0] = c;
7717 str = cc;
7718 c = '\\';
7719 break;
7720 default:
7721 break;
7722 }
7723 USTPUTC(c, nextc);
7724checkstr:
7725 if (!str)
7726 continue;
7727dostr:
7728 while ((c = *str++)) {
7729 USTPUTC(c, nextc);
7730 }
7731 }
7732 if (quoted & 1) {
7733 USTPUTC('"', nextc);
7734 }
7735 *nextc = 0;
7736 cmdnextc = nextc;
7737}
7738
7739
7740static void
7741showpipe(struct job *jp, FILE *out)
7742{
7743 struct procstat *sp;
7744 struct procstat *spend;
7745
7746 spend = jp->ps + jp->nprocs;
7747 for (sp = jp->ps + 1; sp < spend; sp++)
7748 fprintf(out, " | %s", sp->cmd);
7749 outcslow('\n', out);
7750 flushall();
7751}
7752
7753static void
7754xtcsetpgrp(int fd, pid_t pgrp)
7755{
7756 if (tcsetpgrp(fd, pgrp))
7757 sh_error("Cannot set tty process group (%m)");
7758}
7759#endif /* JOBS */
7760
7761static int
7762getstatus(struct job *job) {
7763 int status;
7764 int retval;
7765
7766 status = job->ps[job->nprocs - 1].status;
7767 retval = WEXITSTATUS(status);
7768 if (!WIFEXITED(status)) {
7769#if JOBS
7770 retval = WSTOPSIG(status);
7771 if (!WIFSTOPPED(status))
7772#endif
7773 {
7774 /* XXX: limits number of signals */
7775 retval = WTERMSIG(status);
7776#if JOBS
7777 if (retval == SIGINT)
7778 job->sigint = 1;
7779#endif
7780 }
7781 retval += 128;
7782 }
7783 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7784 jobno(job), job->nprocs, status, retval));
7785 return retval;
7786}
7787
7788#ifdef CONFIG_ASH_MAIL
7789/* mail.c */
7790
7791/*
7792 * Routines to check for mail. (Perhaps make part of main.c?)
7793 */
7794
7795#define MAXMBOXES 10
7796
7797/* times of mailboxes */
7798static time_t mailtime[MAXMBOXES];
7799/* Set if MAIL or MAILPATH is changed. */
7800static int mail_var_path_changed;
7801
7802
7803
7804/*
7805 * Print appropriate message(s) if mail has arrived.
7806 * If mail_var_path_changed is set,
7807 * then the value of MAIL has mail_var_path_changed,
7808 * so we just update the values.
7809 */
7810
7811static void
7812chkmail(void)
7813{
7814 const char *mpath;
7815 char *p;
7816 char *q;
7817 time_t *mtp;
7818 struct stackmark smark;
7819 struct stat statb;
7820
7821 setstackmark(&smark);
7822 mpath = mpathset() ? mpathval() : mailval();
7823 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7824 p = padvance(&mpath, nullstr);
7825 if (p == NULL)
7826 break;
7827 if (*p == '\0')
7828 continue;
7829 for (q = p ; *q ; q++);
7830#if DEBUG
7831 if (q[-1] != '/')
7832 abort();
7833#endif
7834 q[-1] = '\0'; /* delete trailing '/' */
7835 if (stat(p, &statb) < 0) {
7836 *mtp = 0;
7837 continue;
7838 }
7839 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7840 fprintf(
7841 stderr, snlfmt,
7842 pathopt ? pathopt : "you have mail"
7843 );
7844 }
7845 *mtp = statb.st_mtime;
7846 }
7847 mail_var_path_changed = 0;
7848 popstackmark(&smark);
7849}
7850
7851
7852static void
7853changemail(const char *val)
7854{
7855 mail_var_path_changed++;
7856}
7857
7858#endif /* CONFIG_ASH_MAIL */
7859
7860/* main.c */
7861
7862
7863#if PROFILE
7864static short profile_buf[16384];
7865extern int etext();
7866#endif
7867
7868static int isloginsh;
7869
7870static void read_profile(const char *);
7871
7872/*
7873 * Main routine. We initialize things, parse the arguments, execute
7874 * profiles if we're a login shell, and then call cmdloop to execute
7875 * commands. The setjmp call sets up the location to jump to when an
7876 * exception occurs. When an exception occurs the variable "state"
7877 * is used to figure out how far we had gotten.
7878 */
7879
7880int
7881ash_main(int argc, char **argv)
7882{
7883 char *shinit;
7884 volatile int state;
7885 struct jmploc jmploc;
7886 struct stackmark smark;
7887
7888#ifdef __GLIBC__
7889 dash_errno = __errno_location();
7890#endif
7891
7892#if PROFILE
7893 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7894#endif
7895 state = 0;
7896 if (setjmp(jmploc.loc)) {
7897 int e;
7898 int s;
7899
7900 reset();
7901
7902 e = exception;
7903 if (e == EXERROR)
7904 exitstatus = 2;
7905 s = state;
7906 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
7907 exitshell();
7908
7909 if (e == EXINT) {
7910 outcslow('\n', stderr);
7911 }
7912 popstackmark(&smark);
7913 FORCEINTON; /* enable interrupts */
7914 if (s == 1)
7915 goto state1;
7916 else if (s == 2)
7917 goto state2;
7918 else if (s == 3)
7919 goto state3;
7920 else
7921 goto state4;
7922 }
7923 handler = &jmploc;
7924#if DEBUG
7925 opentrace();
7926 trputs("Shell args: "); trargs(argv);
7927#endif
7928 rootpid = getpid();
7929
7930#ifdef CONFIG_ASH_RANDOM_SUPPORT
7931 rseed = rootpid + ((time_t)time((time_t *)0));
7932#endif
7933 init();
7934 setstackmark(&smark);
7935 procargs(argc, argv);
7936#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7937 if ( iflag ) {
7938 const char *hp = lookupvar("HISTFILE");
7939
7940 if(hp == NULL ) {
7941 hp = lookupvar("HOME");
7942 if(hp != NULL) {
7943 char *defhp = concat_path_file(hp, ".ash_history");
7944 setvar("HISTFILE", defhp, 0);
7945 free(defhp);
7946 }
7947 }
7948 }
7949#endif
7950 if (argv[0] && argv[0][0] == '-')
7951 isloginsh = 1;
7952 if (isloginsh) {
7953 state = 1;
7954 read_profile("/etc/profile");
7955state1:
7956 state = 2;
7957 read_profile(".profile");
7958 }
7959state2:
7960 state = 3;
7961 if (
7962#ifndef linux
7963 getuid() == geteuid() && getgid() == getegid() &&
7964#endif
7965 iflag
7966 ) {
7967 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7968 read_profile(shinit);
7969 }
7970 }
7971state3:
7972 state = 4;
7973 if (minusc)
7974 evalstring(minusc, 0);
7975
7976 if (sflag || minusc == NULL) {
7977#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7978 if ( iflag ) {
7979 const char *hp = lookupvar("HISTFILE");
7980
7981 if(hp != NULL )
7982 load_history ( hp );
7983 }
7984#endif
7985state4: /* XXX ??? - why isn't this before the "if" statement */
7986 cmdloop(1);
7987 }
7988#if PROFILE
7989 monitor(0);
7990#endif
7991#ifdef GPROF
7992 {
7993 extern void _mcleanup(void);
7994 _mcleanup();
7995 }
7996#endif
7997 exitshell();
7998 /* NOTREACHED */
7999}
8000
8001
8002/*
8003 * Read and execute commands. "Top" is nonzero for the top level command
8004 * loop; it turns on prompting if the shell is interactive.
8005 */
8006
8007static int
8008cmdloop(int top)
8009{
8010 union node *n;
8011 struct stackmark smark;
8012 int inter;
8013 int numeof = 0;
8014
8015 TRACE(("cmdloop(%d) called\n", top));
8016 for (;;) {
8017 int skip;
8018
8019 setstackmark(&smark);
8020#if JOBS
8021 if (jobctl)
8022 showjobs(stderr, SHOW_CHANGED);
8023#endif
8024 inter = 0;
8025 if (iflag && top) {
8026 inter++;
8027#ifdef CONFIG_ASH_MAIL
8028 chkmail();
8029#endif
8030 }
8031 n = parsecmd(inter);
8032 /* showtree(n); DEBUG */
8033 if (n == NEOF) {
8034 if (!top || numeof >= 50)
8035 break;
8036 if (!stoppedjobs()) {
8037 if (!Iflag)
8038 break;
8039 out2str("\nUse \"exit\" to leave shell.\n");
8040 }
8041 numeof++;
8042 } else if (nflag == 0) {
8043 job_warning = (job_warning == 2) ? 1 : 0;
8044 numeof = 0;
8045 evaltree(n, 0);
8046 }
8047 popstackmark(&smark);
8048 skip = evalskip;
8049
8050 if (skip) {
8051 evalskip = 0;
8052 return skip & SKIPEVAL;
8053 }
8054 }
8055
8056 return 0;
8057}
8058
8059
8060/*
8061 * Read /etc/profile or .profile. Return on error.
8062 */
8063
8064static void
8065read_profile(const char *name)
8066{
8067 int skip;
8068
8069 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
8070 return;
8071
8072 skip = cmdloop(0);
8073 popfile();
8074
8075 if (skip)
8076 exitshell();
8077}
8078
8079
8080/*
8081 * Read a file containing shell functions.
8082 */
8083
8084static void
8085readcmdfile(char *name)
8086{
8087 setinputfile(name, INPUT_PUSH_FILE);
8088 cmdloop(0);
8089 popfile();
8090}
8091
8092
8093/*
8094 * Take commands from a file. To be compatible we should do a path
8095 * search for the file, which is necessary to find sub-commands.
8096 */
8097
8098static char * find_dot_file(char *name)
8099{
8100 char *fullname;
8101 const char *path = pathval();
8102 struct stat statb;
8103
8104 /* don't try this for absolute or relative paths */
8105 if (strchr(name, '/'))
8106 return name;
8107
8108 while ((fullname = padvance(&path, name)) != NULL) {
8109 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8110 /*
8111 * Don't bother freeing here, since it will
8112 * be freed by the caller.
8113 */
8114 return fullname;
8115 }
8116 stunalloc(fullname);
8117 }
8118
8119 /* not found in the PATH */
8120 sh_error(not_found_msg, name);
8121 /* NOTREACHED */
8122}
8123
8124static int dotcmd(int argc, char **argv)
8125{
8126 struct strlist *sp;
8127 volatile struct shparam saveparam;
8128 int status = 0;
8129
8130 for (sp = cmdenviron; sp; sp = sp->next)
8131 setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8132
8133 if (argc >= 2) { /* That's what SVR2 does */
8134 char *fullname;
8135
8136 fullname = find_dot_file(argv[1]);
8137
8138 if (argc > 2) {
8139 saveparam = shellparam;
8140 shellparam.malloc = 0;
8141 shellparam.nparam = argc - 2;
8142 shellparam.p = argv + 2;
8143 };
8144
8145 setinputfile(fullname, INPUT_PUSH_FILE);
8146 commandname = fullname;
8147 cmdloop(0);
8148 popfile();
8149
8150 if (argc > 2) {
8151 freeparam(&shellparam);
8152 shellparam = saveparam;
8153 };
8154 status = exitstatus;
8155 }
8156 return status;
8157}
8158
8159
8160static int
8161exitcmd(int argc, char **argv)
8162{
8163 if (stoppedjobs())
8164 return 0;
8165 if (argc > 1)
8166 exitstatus = number(argv[1]);
8167 exraise(EXEXIT);
8168 /* NOTREACHED */
8169}
8170
8171#ifdef CONFIG_ASH_BUILTIN_ECHO
8172static int
8173echocmd(int argc, char **argv)
8174{
8175 return bb_echo(argc, argv);
8176}
8177#endif
8178
8179#ifdef CONFIG_ASH_BUILTIN_TEST
8180static int
8181testcmd(int argc, char **argv)
8182{
8183 return bb_test(argc, argv);
8184}
8185#endif
8186
8187/* memalloc.c */
8188
8189/*
8190 * Same for malloc, realloc, but returns an error when out of space.
8191 */
8192
8193static pointer
8194ckrealloc(pointer p, size_t nbytes)
8195{
8196 p = realloc(p, nbytes);
8197 if (p == NULL)
8198 sh_error(bb_msg_memory_exhausted);
8199 return p;
8200}
8201
8202static pointer
8203ckmalloc(size_t nbytes)
8204{
8205 return ckrealloc(NULL, nbytes);
8206}
8207
8208/*
8209 * Make a copy of a string in safe storage.
8210 */
8211
8212static char *
8213savestr(const char *s)
8214{
8215 char *p = strdup(s);
8216 if (!p)
8217 sh_error(bb_msg_memory_exhausted);
8218 return p;
8219}
8220
8221
8222/*
8223 * Parse trees for commands are allocated in lifo order, so we use a stack
8224 * to make this more efficient, and also to avoid all sorts of exception
8225 * handling code to handle interrupts in the middle of a parse.
8226 *
8227 * The size 504 was chosen because the Ultrix malloc handles that size
8228 * well.
8229 */
8230
8231
8232static pointer
8233stalloc(size_t nbytes)
8234{
8235 char *p;
8236 size_t aligned;
8237
8238 aligned = SHELL_ALIGN(nbytes);
8239 if (aligned > stacknleft) {
8240 size_t len;
8241 size_t blocksize;
8242 struct stack_block *sp;
8243
8244 blocksize = aligned;
8245 if (blocksize < MINSIZE)
8246 blocksize = MINSIZE;
8247 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8248 if (len < blocksize)
8249 sh_error(bb_msg_memory_exhausted);
8250 INTOFF;
8251 sp = ckmalloc(len);
8252 sp->prev = stackp;
8253 stacknxt = sp->space;
8254 stacknleft = blocksize;
8255 sstrend = stacknxt + blocksize;
8256 stackp = sp;
8257 INTON;
8258 }
8259 p = stacknxt;
8260 stacknxt += aligned;
8261 stacknleft -= aligned;
8262 return p;
8263}
8264
8265
8266void
8267stunalloc(pointer p)
8268{
8269#if DEBUG
8270 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8271 write(2, "stunalloc\n", 10);
8272 abort();
8273 }
8274#endif
8275 stacknleft += stacknxt - (char *)p;
8276 stacknxt = p;
8277}
8278
8279
8280void
8281setstackmark(struct stackmark *mark)
8282{
8283 mark->stackp = stackp;
8284 mark->stacknxt = stacknxt;
8285 mark->stacknleft = stacknleft;
8286 mark->marknext = markp;
8287 markp = mark;
8288}
8289
8290
8291void
8292popstackmark(struct stackmark *mark)
8293{
8294 struct stack_block *sp;
8295
8296 INTOFF;
8297 markp = mark->marknext;
8298 while (stackp != mark->stackp) {
8299 sp = stackp;
8300 stackp = sp->prev;
8301 ckfree(sp);
8302 }
8303 stacknxt = mark->stacknxt;
8304 stacknleft = mark->stacknleft;
8305 sstrend = mark->stacknxt + mark->stacknleft;
8306 INTON;
8307}
8308
8309
8310/*
8311 * When the parser reads in a string, it wants to stick the string on the
8312 * stack and only adjust the stack pointer when it knows how big the
8313 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8314 * of space on top of the stack and stackblocklen returns the length of
8315 * this block. Growstackblock will grow this space by at least one byte,
8316 * possibly moving it (like realloc). Grabstackblock actually allocates the
8317 * part of the block that has been used.
8318 */
8319
8320void
8321growstackblock(void)
8322{
8323 size_t newlen;
8324
8325 newlen = stacknleft * 2;
8326 if (newlen < stacknleft)
8327 sh_error(bb_msg_memory_exhausted);
8328 if (newlen < 128)
8329 newlen += 128;
8330
8331 if (stacknxt == stackp->space && stackp != &stackbase) {
8332 struct stack_block *oldstackp;
8333 struct stackmark *xmark;
8334 struct stack_block *sp;
8335 struct stack_block *prevstackp;
8336 size_t grosslen;
8337
8338 INTOFF;
8339 oldstackp = stackp;
8340 sp = stackp;
8341 prevstackp = sp->prev;
8342 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8343 sp = ckrealloc((pointer)sp, grosslen);
8344 sp->prev = prevstackp;
8345 stackp = sp;
8346 stacknxt = sp->space;
8347 stacknleft = newlen;
8348 sstrend = sp->space + newlen;
8349
8350 /*
8351 * Stack marks pointing to the start of the old block
8352 * must be relocated to point to the new block
8353 */
8354 xmark = markp;
8355 while (xmark != NULL && xmark->stackp == oldstackp) {
8356 xmark->stackp = stackp;
8357 xmark->stacknxt = stacknxt;
8358 xmark->stacknleft = stacknleft;
8359 xmark = xmark->marknext;
8360 }
8361 INTON;
8362 } else {
8363 char *oldspace = stacknxt;
8364 int oldlen = stacknleft;
8365 char *p = stalloc(newlen);
8366
8367 /* free the space we just allocated */
8368 stacknxt = memcpy(p, oldspace, oldlen);
8369 stacknleft += newlen;
8370 }
8371}
8372
8373static void grabstackblock(size_t len)
8374{
8375 len = SHELL_ALIGN(len);
8376 stacknxt += len;
8377 stacknleft -= len;
8378}
8379
8380/*
8381 * The following routines are somewhat easier to use than the above.
8382 * The user declares a variable of type STACKSTR, which may be declared
8383 * to be a register. The macro STARTSTACKSTR initializes things. Then
8384 * the user uses the macro STPUTC to add characters to the string. In
8385 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8386 * grown as necessary. When the user is done, she can just leave the
8387 * string there and refer to it using stackblock(). Or she can allocate
8388 * the space for it using grabstackstr(). If it is necessary to allow
8389 * someone else to use the stack temporarily and then continue to grow
8390 * the string, the user should use grabstack to allocate the space, and
8391 * then call ungrabstr(p) to return to the previous mode of operation.
8392 *
8393 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8394 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8395 * is space for at least one character.
8396 */
8397
8398void *
8399growstackstr(void)
8400{
8401 size_t len = stackblocksize();
8402 if (herefd >= 0 && len >= 1024) {
8403 full_write(herefd, stackblock(), len);
8404 return stackblock();
8405 }
8406 growstackblock();
8407 return stackblock() + len;
8408}
8409
8410/*
8411 * Called from CHECKSTRSPACE.
8412 */
8413
8414char *
8415makestrspace(size_t newlen, char *p)
8416{
8417 size_t len = p - stacknxt;
8418 size_t size = stackblocksize();
8419
8420 for (;;) {
8421 size_t nleft;
8422
8423 size = stackblocksize();
8424 nleft = size - len;
8425 if (nleft >= newlen)
8426 break;
8427 growstackblock();
8428 }
8429 return stackblock() + len;
8430}
8431
8432char *
8433stnputs(const char *s, size_t n, char *p)
8434{
8435 p = makestrspace(n, p);
8436 p = mempcpy(p, s, n);
8437 return p;
8438}
8439
8440char *
8441stputs(const char *s, char *p)
8442{
8443 return stnputs(s, strlen(s), p);
8444}
8445
8446/* mystring.c */
8447
8448/*
8449 * String functions.
8450 *
8451 * number(s) Convert a string of digits to an integer.
8452 * is_number(s) Return true if s is a string of digits.
8453 */
8454
8455/*
8456 * prefix -- see if pfx is a prefix of string.
8457 */
8458
8459char *
8460prefix(const char *string, const char *pfx)
8461{
8462 while (*pfx) {
8463 if (*pfx++ != *string++)
8464 return 0;
8465 }
8466 return (char *) string;
8467}
8468
8469
8470/*
8471 * Convert a string of digits to an integer, printing an error message on
8472 * failure.
8473 */
8474
8475int
8476number(const char *s)
8477{
8478
8479 if (! is_number(s))
8480 sh_error(illnum, s);
8481 return atoi(s);
8482}
8483
8484
8485/*
8486 * Check for a valid number. This should be elsewhere.
8487 */
8488
8489int
8490is_number(const char *p)
8491{
8492 do {
8493 if (! is_digit(*p))
8494 return 0;
8495 } while (*++p != '\0');
8496 return 1;
8497}
8498
8499
8500/*
8501 * Produce a possibly single quoted string suitable as input to the shell.
8502 * The return string is allocated on the stack.
8503 */
8504
8505char *
8506single_quote(const char *s) {
8507 char *p;
8508
8509 STARTSTACKSTR(p);
8510
8511 do {
8512 char *q;
8513 size_t len;
8514
8515 len = strchrnul(s, '\'') - s;
8516
8517 q = p = makestrspace(len + 3, p);
8518
8519 *q++ = '\'';
8520 q = mempcpy(q, s, len);
8521 *q++ = '\'';
8522 s += len;
8523
8524 STADJUST(q - p, p);
8525
8526 len = strspn(s, "'");
8527 if (!len)
8528 break;
8529
8530 q = p = makestrspace(len + 3, p);
8531
8532 *q++ = '"';
8533 q = mempcpy(q, s, len);
8534 *q++ = '"';
8535 s += len;
8536
8537 STADJUST(q - p, p);
8538 } while (*s);
8539
8540 USTPUTC(0, p);
8541
8542 return stackblock();
8543}
8544
8545/*
8546 * Like strdup but works with the ash stack.
8547 */
8548
8549char *
8550sstrdup(const char *p)
8551{
8552 size_t len = strlen(p) + 1;
8553 return memcpy(stalloc(len), p, len);
8554}
8555
8556
8557static void
8558calcsize(union node *n)
8559{
8560 if (n == NULL)
8561 return;
8562 funcblocksize += nodesize[n->type];
8563 switch (n->type) {
8564 case NCMD:
8565 calcsize(n->ncmd.redirect);
8566 calcsize(n->ncmd.args);
8567 calcsize(n->ncmd.assign);
8568 break;
8569 case NPIPE:
8570 sizenodelist(n->npipe.cmdlist);
8571 break;
8572 case NREDIR:
8573 case NBACKGND:
8574 case NSUBSHELL:
8575 calcsize(n->nredir.redirect);
8576 calcsize(n->nredir.n);
8577 break;
8578 case NAND:
8579 case NOR:
8580 case NSEMI:
8581 case NWHILE:
8582 case NUNTIL:
8583 calcsize(n->nbinary.ch2);
8584 calcsize(n->nbinary.ch1);
8585 break;
8586 case NIF:
8587 calcsize(n->nif.elsepart);
8588 calcsize(n->nif.ifpart);
8589 calcsize(n->nif.test);
8590 break;
8591 case NFOR:
8592 funcstringsize += strlen(n->nfor.var) + 1;
8593 calcsize(n->nfor.body);
8594 calcsize(n->nfor.args);
8595 break;
8596 case NCASE:
8597 calcsize(n->ncase.cases);
8598 calcsize(n->ncase.expr);
8599 break;
8600 case NCLIST:
8601 calcsize(n->nclist.body);
8602 calcsize(n->nclist.pattern);
8603 calcsize(n->nclist.next);
8604 break;
8605 case NDEFUN:
8606 case NARG:
8607 sizenodelist(n->narg.backquote);
8608 funcstringsize += strlen(n->narg.text) + 1;
8609 calcsize(n->narg.next);
8610 break;
8611 case NTO:
8612 case NCLOBBER:
8613 case NFROM:
8614 case NFROMTO:
8615 case NAPPEND:
8616 calcsize(n->nfile.fname);
8617 calcsize(n->nfile.next);
8618 break;
8619 case NTOFD:
8620 case NFROMFD:
8621 calcsize(n->ndup.vname);
8622 calcsize(n->ndup.next);
8623 break;
8624 case NHERE:
8625 case NXHERE:
8626 calcsize(n->nhere.doc);
8627 calcsize(n->nhere.next);
8628 break;
8629 case NNOT:
8630 calcsize(n->nnot.com);
8631 break;
8632 };
8633}
8634
8635
8636static void
8637sizenodelist(struct nodelist *lp)
8638{
8639 while (lp) {
8640 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8641 calcsize(lp->n);
8642 lp = lp->next;
8643 }
8644}
8645
8646
8647static union node *
8648copynode(union node *n)
8649{
8650 union node *new;
8651
8652 if (n == NULL)
8653 return NULL;
8654 new = funcblock;
8655 funcblock = (char *) funcblock + nodesize[n->type];
8656 switch (n->type) {
8657 case NCMD:
8658 new->ncmd.redirect = copynode(n->ncmd.redirect);
8659 new->ncmd.args = copynode(n->ncmd.args);
8660 new->ncmd.assign = copynode(n->ncmd.assign);
8661 break;
8662 case NPIPE:
8663 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8664 new->npipe.backgnd = n->npipe.backgnd;
8665 break;
8666 case NREDIR:
8667 case NBACKGND:
8668 case NSUBSHELL:
8669 new->nredir.redirect = copynode(n->nredir.redirect);
8670 new->nredir.n = copynode(n->nredir.n);
8671 break;
8672 case NAND:
8673 case NOR:
8674 case NSEMI:
8675 case NWHILE:
8676 case NUNTIL:
8677 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8678 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8679 break;
8680 case NIF:
8681 new->nif.elsepart = copynode(n->nif.elsepart);
8682 new->nif.ifpart = copynode(n->nif.ifpart);
8683 new->nif.test = copynode(n->nif.test);
8684 break;
8685 case NFOR:
8686 new->nfor.var = nodesavestr(n->nfor.var);
8687 new->nfor.body = copynode(n->nfor.body);
8688 new->nfor.args = copynode(n->nfor.args);
8689 break;
8690 case NCASE:
8691 new->ncase.cases = copynode(n->ncase.cases);
8692 new->ncase.expr = copynode(n->ncase.expr);
8693 break;
8694 case NCLIST:
8695 new->nclist.body = copynode(n->nclist.body);
8696 new->nclist.pattern = copynode(n->nclist.pattern);
8697 new->nclist.next = copynode(n->nclist.next);
8698 break;
8699 case NDEFUN:
8700 case NARG:
8701 new->narg.backquote = copynodelist(n->narg.backquote);
8702 new->narg.text = nodesavestr(n->narg.text);
8703 new->narg.next = copynode(n->narg.next);
8704 break;
8705 case NTO:
8706 case NCLOBBER:
8707 case NFROM:
8708 case NFROMTO:
8709 case NAPPEND:
8710 new->nfile.fname = copynode(n->nfile.fname);
8711 new->nfile.fd = n->nfile.fd;
8712 new->nfile.next = copynode(n->nfile.next);
8713 break;
8714 case NTOFD:
8715 case NFROMFD:
8716 new->ndup.vname = copynode(n->ndup.vname);
8717 new->ndup.dupfd = n->ndup.dupfd;
8718 new->ndup.fd = n->ndup.fd;
8719 new->ndup.next = copynode(n->ndup.next);
8720 break;
8721 case NHERE:
8722 case NXHERE:
8723 new->nhere.doc = copynode(n->nhere.doc);
8724 new->nhere.fd = n->nhere.fd;
8725 new->nhere.next = copynode(n->nhere.next);
8726 break;
8727 case NNOT:
8728 new->nnot.com = copynode(n->nnot.com);
8729 break;
8730 };
8731 new->type = n->type;
8732 return new;
8733}
8734
8735
8736static struct nodelist *
8737copynodelist(struct nodelist *lp)
8738{
8739 struct nodelist *start;
8740 struct nodelist **lpp;
8741
8742 lpp = &start;
8743 while (lp) {
8744 *lpp = funcblock;
8745 funcblock = (char *) funcblock +
8746 SHELL_ALIGN(sizeof(struct nodelist));
8747 (*lpp)->n = copynode(lp->n);
8748 lp = lp->next;
8749 lpp = &(*lpp)->next;
8750 }
8751 *lpp = NULL;
8752 return start;
8753}
8754
8755
8756static char *
8757nodesavestr(char *s)
8758{
8759 char *rtn = funcstring;
8760
8761 funcstring = stpcpy(funcstring, s) + 1;
8762 return rtn;
8763}
8764
8765
8766/*
8767 * Free a parse tree.
8768 */
8769
8770static void
8771freefunc(struct funcnode *f)
8772{
8773 if (f && --f->count < 0)
8774 ckfree(f);
8775}
8776
8777
8778static void options(int);
8779static void setoption(int, int);
8780
8781
8782/*
8783 * Process the shell command line arguments.
8784 */
8785
8786void
8787procargs(int argc, char **argv)
8788{
8789 int i;
8790 const char *xminusc;
8791 char **xargv;
8792
8793 xargv = argv;
8794 arg0 = xargv[0];
8795 if (argc > 0)
8796 xargv++;
8797 for (i = 0; i < NOPTS; i++)
8798 optlist[i] = 2;
8799 argptr = xargv;
8800 options(1);
8801 xargv = argptr;
8802 xminusc = minusc;
8803 if (*xargv == NULL) {
8804 if (xminusc)
8805 sh_error(bb_msg_requires_arg, "-c");
8806 sflag = 1;
8807 }
8808 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8809 iflag = 1;
8810 if (mflag == 2)
8811 mflag = iflag;
8812 for (i = 0; i < NOPTS; i++)
8813 if (optlist[i] == 2)
8814 optlist[i] = 0;
8815#if DEBUG == 2
8816 debug = 1;
8817#endif
8818 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8819 if (xminusc) {
8820 minusc = *xargv++;
8821 if (*xargv)
8822 goto setarg0;
8823 } else if (!sflag) {
8824 setinputfile(*xargv, 0);
8825setarg0:
8826 arg0 = *xargv++;
8827 commandname = arg0;
8828 }
8829
8830 shellparam.p = xargv;
8831#ifdef CONFIG_ASH_GETOPTS
8832 shellparam.optind = 1;
8833 shellparam.optoff = -1;
8834#endif
8835 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8836 while (*xargv) {
8837 shellparam.nparam++;
8838 xargv++;
8839 }
8840 optschanged();
8841}
8842
8843
8844void
8845optschanged(void)
8846{
8847#if DEBUG
8848 opentrace();
8849#endif
8850 setinteractive(iflag);
8851 setjobctl(mflag);
8852 setvimode(viflag);
8853}
8854
8855static void minus_o(char *name, int val)
8856{
8857 int i;
8858
8859 if (name == NULL) {
8860 out1str("Current option settings\n");
8861 for (i = 0; i < NOPTS; i++)
8862 out1fmt("%-16s%s\n", optnames(i),
8863 optlist[i] ? "on" : "off");
8864 } else {
8865 for (i = 0; i < NOPTS; i++)
8866 if (equal(name, optnames(i))) {
8867 optlist[i] = val;
8868 return;
8869 }
8870 sh_error("Illegal option -o %s", name);
8871 }
8872}
8873
8874/*
8875 * Process shell options. The global variable argptr contains a pointer
8876 * to the argument list; we advance it past the options.
8877 */
8878
8879static void
8880options(int cmdline)
8881{
8882 char *p;
8883 int val;
8884 int c;
8885
8886 if (cmdline)
8887 minusc = NULL;
8888 while ((p = *argptr) != NULL) {
8889 argptr++;
8890 if ((c = *p++) == '-') {
8891 val = 1;
8892 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8893 if (!cmdline) {
8894 /* "-" means turn off -x and -v */
8895 if (p[0] == '\0')
8896 xflag = vflag = 0;
8897 /* "--" means reset params */
8898 else if (*argptr == NULL)
8899 setparam(argptr);
8900 }
8901 break; /* "-" or "--" terminates options */
8902 }
8903 } else if (c == '+') {
8904 val = 0;
8905 } else {
8906 argptr--;
8907 break;
8908 }
8909 while ((c = *p++) != '\0') {
8910 if (c == 'c' && cmdline) {
8911 minusc = p; /* command is after shell args*/
8912 } else if (c == 'o') {
8913 minus_o(*argptr, val);
8914 if (*argptr)
8915 argptr++;
8916 } else if (cmdline && (c == '-')) { // long options
8917 if (strcmp(p, "login") == 0)
8918 isloginsh = 1;
8919 break;
8920 } else {
8921 setoption(c, val);
8922 }
8923 }
8924 }
8925}
8926
8927
8928static void
8929setoption(int flag, int val)
8930{
8931 int i;
8932
8933 for (i = 0; i < NOPTS; i++)
8934 if (optletters(i) == flag) {
8935 optlist[i] = val;
8936 return;
8937 }
8938 sh_error("Illegal option -%c", flag);
8939 /* NOTREACHED */
8940}
8941
8942
8943
8944/*
8945 * Set the shell parameters.
8946 */
8947
8948void
8949setparam(char **argv)
8950{
8951 char **newparam;
8952 char **ap;
8953 int nparam;
8954
8955 for (nparam = 0 ; argv[nparam] ; nparam++);
8956 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8957 while (*argv) {
8958 *ap++ = savestr(*argv++);
8959 }
8960 *ap = NULL;
8961 freeparam(&shellparam);
8962 shellparam.malloc = 1;
8963 shellparam.nparam = nparam;
8964 shellparam.p = newparam;
8965#ifdef CONFIG_ASH_GETOPTS
8966 shellparam.optind = 1;
8967 shellparam.optoff = -1;
8968#endif
8969}
8970
8971
8972/*
8973 * Free the list of positional parameters.
8974 */
8975
8976void
8977freeparam(volatile struct shparam *param)
8978{
8979 char **ap;
8980
8981 if (param->malloc) {
8982 for (ap = param->p ; *ap ; ap++)
8983 ckfree(*ap);
8984 ckfree(param->p);
8985 }
8986}
8987
8988
8989
8990/*
8991 * The shift builtin command.
8992 */
8993
8994int
8995shiftcmd(int argc, char **argv)
8996{
8997 int n;
8998 char **ap1, **ap2;
8999
9000 n = 1;
9001 if (argc > 1)
9002 n = number(argv[1]);
9003 if (n > shellparam.nparam)
9004 sh_error("can't shift that many");
9005 INTOFF;
9006 shellparam.nparam -= n;
9007 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9008 if (shellparam.malloc)
9009 ckfree(*ap1);
9010 }
9011 ap2 = shellparam.p;
9012 while ((*ap2++ = *ap1++) != NULL);
9013#ifdef CONFIG_ASH_GETOPTS
9014 shellparam.optind = 1;
9015 shellparam.optoff = -1;
9016#endif
9017 INTON;
9018 return 0;
9019}
9020
9021
9022
9023/*
9024 * The set command builtin.
9025 */
9026
9027int
9028setcmd(int argc, char **argv)
9029{
9030 if (argc == 1)
9031 return showvars(nullstr, 0, VUNSET);
9032 INTOFF;
9033 options(0);
9034 optschanged();
9035 if (*argptr != NULL) {
9036 setparam(argptr);
9037 }
9038 INTON;
9039 return 0;
9040}
9041
9042
9043#ifdef CONFIG_ASH_GETOPTS
9044static void
9045getoptsreset(const char *value)
9046{
9047 shellparam.optind = number(value);
9048 shellparam.optoff = -1;
9049}
9050#endif
9051
9052#ifdef CONFIG_LOCALE_SUPPORT
9053static void change_lc_all(const char *value)
9054{
9055 if (value != 0 && *value != 0)
9056 setlocale(LC_ALL, value);
9057}
9058
9059static void change_lc_ctype(const char *value)
9060{
9061 if (value != 0 && *value != 0)
9062 setlocale(LC_CTYPE, value);
9063}
9064
9065#endif
9066
9067#ifdef CONFIG_ASH_RANDOM_SUPPORT
9068/* Roughly copied from bash.. */
9069static void change_random(const char *value)
9070{
9071 if(value == NULL) {
9072 /* "get", generate */
9073 char buf[16];
9074
9075 rseed = rseed * 1103515245 + 12345;
9076 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9077 /* set without recursion */
9078 setvar(vrandom.text, buf, VNOFUNC);
9079 vrandom.flags &= ~VNOFUNC;
9080 } else {
9081 /* set/reset */
9082 rseed = strtoul(value, (char **)NULL, 10);
9083 }
9084}
9085#endif
9086
9087
9088#ifdef CONFIG_ASH_GETOPTS
9089static int
9090getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9091{
9092 char *p, *q;
9093 char c = '?';
9094 int done = 0;
9095 int err = 0;
9096 char s[12];
9097 char **optnext;
9098
9099 if(*param_optind < 1)
9100 return 1;
9101 optnext = optfirst + *param_optind - 1;
9102
9103 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9104 p = NULL;
9105 else
9106 p = optnext[-1] + *optoff;
9107 if (p == NULL || *p == '\0') {
9108 /* Current word is done, advance */
9109 p = *optnext;
9110 if (p == NULL || *p != '-' || *++p == '\0') {
9111atend:
9112 p = NULL;
9113 done = 1;
9114 goto out;
9115 }
9116 optnext++;
9117 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9118 goto atend;
9119 }
9120
9121 c = *p++;
9122 for (q = optstr; *q != c; ) {
9123 if (*q == '\0') {
9124 if (optstr[0] == ':') {
9125 s[0] = c;
9126 s[1] = '\0';
9127 err |= setvarsafe("OPTARG", s, 0);
9128 } else {
9129 fprintf(stderr, "Illegal option -%c\n", c);
9130 (void) unsetvar("OPTARG");
9131 }
9132 c = '?';
9133 goto out;
9134 }
9135 if (*++q == ':')
9136 q++;
9137 }
9138
9139 if (*++q == ':') {
9140 if (*p == '\0' && (p = *optnext) == NULL) {
9141 if (optstr[0] == ':') {
9142 s[0] = c;
9143 s[1] = '\0';
9144 err |= setvarsafe("OPTARG", s, 0);
9145 c = ':';
9146 } else {
9147 fprintf(stderr, "No arg for -%c option\n", c);
9148 (void) unsetvar("OPTARG");
9149 c = '?';
9150 }
9151 goto out;
9152 }
9153
9154 if (p == *optnext)
9155 optnext++;
9156 err |= setvarsafe("OPTARG", p, 0);
9157 p = NULL;
9158 } else
9159 err |= setvarsafe("OPTARG", nullstr, 0);
9160
9161out:
9162 *optoff = p ? p - *(optnext - 1) : -1;
9163 *param_optind = optnext - optfirst + 1;
9164 fmtstr(s, sizeof(s), "%d", *param_optind);
9165 err |= setvarsafe("OPTIND", s, VNOFUNC);
9166 s[0] = c;
9167 s[1] = '\0';
9168 err |= setvarsafe(optvar, s, 0);
9169 if (err) {
9170 *param_optind = 1;
9171 *optoff = -1;
9172 flushall();
9173 exraise(EXERROR);
9174 }
9175 return done;
9176}
9177
9178/*
9179 * The getopts builtin. Shellparam.optnext points to the next argument
9180 * to be processed. Shellparam.optptr points to the next character to
9181 * be processed in the current argument. If shellparam.optnext is NULL,
9182 * then it's the first time getopts has been called.
9183 */
9184
9185int
9186getoptscmd(int argc, char **argv)
9187{
9188 char **optbase;
9189
9190 if (argc < 3)
9191 sh_error("Usage: getopts optstring var [arg]");
9192 else if (argc == 3) {
9193 optbase = shellparam.p;
9194 if (shellparam.optind > shellparam.nparam + 1) {
9195 shellparam.optind = 1;
9196 shellparam.optoff = -1;
9197 }
9198 }
9199 else {
9200 optbase = &argv[3];
9201 if (shellparam.optind > argc - 2) {
9202 shellparam.optind = 1;
9203 shellparam.optoff = -1;
9204 }
9205 }
9206
9207 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9208 &shellparam.optoff);
9209}
9210#endif /* CONFIG_ASH_GETOPTS */
9211
9212/*
9213 * XXX - should get rid of. have all builtins use getopt(3). the
9214 * library getopt must have the BSD extension static variable "optreset"
9215 * otherwise it can't be used within the shell safely.
9216 *
9217 * Standard option processing (a la getopt) for builtin routines. The
9218 * only argument that is passed to nextopt is the option string; the
9219 * other arguments are unnecessary. It return the character, or '\0' on
9220 * end of input.
9221 */
9222
9223static int
9224nextopt(const char *optstring)
9225{
9226 char *p;
9227 const char *q;
9228 char c;
9229
9230 if ((p = optptr) == NULL || *p == '\0') {
9231 p = *argptr;
9232 if (p == NULL || *p != '-' || *++p == '\0')
9233 return '\0';
9234 argptr++;
9235 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9236 return '\0';
9237 }
9238 c = *p++;
9239 for (q = optstring ; *q != c ; ) {
9240 if (*q == '\0')
9241 sh_error("Illegal option -%c", c);
9242 if (*++q == ':')
9243 q++;
9244 }
9245 if (*++q == ':') {
9246 if (*p == '\0' && (p = *argptr++) == NULL)
9247 sh_error("No arg for -%c option", c);
9248 optionarg = p;
9249 p = NULL;
9250 }
9251 optptr = p;
9252 return c;
9253}
9254
9255
9256/* output.c */
9257
9258void
9259outstr(const char *p, FILE *file)
9260{
9261 INTOFF;
9262 fputs(p, file);
9263 INTON;
9264}
9265
9266void
9267flushall(void)
9268{
9269 INTOFF;
9270 fflush(stdout);
9271 fflush(stderr);
9272 INTON;
9273}
9274
9275void
9276flusherr(void)
9277{
9278 INTOFF;
9279 fflush(stderr);
9280 INTON;
9281}
9282
9283static void
9284outcslow(int c, FILE *dest)
9285{
9286 INTOFF;
9287 putc(c, dest);
9288 fflush(dest);
9289 INTON;
9290}
9291
9292
9293static int
9294out1fmt(const char *fmt, ...)
9295{
9296 va_list ap;
9297 int r;
9298
9299 INTOFF;
9300 va_start(ap, fmt);
9301 r = vprintf(fmt, ap);
9302 va_end(ap);
9303 INTON;
9304 return r;
9305}
9306
9307
9308int
9309fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9310{
9311 va_list ap;
9312 int ret;
9313
9314 va_start(ap, fmt);
9315 INTOFF;
9316 ret = vsnprintf(outbuf, length, fmt, ap);
9317 va_end(ap);
9318 INTON;
9319 return ret;
9320}
9321
9322
9323
9324/* parser.c */
9325
9326
9327/*
9328 * Shell command parser.
9329 */
9330
9331#define EOFMARKLEN 79
9332
9333
9334struct heredoc {
9335 struct heredoc *next; /* next here document in list */
9336 union node *here; /* redirection node */
9337 char *eofmark; /* string indicating end of input */
9338 int striptabs; /* if set, strip leading tabs */
9339};
9340
9341
9342
9343static struct heredoc *heredoclist; /* list of here documents to read */
9344
9345
9346static union node *list(int);
9347static union node *andor(void);
9348static union node *pipeline(void);
9349static union node *command(void);
9350static union node *simplecmd(void);
9351static union node *makename(void);
9352static void parsefname(void);
9353static void parseheredoc(void);
9354static char peektoken(void);
9355static int readtoken(void);
9356static int xxreadtoken(void);
9357static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9358static int noexpand(char *);
9359static void synexpect(int) ATTRIBUTE_NORETURN;
9360static void synerror(const char *) ATTRIBUTE_NORETURN;
9361static void setprompt(int);
9362
9363
9364
9365
9366/*
9367 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9368 * valid parse tree indicating a blank line.)
9369 */
9370
9371union node *
9372parsecmd(int interact)
9373{
9374 int t;
9375
9376 tokpushback = 0;
9377 doprompt = interact;
9378 if (doprompt)
9379 setprompt(doprompt);
9380 needprompt = 0;
9381 t = readtoken();
9382 if (t == TEOF)
9383 return NEOF;
9384 if (t == TNL)
9385 return NULL;
9386 tokpushback++;
9387 return list(1);
9388}
9389
9390
9391static union node *
9392list(int nlflag)
9393{
9394 union node *n1, *n2, *n3;
9395 int tok;
9396
9397 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9398 if (nlflag == 2 && peektoken())
9399 return NULL;
9400 n1 = NULL;
9401 for (;;) {
9402 n2 = andor();
9403 tok = readtoken();
9404 if (tok == TBACKGND) {
9405 if (n2->type == NPIPE) {
9406 n2->npipe.backgnd = 1;
9407 } else {
9408 if (n2->type != NREDIR) {
9409 n3 = stalloc(sizeof(struct nredir));
9410 n3->nredir.n = n2;
9411 n3->nredir.redirect = NULL;
9412 n2 = n3;
9413 }
9414 n2->type = NBACKGND;
9415 }
9416 }
9417 if (n1 == NULL) {
9418 n1 = n2;
9419 }
9420 else {
9421 n3 = (union node *)stalloc(sizeof (struct nbinary));
9422 n3->type = NSEMI;
9423 n3->nbinary.ch1 = n1;
9424 n3->nbinary.ch2 = n2;
9425 n1 = n3;
9426 }
9427 switch (tok) {
9428 case TBACKGND:
9429 case TSEMI:
9430 tok = readtoken();
9431 /* fall through */
9432 case TNL:
9433 if (tok == TNL) {
9434 parseheredoc();
9435 if (nlflag == 1)
9436 return n1;
9437 } else {
9438 tokpushback++;
9439 }
9440 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9441 if (peektoken())
9442 return n1;
9443 break;
9444 case TEOF:
9445 if (heredoclist)
9446 parseheredoc();
9447 else
9448 pungetc(); /* push back EOF on input */
9449 return n1;
9450 default:
9451 if (nlflag == 1)
9452 synexpect(-1);
9453 tokpushback++;
9454 return n1;
9455 }
9456 }
9457}
9458
9459
9460
9461static union node *
9462andor(void)
9463{
9464 union node *n1, *n2, *n3;
9465 int t;
9466
9467 n1 = pipeline();
9468 for (;;) {
9469 if ((t = readtoken()) == TAND) {
9470 t = NAND;
9471 } else if (t == TOR) {
9472 t = NOR;
9473 } else {
9474 tokpushback++;
9475 return n1;
9476 }
9477 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9478 n2 = pipeline();
9479 n3 = (union node *)stalloc(sizeof (struct nbinary));
9480 n3->type = t;
9481 n3->nbinary.ch1 = n1;
9482 n3->nbinary.ch2 = n2;
9483 n1 = n3;
9484 }
9485}
9486
9487
9488
9489static union node *
9490pipeline(void)
9491{
9492 union node *n1, *n2, *pipenode;
9493 struct nodelist *lp, *prev;
9494 int negate;
9495
9496 negate = 0;
9497 TRACE(("pipeline: entered\n"));
9498 if (readtoken() == TNOT) {
9499 negate = !negate;
9500 checkkwd = CHKKWD | CHKALIAS;
9501 } else
9502 tokpushback++;
9503 n1 = command();
9504 if (readtoken() == TPIPE) {
9505 pipenode = (union node *)stalloc(sizeof (struct npipe));
9506 pipenode->type = NPIPE;
9507 pipenode->npipe.backgnd = 0;
9508 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9509 pipenode->npipe.cmdlist = lp;
9510 lp->n = n1;
9511 do {
9512 prev = lp;
9513 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9514 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9515 lp->n = command();
9516 prev->next = lp;
9517 } while (readtoken() == TPIPE);
9518 lp->next = NULL;
9519 n1 = pipenode;
9520 }
9521 tokpushback++;
9522 if (negate) {
9523 n2 = (union node *)stalloc(sizeof (struct nnot));
9524 n2->type = NNOT;
9525 n2->nnot.com = n1;
9526 return n2;
9527 } else
9528 return n1;
9529}
9530
9531
9532
9533static union node *
9534command(void)
9535{
9536 union node *n1, *n2;
9537 union node *ap, **app;
9538 union node *cp, **cpp;
9539 union node *redir, **rpp;
9540 union node **rpp2;
9541 int t;
9542
9543 redir = NULL;
9544 rpp2 = &redir;
9545
9546 switch (readtoken()) {
9547 default:
9548 synexpect(-1);
9549 /* NOTREACHED */
9550 case TIF:
9551 n1 = (union node *)stalloc(sizeof (struct nif));
9552 n1->type = NIF;
9553 n1->nif.test = list(0);
9554 if (readtoken() != TTHEN)
9555 synexpect(TTHEN);
9556 n1->nif.ifpart = list(0);
9557 n2 = n1;
9558 while (readtoken() == TELIF) {
9559 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9560 n2 = n2->nif.elsepart;
9561 n2->type = NIF;
9562 n2->nif.test = list(0);
9563 if (readtoken() != TTHEN)
9564 synexpect(TTHEN);
9565 n2->nif.ifpart = list(0);
9566 }
9567 if (lasttoken == TELSE)
9568 n2->nif.elsepart = list(0);
9569 else {
9570 n2->nif.elsepart = NULL;
9571 tokpushback++;
9572 }
9573 t = TFI;
9574 break;
9575 case TWHILE:
9576 case TUNTIL: {
9577 int got;
9578 n1 = (union node *)stalloc(sizeof (struct nbinary));
9579 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9580 n1->nbinary.ch1 = list(0);
9581 if ((got=readtoken()) != TDO) {
9582TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9583 synexpect(TDO);
9584 }
9585 n1->nbinary.ch2 = list(0);
9586 t = TDONE;
9587 break;
9588 }
9589 case TFOR:
9590 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9591 synerror("Bad for loop variable");
9592 n1 = (union node *)stalloc(sizeof (struct nfor));
9593 n1->type = NFOR;
9594 n1->nfor.var = wordtext;
9595 checkkwd = CHKKWD | CHKALIAS;
9596 if (readtoken() == TIN) {
9597 app = &ap;
9598 while (readtoken() == TWORD) {
9599 n2 = (union node *)stalloc(sizeof (struct narg));
9600 n2->type = NARG;
9601 n2->narg.text = wordtext;
9602 n2->narg.backquote = backquotelist;
9603 *app = n2;
9604 app = &n2->narg.next;
9605 }
9606 *app = NULL;
9607 n1->nfor.args = ap;
9608 if (lasttoken != TNL && lasttoken != TSEMI)
9609 synexpect(-1);
9610 } else {
9611 n2 = (union node *)stalloc(sizeof (struct narg));
9612 n2->type = NARG;
9613 n2->narg.text = (char *)dolatstr;
9614 n2->narg.backquote = NULL;
9615 n2->narg.next = NULL;
9616 n1->nfor.args = n2;
9617 /*
9618 * Newline or semicolon here is optional (but note
9619 * that the original Bourne shell only allowed NL).
9620 */
9621 if (lasttoken != TNL && lasttoken != TSEMI)
9622 tokpushback++;
9623 }
9624 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9625 if (readtoken() != TDO)
9626 synexpect(TDO);
9627 n1->nfor.body = list(0);
9628 t = TDONE;
9629 break;
9630 case TCASE:
9631 n1 = (union node *)stalloc(sizeof (struct ncase));
9632 n1->type = NCASE;
9633 if (readtoken() != TWORD)
9634 synexpect(TWORD);
9635 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9636 n2->type = NARG;
9637 n2->narg.text = wordtext;
9638 n2->narg.backquote = backquotelist;
9639 n2->narg.next = NULL;
9640 do {
9641 checkkwd = CHKKWD | CHKALIAS;
9642 } while (readtoken() == TNL);
9643 if (lasttoken != TIN)
9644 synexpect(TIN);
9645 cpp = &n1->ncase.cases;
9646next_case:
9647 checkkwd = CHKNL | CHKKWD;
9648 t = readtoken();
9649 while(t != TESAC) {
9650 if (lasttoken == TLP)
9651 readtoken();
9652 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9653 cp->type = NCLIST;
9654 app = &cp->nclist.pattern;
9655 for (;;) {
9656 *app = ap = (union node *)stalloc(sizeof (struct narg));
9657 ap->type = NARG;
9658 ap->narg.text = wordtext;
9659 ap->narg.backquote = backquotelist;
9660 if (readtoken() != TPIPE)
9661 break;
9662 app = &ap->narg.next;
9663 readtoken();
9664 }
9665 ap->narg.next = NULL;
9666 if (lasttoken != TRP)
9667 synexpect(TRP);
9668 cp->nclist.body = list(2);
9669
9670 cpp = &cp->nclist.next;
9671
9672 checkkwd = CHKNL | CHKKWD;
9673 if ((t = readtoken()) != TESAC) {
9674 if (t != TENDCASE)
9675 synexpect(TENDCASE);
9676 else
9677 goto next_case;
9678 }
9679 }
9680 *cpp = NULL;
9681 goto redir;
9682 case TLP:
9683 n1 = (union node *)stalloc(sizeof (struct nredir));
9684 n1->type = NSUBSHELL;
9685 n1->nredir.n = list(0);
9686 n1->nredir.redirect = NULL;
9687 t = TRP;
9688 break;
9689 case TBEGIN:
9690 n1 = list(0);
9691 t = TEND;
9692 break;
9693 case TWORD:
9694 case TREDIR:
9695 tokpushback++;
9696 return simplecmd();
9697 }
9698
9699 if (readtoken() != t)
9700 synexpect(t);
9701
9702redir:
9703 /* Now check for redirection which may follow command */
9704 checkkwd = CHKKWD | CHKALIAS;
9705 rpp = rpp2;
9706 while (readtoken() == TREDIR) {
9707 *rpp = n2 = redirnode;
9708 rpp = &n2->nfile.next;
9709 parsefname();
9710 }
9711 tokpushback++;
9712 *rpp = NULL;
9713 if (redir) {
9714 if (n1->type != NSUBSHELL) {
9715 n2 = (union node *)stalloc(sizeof (struct nredir));
9716 n2->type = NREDIR;
9717 n2->nredir.n = n1;
9718 n1 = n2;
9719 }
9720 n1->nredir.redirect = redir;
9721 }
9722
9723 return n1;
9724}
9725
9726
9727static union node *
9728simplecmd(void) {
9729 union node *args, **app;
9730 union node *n = NULL;
9731 union node *vars, **vpp;
9732 union node **rpp, *redir;
9733 int savecheckkwd;
9734
9735 args = NULL;
9736 app = &args;
9737 vars = NULL;
9738 vpp = &vars;
9739 redir = NULL;
9740 rpp = &redir;
9741
9742 savecheckkwd = CHKALIAS;
9743 for (;;) {
9744 checkkwd = savecheckkwd;
9745 switch (readtoken()) {
9746 case TWORD:
9747 n = (union node *)stalloc(sizeof (struct narg));
9748 n->type = NARG;
9749 n->narg.text = wordtext;
9750 n->narg.backquote = backquotelist;
9751 if (savecheckkwd && isassignment(wordtext)) {
9752 *vpp = n;
9753 vpp = &n->narg.next;
9754 } else {
9755 *app = n;
9756 app = &n->narg.next;
9757 savecheckkwd = 0;
9758 }
9759 break;
9760 case TREDIR:
9761 *rpp = n = redirnode;
9762 rpp = &n->nfile.next;
9763 parsefname(); /* read name of redirection file */
9764 break;
9765 case TLP:
9766 if (
9767 args && app == &args->narg.next &&
9768 !vars && !redir
9769 ) {
9770 struct builtincmd *bcmd;
9771 const char *name;
9772
9773 /* We have a function */
9774 if (readtoken() != TRP)
9775 synexpect(TRP);
9776 name = n->narg.text;
9777 if (
9778 !goodname(name) || (
9779 (bcmd = find_builtin(name)) &&
9780 IS_BUILTIN_SPECIAL(bcmd)
9781 )
9782 )
9783 synerror("Bad function name");
9784 n->type = NDEFUN;
9785 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9786 n->narg.next = command();
9787 return n;
9788 }
9789 /* fall through */
9790 default:
9791 tokpushback++;
9792 goto out;
9793 }
9794 }
9795out:
9796 *app = NULL;
9797 *vpp = NULL;
9798 *rpp = NULL;
9799 n = (union node *)stalloc(sizeof (struct ncmd));
9800 n->type = NCMD;
9801 n->ncmd.args = args;
9802 n->ncmd.assign = vars;
9803 n->ncmd.redirect = redir;
9804 return n;
9805}
9806
9807static union node *
9808makename(void)
9809{
9810 union node *n;
9811
9812 n = (union node *)stalloc(sizeof (struct narg));
9813 n->type = NARG;
9814 n->narg.next = NULL;
9815 n->narg.text = wordtext;
9816 n->narg.backquote = backquotelist;
9817 return n;
9818}
9819
9820void fixredir(union node *n, const char *text, int err)
9821{
9822 TRACE(("Fix redir %s %d\n", text, err));
9823 if (!err)
9824 n->ndup.vname = NULL;
9825
9826 if (is_digit(text[0]) && text[1] == '\0')
9827 n->ndup.dupfd = digit_val(text[0]);
9828 else if (text[0] == '-' && text[1] == '\0')
9829 n->ndup.dupfd = -1;
9830 else {
9831
9832 if (err)
9833 synerror("Bad fd number");
9834 else
9835 n->ndup.vname = makename();
9836 }
9837}
9838
9839
9840static void
9841parsefname(void)
9842{
9843 union node *n = redirnode;
9844
9845 if (readtoken() != TWORD)
9846 synexpect(-1);
9847 if (n->type == NHERE) {
9848 struct heredoc *here = heredoc;
9849 struct heredoc *p;
9850 int i;
9851
9852 if (quoteflag == 0)
9853 n->type = NXHERE;
9854 TRACE(("Here document %d\n", n->type));
9855 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9856 synerror("Illegal eof marker for << redirection");
9857 rmescapes(wordtext);
9858 here->eofmark = wordtext;
9859 here->next = NULL;
9860 if (heredoclist == NULL)
9861 heredoclist = here;
9862 else {
9863 for (p = heredoclist ; p->next ; p = p->next);
9864 p->next = here;
9865 }
9866 } else if (n->type == NTOFD || n->type == NFROMFD) {
9867 fixredir(n, wordtext, 0);
9868 } else {
9869 n->nfile.fname = makename();
9870 }
9871}
9872
9873
9874/*
9875 * Input any here documents.
9876 */
9877
9878static void
9879parseheredoc(void)
9880{
9881 struct heredoc *here;
9882 union node *n;
9883
9884 here = heredoclist;
9885 heredoclist = 0;
9886
9887 while (here) {
9888 if (needprompt) {
9889 setprompt(2);
9890 }
9891 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9892 here->eofmark, here->striptabs);
9893 n = (union node *)stalloc(sizeof (struct narg));
9894 n->narg.type = NARG;
9895 n->narg.next = NULL;
9896 n->narg.text = wordtext;
9897 n->narg.backquote = backquotelist;
9898 here->here->nhere.doc = n;
9899 here = here->next;
9900 }
9901}
9902
9903static char peektoken(void)
9904{
9905 int t;
9906
9907 t = readtoken();
9908 tokpushback++;
9909 return tokname_array[t][0];
9910}
9911
9912static int
9913readtoken(void)
9914{
9915 int t;
9916#if DEBUG
9917 int alreadyseen = tokpushback;
9918#endif
9919
9920#ifdef CONFIG_ASH_ALIAS
9921top:
9922#endif
9923
9924 t = xxreadtoken();
9925
9926 /*
9927 * eat newlines
9928 */
9929 if (checkkwd & CHKNL) {
9930 while (t == TNL) {
9931 parseheredoc();
9932 t = xxreadtoken();
9933 }
9934 }
9935
9936 if (t != TWORD || quoteflag) {
9937 goto out;
9938 }
9939
9940 /*
9941 * check for keywords
9942 */
9943 if (checkkwd & CHKKWD) {
9944 const char *const *pp;
9945
9946 if ((pp = findkwd(wordtext))) {
9947 lasttoken = t = pp - tokname_array;
9948 TRACE(("keyword %s recognized\n", tokname(t)));
9949 goto out;
9950 }
9951 }
9952
9953 if (checkkwd & CHKALIAS) {
9954#ifdef CONFIG_ASH_ALIAS
9955 struct alias *ap;
9956 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9957 if (*ap->val) {
9958 pushstring(ap->val, ap);
9959 }
9960 goto top;
9961 }
9962#endif
9963 }
9964out:
9965 checkkwd = 0;
9966#if DEBUG
9967 if (!alreadyseen)
9968 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9969 else
9970 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9971#endif
9972 return t;
9973}
9974
9975
9976/*
9977 * Read the next input token.
9978 * If the token is a word, we set backquotelist to the list of cmds in
9979 * backquotes. We set quoteflag to true if any part of the word was
9980 * quoted.
9981 * If the token is TREDIR, then we set redirnode to a structure containing
9982 * the redirection.
9983 * In all cases, the variable startlinno is set to the number of the line
9984 * on which the token starts.
9985 *
9986 * [Change comment: here documents and internal procedures]
9987 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9988 * word parsing code into a separate routine. In this case, readtoken
9989 * doesn't need to have any internal procedures, but parseword does.
9990 * We could also make parseoperator in essence the main routine, and
9991 * have parseword (readtoken1?) handle both words and redirection.]
9992 */
9993
9994#define NEW_xxreadtoken
9995#ifdef NEW_xxreadtoken
9996
9997/* singles must be first! */
9998static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9999
10000static const char xxreadtoken_tokens[] = {
10001 TNL, TLP, TRP, /* only single occurrence allowed */
10002 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10003 TEOF, /* corresponds to trailing nul */
10004 TAND, TOR, TENDCASE, /* if double occurrence */
10005};
10006
10007#define xxreadtoken_doubles \
10008 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10009#define xxreadtoken_singles \
10010 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10011
10012static int xxreadtoken(void)
10013{
10014 int c;
10015
10016 if (tokpushback) {
10017 tokpushback = 0;
10018 return lasttoken;
10019 }
10020 if (needprompt) {
10021 setprompt(2);
10022 }
10023 startlinno = plinno;
10024 for (;;) { /* until token or start of word found */
10025 c = pgetc_macro();
10026
10027 if ((c != ' ') && (c != '\t')
10028#ifdef CONFIG_ASH_ALIAS
10029 && (c != PEOA)
10030#endif
10031 ) {
10032 if (c == '#') {
10033 while ((c = pgetc()) != '\n' && c != PEOF);
10034 pungetc();
10035 } else if (c == '\\') {
10036 if (pgetc() != '\n') {
10037 pungetc();
10038 goto READTOKEN1;
10039 }
10040 startlinno = ++plinno;
10041 if (doprompt)
10042 setprompt(2);
10043 } else {
10044 const char *p
10045 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10046
10047 if (c != PEOF) {
10048 if (c == '\n') {
10049 plinno++;
10050 needprompt = doprompt;
10051 }
10052
10053 p = strchr(xxreadtoken_chars, c);
10054 if (p == NULL) {
10055 READTOKEN1:
10056 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10057 }
10058
10059 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10060 if (pgetc() == *p) { /* double occurrence? */
10061 p += xxreadtoken_doubles + 1;
10062 } else {
10063 pungetc();
10064 }
10065 }
10066 }
10067
10068 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10069 }
10070 }
10071 }
10072}
10073
10074
10075#else
10076#define RETURN(token) return lasttoken = token
10077
10078static int
10079xxreadtoken(void)
10080{
10081 int c;
10082
10083 if (tokpushback) {
10084 tokpushback = 0;
10085 return lasttoken;
10086 }
10087 if (needprompt) {
10088 setprompt(2);
10089 }
10090 startlinno = plinno;
10091 for (;;) { /* until token or start of word found */
10092 c = pgetc_macro();
10093 switch (c) {
10094 case ' ': case '\t':
10095#ifdef CONFIG_ASH_ALIAS
10096 case PEOA:
10097#endif
10098 continue;
10099 case '#':
10100 while ((c = pgetc()) != '\n' && c != PEOF);
10101 pungetc();
10102 continue;
10103 case '\\':
10104 if (pgetc() == '\n') {
10105 startlinno = ++plinno;
10106 if (doprompt)
10107 setprompt(2);
10108 continue;
10109 }
10110 pungetc();
10111 goto breakloop;
10112 case '\n':
10113 plinno++;
10114 needprompt = doprompt;
10115 RETURN(TNL);
10116 case PEOF:
10117 RETURN(TEOF);
10118 case '&':
10119 if (pgetc() == '&')
10120 RETURN(TAND);
10121 pungetc();
10122 RETURN(TBACKGND);
10123 case '|':
10124 if (pgetc() == '|')
10125 RETURN(TOR);
10126 pungetc();
10127 RETURN(TPIPE);
10128 case ';':
10129 if (pgetc() == ';')
10130 RETURN(TENDCASE);
10131 pungetc();
10132 RETURN(TSEMI);
10133 case '(':
10134 RETURN(TLP);
10135 case ')':
10136 RETURN(TRP);
10137 default:
10138 goto breakloop;
10139 }
10140 }
10141breakloop:
10142 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10143#undef RETURN
10144}
10145#endif /* NEW_xxreadtoken */
10146
10147
10148/*
10149 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10150 * is not NULL, read a here document. In the latter case, eofmark is the
10151 * word which marks the end of the document and striptabs is true if
10152 * leading tabs should be stripped from the document. The argument firstc
10153 * is the first character of the input token or document.
10154 *
10155 * Because C does not have internal subroutines, I have simulated them
10156 * using goto's to implement the subroutine linkage. The following macros
10157 * will run code that appears at the end of readtoken1.
10158 */
10159
10160#define CHECKEND() {goto checkend; checkend_return:;}
10161#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10162#define PARSESUB() {goto parsesub; parsesub_return:;}
10163#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10164#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10165#define PARSEARITH() {goto parsearith; parsearith_return:;}
10166
10167static int
10168readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10169{
10170 int c = firstc;
10171 char *out;
10172 int len;
10173 char line[EOFMARKLEN + 1];
10174 struct nodelist *bqlist = 0;
10175 int quotef = 0;
10176 int dblquote = 0;
10177 int varnest = 0; /* levels of variables expansion */
10178 int arinest = 0; /* levels of arithmetic expansion */
10179 int parenlevel = 0; /* levels of parens in arithmetic */
10180 int dqvarnest = 0; /* levels of variables expansion within double quotes */
10181 int oldstyle = 0;
10182 int prevsyntax = 0; /* syntax before arithmetic */
10183#if __GNUC__
10184 /* Avoid longjmp clobbering */
10185 (void) &out;
10186 (void) &quotef;
10187 (void) &dblquote;
10188 (void) &varnest;
10189 (void) &arinest;
10190 (void) &parenlevel;
10191 (void) &dqvarnest;
10192 (void) &oldstyle;
10193 (void) &prevsyntax;
10194 (void) &syntax;
10195#endif
10196
10197 startlinno = plinno;
10198 dblquote = 0;
10199 if (syntax == DQSYNTAX)
10200 dblquote = 1;
10201 quotef = 0;
10202 bqlist = NULL;
10203 varnest = 0;
10204 arinest = 0;
10205 parenlevel = 0;
10206 dqvarnest = 0;
10207
10208 STARTSTACKSTR(out);
10209 loop: { /* for each line, until end of word */
10210 CHECKEND(); /* set c to PEOF if at end of here document */
10211 for (;;) { /* until end of line or end of word */
10212 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10213 switch(SIT(c, syntax)) {
10214 case CNL: /* '\n' */
10215 if (syntax == BASESYNTAX)
10216 goto endword; /* exit outer loop */
10217 USTPUTC(c, out);
10218 plinno++;
10219 if (doprompt)
10220 setprompt(2);
10221 c = pgetc();
10222 goto loop; /* continue outer loop */
10223 case CWORD:
10224 USTPUTC(c, out);
10225 break;
10226 case CCTL:
10227 if (eofmark == NULL || dblquote)
10228 USTPUTC(CTLESC, out);
10229 USTPUTC(c, out);
10230 break;
10231 case CBACK: /* backslash */
10232 c = pgetc2();
10233 if (c == PEOF) {
10234 USTPUTC(CTLESC, out);
10235 USTPUTC('\\', out);
10236 pungetc();
10237 } else if (c == '\n') {
10238 if (doprompt)
10239 setprompt(2);
10240 } else {
10241 if (dblquote &&
10242 c != '\\' && c != '`' &&
10243 c != '$' && (
10244 c != '"' ||
10245 eofmark != NULL)
10246 ) {
10247 USTPUTC(CTLESC, out);
10248 USTPUTC('\\', out);
10249 }
10250 if (SIT(c, SQSYNTAX) == CCTL)
10251 USTPUTC(CTLESC, out);
10252 USTPUTC(c, out);
10253 quotef++;
10254 }
10255 break;
10256 case CSQUOTE:
10257 syntax = SQSYNTAX;
10258quotemark:
10259 if (eofmark == NULL) {
10260 USTPUTC(CTLQUOTEMARK, out);
10261 }
10262 break;
10263 case CDQUOTE:
10264 syntax = DQSYNTAX;
10265 dblquote = 1;
10266 goto quotemark;
10267 case CENDQUOTE:
10268 if (eofmark != NULL && arinest == 0 &&
10269 varnest == 0) {
10270 USTPUTC(c, out);
10271 } else {
10272 if (dqvarnest == 0) {
10273 syntax = BASESYNTAX;
10274 dblquote = 0;
10275 }
10276 quotef++;
10277 goto quotemark;
10278 }
10279 break;
10280 case CVAR: /* '$' */
10281 PARSESUB(); /* parse substitution */
10282 break;
10283 case CENDVAR: /* '}' */
10284 if (varnest > 0) {
10285 varnest--;
10286 if (dqvarnest > 0) {
10287 dqvarnest--;
10288 }
10289 USTPUTC(CTLENDVAR, out);
10290 } else {
10291 USTPUTC(c, out);
10292 }
10293 break;
10294#ifdef CONFIG_ASH_MATH_SUPPORT
10295 case CLP: /* '(' in arithmetic */
10296 parenlevel++;
10297 USTPUTC(c, out);
10298 break;
10299 case CRP: /* ')' in arithmetic */
10300 if (parenlevel > 0) {
10301 USTPUTC(c, out);
10302 --parenlevel;
10303 } else {
10304 if (pgetc() == ')') {
10305 if (--arinest == 0) {
10306 USTPUTC(CTLENDARI, out);
10307 syntax = prevsyntax;
10308 if (syntax == DQSYNTAX)
10309 dblquote = 1;
10310 else
10311 dblquote = 0;
10312 } else
10313 USTPUTC(')', out);
10314 } else {
10315 /*
10316 * unbalanced parens
10317 * (don't 2nd guess - no error)
10318 */
10319 pungetc();
10320 USTPUTC(')', out);
10321 }
10322 }
10323 break;
10324#endif
10325 case CBQUOTE: /* '`' */
10326 PARSEBACKQOLD();
10327 break;
10328 case CENDFILE:
10329 goto endword; /* exit outer loop */
10330 case CIGN:
10331 break;
10332 default:
10333 if (varnest == 0)
10334 goto endword; /* exit outer loop */
10335#ifdef CONFIG_ASH_ALIAS
10336 if (c != PEOA)
10337#endif
10338 USTPUTC(c, out);
10339
10340 }
10341 c = pgetc_macro();
10342 }
10343 }
10344endword:
10345#ifdef CONFIG_ASH_MATH_SUPPORT
10346 if (syntax == ARISYNTAX)
10347 synerror("Missing '))'");
10348#endif
10349 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10350 synerror("Unterminated quoted string");
10351 if (varnest != 0) {
10352 startlinno = plinno;
10353 /* { */
10354 synerror("Missing '}'");
10355 }
10356 USTPUTC('\0', out);
10357 len = out - (char *)stackblock();
10358 out = stackblock();
10359 if (eofmark == NULL) {
10360 if ((c == '>' || c == '<')
10361 && quotef == 0
10362 && len <= 2
10363 && (*out == '\0' || is_digit(*out))) {
10364 PARSEREDIR();
10365 return lasttoken = TREDIR;
10366 } else {
10367 pungetc();
10368 }
10369 }
10370 quoteflag = quotef;
10371 backquotelist = bqlist;
10372 grabstackblock(len);
10373 wordtext = out;
10374 return lasttoken = TWORD;
10375/* end of readtoken routine */
10376
10377
10378
10379/*
10380 * Check to see whether we are at the end of the here document. When this
10381 * is called, c is set to the first character of the next input line. If
10382 * we are at the end of the here document, this routine sets the c to PEOF.
10383 */
10384
10385checkend: {
10386 if (eofmark) {
10387#ifdef CONFIG_ASH_ALIAS
10388 if (c == PEOA) {
10389 c = pgetc2();
10390 }
10391#endif
10392 if (striptabs) {
10393 while (c == '\t') {
10394 c = pgetc2();
10395 }
10396 }
10397 if (c == *eofmark) {
10398 if (pfgets(line, sizeof line) != NULL) {
10399 char *p, *q;
10400
10401 p = line;
10402 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10403 if (*p == '\n' && *q == '\0') {
10404 c = PEOF;
10405 plinno++;
10406 needprompt = doprompt;
10407 } else {
10408 pushstring(line, NULL);
10409 }
10410 }
10411 }
10412 }
10413 goto checkend_return;
10414}
10415
10416
10417/*
10418 * Parse a redirection operator. The variable "out" points to a string
10419 * specifying the fd to be redirected. The variable "c" contains the
10420 * first character of the redirection operator.
10421 */
10422
10423parseredir: {
10424 char fd = *out;
10425 union node *np;
10426
10427 np = (union node *)stalloc(sizeof (struct nfile));
10428 if (c == '>') {
10429 np->nfile.fd = 1;
10430 c = pgetc();
10431 if (c == '>')
10432 np->type = NAPPEND;
10433 else if (c == '|')
10434 np->type = NCLOBBER;
10435 else if (c == '&')
10436 np->type = NTOFD;
10437 else {
10438 np->type = NTO;
10439 pungetc();
10440 }
10441 } else { /* c == '<' */
10442 np->nfile.fd = 0;
10443 switch (c = pgetc()) {
10444 case '<':
10445 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10446 np = (union node *)stalloc(sizeof (struct nhere));
10447 np->nfile.fd = 0;
10448 }
10449 np->type = NHERE;
10450 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10451 heredoc->here = np;
10452 if ((c = pgetc()) == '-') {
10453 heredoc->striptabs = 1;
10454 } else {
10455 heredoc->striptabs = 0;
10456 pungetc();
10457 }
10458 break;
10459
10460 case '&':
10461 np->type = NFROMFD;
10462 break;
10463
10464 case '>':
10465 np->type = NFROMTO;
10466 break;
10467
10468 default:
10469 np->type = NFROM;
10470 pungetc();
10471 break;
10472 }
10473 }
10474 if (fd != '\0')
10475 np->nfile.fd = digit_val(fd);
10476 redirnode = np;
10477 goto parseredir_return;
10478}
10479
10480
10481/*
10482 * Parse a substitution. At this point, we have read the dollar sign
10483 * and nothing else.
10484 */
10485
10486parsesub: {
10487 int subtype;
10488 int typeloc;
10489 int flags;
10490 char *p;
10491 static const char types[] = "}-+?=";
10492
10493 c = pgetc();
10494 if (
10495 c <= PEOA_OR_PEOF ||
10496 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10497 ) {
10498 USTPUTC('$', out);
10499 pungetc();
10500 } else if (c == '(') { /* $(command) or $((arith)) */
10501 if (pgetc() == '(') {
10502#ifdef CONFIG_ASH_MATH_SUPPORT
10503 PARSEARITH();
10504#else
10505 synerror("We unsupport $((arith))");
10506#endif
10507 } else {
10508 pungetc();
10509 PARSEBACKQNEW();
10510 }
10511 } else {
10512 USTPUTC(CTLVAR, out);
10513 typeloc = out - (char *)stackblock();
10514 USTPUTC(VSNORMAL, out);
10515 subtype = VSNORMAL;
10516 if (c == '{') {
10517 c = pgetc();
10518 if (c == '#') {
10519 if ((c = pgetc()) == '}')
10520 c = '#';
10521 else
10522 subtype = VSLENGTH;
10523 }
10524 else
10525 subtype = 0;
10526 }
10527 if (c > PEOA_OR_PEOF && is_name(c)) {
10528 do {
10529 STPUTC(c, out);
10530 c = pgetc();
10531 } while (c > PEOA_OR_PEOF && is_in_name(c));
10532 } else if (is_digit(c)) {
10533 do {
10534 STPUTC(c, out);
10535 c = pgetc();
10536 } while (is_digit(c));
10537 }
10538 else if (is_special(c)) {
10539 USTPUTC(c, out);
10540 c = pgetc();
10541 }
10542 else
10543badsub: synerror("Bad substitution");
10544
10545 STPUTC('=', out);
10546 flags = 0;
10547 if (subtype == 0) {
10548 switch (c) {
10549 case ':':
10550 flags = VSNUL;
10551 c = pgetc();
10552 /*FALLTHROUGH*/
10553 default:
10554 p = strchr(types, c);
10555 if (p == NULL)
10556 goto badsub;
10557 subtype = p - types + VSNORMAL;
10558 break;
10559 case '%':
10560 case '#':
10561 {
10562 int cc = c;
10563 subtype = c == '#' ? VSTRIMLEFT :
10564 VSTRIMRIGHT;
10565 c = pgetc();
10566 if (c == cc)
10567 subtype++;
10568 else
10569 pungetc();
10570 break;
10571 }
10572 }
10573 } else {
10574 pungetc();
10575 }
10576 if (dblquote || arinest)
10577 flags |= VSQUOTE;
10578 *((char *)stackblock() + typeloc) = subtype | flags;
10579 if (subtype != VSNORMAL) {
10580 varnest++;
10581 if (dblquote || arinest) {
10582 dqvarnest++;
10583 }
10584 }
10585 }
10586 goto parsesub_return;
10587}
10588
10589
10590/*
10591 * Called to parse command substitutions. Newstyle is set if the command
10592 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10593 * list of commands (passed by reference), and savelen is the number of
10594 * characters on the top of the stack which must be preserved.
10595 */
10596
10597parsebackq: {
10598 struct nodelist **nlpp;
10599 int savepbq;
10600 union node *n;
10601 char *volatile str;
10602 struct jmploc jmploc;
10603 struct jmploc *volatile savehandler;
10604 size_t savelen;
10605 int saveprompt = 0;
10606#ifdef __GNUC__
10607 (void) &saveprompt;
10608#endif
10609
10610 savepbq = parsebackquote;
10611 if (setjmp(jmploc.loc)) {
10612 if (str)
10613 ckfree(str);
10614 parsebackquote = 0;
10615 handler = savehandler;
10616 longjmp(handler->loc, 1);
10617 }
10618 INTOFF;
10619 str = NULL;
10620 savelen = out - (char *)stackblock();
10621 if (savelen > 0) {
10622 str = ckmalloc(savelen);
10623 memcpy(str, stackblock(), savelen);
10624 }
10625 savehandler = handler;
10626 handler = &jmploc;
10627 INTON;
10628 if (oldstyle) {
10629 /* We must read until the closing backquote, giving special
10630 treatment to some slashes, and then push the string and
10631 reread it as input, interpreting it normally. */
10632 char *pout;
10633 int pc;
10634 size_t psavelen;
10635 char *pstr;
10636
10637
10638 STARTSTACKSTR(pout);
10639 for (;;) {
10640 if (needprompt) {
10641 setprompt(2);
10642 }
10643 switch (pc = pgetc()) {
10644 case '`':
10645 goto done;
10646
10647 case '\\':
10648 if ((pc = pgetc()) == '\n') {
10649 plinno++;
10650 if (doprompt)
10651 setprompt(2);
10652 /*
10653 * If eating a newline, avoid putting
10654 * the newline into the new character
10655 * stream (via the STPUTC after the
10656 * switch).
10657 */
10658 continue;
10659 }
10660 if (pc != '\\' && pc != '`' && pc != '$'
10661 && (!dblquote || pc != '"'))
10662 STPUTC('\\', pout);
10663 if (pc > PEOA_OR_PEOF) {
10664 break;
10665 }
10666 /* fall through */
10667
10668 case PEOF:
10669#ifdef CONFIG_ASH_ALIAS
10670 case PEOA:
10671#endif
10672 startlinno = plinno;
10673 synerror("EOF in backquote substitution");
10674
10675 case '\n':
10676 plinno++;
10677 needprompt = doprompt;
10678 break;
10679
10680 default:
10681 break;
10682 }
10683 STPUTC(pc, pout);
10684 }
10685done:
10686 STPUTC('\0', pout);
10687 psavelen = pout - (char *)stackblock();
10688 if (psavelen > 0) {
10689 pstr = grabstackstr(pout);
10690 setinputstring(pstr);
10691 }
10692 }
10693 nlpp = &bqlist;
10694 while (*nlpp)
10695 nlpp = &(*nlpp)->next;
10696 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10697 (*nlpp)->next = NULL;
10698 parsebackquote = oldstyle;
10699
10700 if (oldstyle) {
10701 saveprompt = doprompt;
10702 doprompt = 0;
10703 }
10704
10705 n = list(2);
10706
10707 if (oldstyle)
10708 doprompt = saveprompt;
10709 else {
10710 if (readtoken() != TRP)
10711 synexpect(TRP);
10712 }
10713
10714 (*nlpp)->n = n;
10715 if (oldstyle) {
10716 /*
10717 * Start reading from old file again, ignoring any pushed back
10718 * tokens left from the backquote parsing
10719 */
10720 popfile();
10721 tokpushback = 0;
10722 }
10723 while (stackblocksize() <= savelen)
10724 growstackblock();
10725 STARTSTACKSTR(out);
10726 if (str) {
10727 memcpy(out, str, savelen);
10728 STADJUST(savelen, out);
10729 INTOFF;
10730 ckfree(str);
10731 str = NULL;
10732 INTON;
10733 }
10734 parsebackquote = savepbq;
10735 handler = savehandler;
10736 if (arinest || dblquote)
10737 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10738 else
10739 USTPUTC(CTLBACKQ, out);
10740 if (oldstyle)
10741 goto parsebackq_oldreturn;
10742 else
10743 goto parsebackq_newreturn;
10744}
10745
10746#ifdef CONFIG_ASH_MATH_SUPPORT
10747/*
10748 * Parse an arithmetic expansion (indicate start of one and set state)
10749 */
10750parsearith: {
10751
10752 if (++arinest == 1) {
10753 prevsyntax = syntax;
10754 syntax = ARISYNTAX;
10755 USTPUTC(CTLARI, out);
10756 if (dblquote)
10757 USTPUTC('"',out);
10758 else
10759 USTPUTC(' ',out);
10760 } else {
10761 /*
10762 * we collapse embedded arithmetic expansion to
10763 * parenthesis, which should be equivalent
10764 */
10765 USTPUTC('(', out);
10766 }
10767 goto parsearith_return;
10768}
10769#endif
10770
10771} /* end of readtoken */
10772
10773
10774
10775/*
10776 * Returns true if the text contains nothing to expand (no dollar signs
10777 * or backquotes).
10778 */
10779
10780static int
10781noexpand(char *text)
10782{
10783 char *p;
10784 char c;
10785
10786 p = text;
10787 while ((c = *p++) != '\0') {
10788 if (c == CTLQUOTEMARK)
10789 continue;
10790 if (c == CTLESC)
10791 p++;
10792 else if (SIT(c, BASESYNTAX) == CCTL)
10793 return 0;
10794 }
10795 return 1;
10796}
10797
10798
10799/*
10800 * Return of a legal variable name (a letter or underscore followed by zero or
10801 * more letters, underscores, and digits).
10802 */
10803
10804static char *
10805endofname(const char *name)
10806{
10807 char *p;
10808
10809 p = (char *) name;
10810 if (! is_name(*p))
10811 return p;
10812 while (*++p) {
10813 if (! is_in_name(*p))
10814 break;
10815 }
10816 return p;
10817}
10818
10819
10820/*
10821 * Called when an unexpected token is read during the parse. The argument
10822 * is the token that is expected, or -1 if more than one type of token can
10823 * occur at this point.
10824 */
10825
10826static void synexpect(int token)
10827{
10828 char msg[64];
10829 int l;
10830
10831 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10832 if (token >= 0)
10833 sprintf(msg + l, " (expecting %s)", tokname(token));
10834 synerror(msg);
10835 /* NOTREACHED */
10836}
10837
10838static void
10839synerror(const char *msg)
10840{
10841 sh_error("Syntax error: %s", msg);
10842 /* NOTREACHED */
10843}
10844
10845
10846/*
10847 * called by editline -- any expansions to the prompt
10848 * should be added here.
10849 */
10850
10851#ifdef CONFIG_ASH_EXPAND_PRMT
10852static const char *
10853expandstr(const char *ps)
10854{
10855 union node n;
10856
10857 /* XXX Fix (char *) cast. */
10858 setinputstring((char *)ps);
10859 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10860 popfile();
10861
10862 n.narg.type = NARG;
10863 n.narg.next = NULL;
10864 n.narg.text = wordtext;
10865 n.narg.backquote = backquotelist;
10866
10867 expandarg(&n, NULL, 0);
10868 return stackblock();
10869}
10870#endif
10871
10872static void setprompt(int whichprompt)
10873{
10874 const char *prompt;
10875#ifdef CONFIG_ASH_EXPAND_PRMT
10876 struct stackmark smark;
10877#endif
10878
10879 needprompt = 0;
10880
10881 switch (whichprompt) {
10882 case 1:
10883 prompt = ps1val();
10884 break;
10885 case 2:
10886 prompt = ps2val();
10887 break;
10888 default: /* 0 */
10889 prompt = nullstr;
10890 }
10891#ifdef CONFIG_ASH_EXPAND_PRMT
10892 setstackmark(&smark);
10893 stalloc(stackblocksize());
10894#endif
10895 putprompt(expandstr(prompt));
10896#ifdef CONFIG_ASH_EXPAND_PRMT
10897 popstackmark(&smark);
10898#endif
10899}
10900
10901
10902static const char *const *findkwd(const char *s)
10903{
10904 return bsearch(s, tokname_array + KWDOFFSET,
10905 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10906 sizeof(const char *), pstrcmp);
10907}
10908
10909/* redir.c */
10910
10911/*
10912 * Code for dealing with input/output redirection.
10913 */
10914
10915#define EMPTY -2 /* marks an unused slot in redirtab */
10916#ifndef PIPE_BUF
10917# define PIPESIZE 4096 /* amount of buffering in a pipe */
10918#else
10919# define PIPESIZE PIPE_BUF
10920#endif
10921
10922/*
10923 * Open a file in noclobber mode.
10924 * The code was copied from bash.
10925 */
10926static int noclobberopen(const char *fname)
10927{
10928 int r, fd;
10929 struct stat finfo, finfo2;
10930
10931 /*
10932 * If the file exists and is a regular file, return an error
10933 * immediately.
10934 */
10935 r = stat(fname, &finfo);
10936 if (r == 0 && S_ISREG(finfo.st_mode)) {
10937 errno = EEXIST;
10938 return -1;
10939 }
10940
10941 /*
10942 * If the file was not present (r != 0), make sure we open it
10943 * exclusively so that if it is created before we open it, our open
10944 * will fail. Make sure that we do not truncate an existing file.
10945 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10946 * file was not a regular file, we leave O_EXCL off.
10947 */
10948 if (r != 0)
10949 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10950 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10951
10952 /* If the open failed, return the file descriptor right away. */
10953 if (fd < 0)
10954 return fd;
10955
10956 /*
10957 * OK, the open succeeded, but the file may have been changed from a
10958 * non-regular file to a regular file between the stat and the open.
10959 * We are assuming that the O_EXCL open handles the case where FILENAME
10960 * did not exist and is symlinked to an existing file between the stat
10961 * and open.
10962 */
10963
10964 /*
10965 * If we can open it and fstat the file descriptor, and neither check
10966 * revealed that it was a regular file, and the file has not been
10967 * replaced, return the file descriptor.
10968 */
10969 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10970 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10971 return fd;
10972
10973 /* The file has been replaced. badness. */
10974 close(fd);
10975 errno = EEXIST;
10976 return -1;
10977}
10978
10979/*
10980 * Handle here documents. Normally we fork off a process to write the
10981 * data to a pipe. If the document is short, we can stuff the data in
10982 * the pipe without forking.
10983 */
10984
10985static int openhere(union node *redir)
10986{
10987 int pip[2];
10988 size_t len = 0;
10989
10990 if (pipe(pip) < 0)
10991 sh_error("Pipe call failed");
10992 if (redir->type == NHERE) {
10993 len = strlen(redir->nhere.doc->narg.text);
10994 if (len <= PIPESIZE) {
10995 full_write(pip[1], redir->nhere.doc->narg.text, len);
10996 goto out;
10997 }
10998 }
10999 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11000 close(pip[0]);
11001 signal(SIGINT, SIG_IGN);
11002 signal(SIGQUIT, SIG_IGN);
11003 signal(SIGHUP, SIG_IGN);
11004#ifdef SIGTSTP
11005 signal(SIGTSTP, SIG_IGN);
11006#endif
11007 signal(SIGPIPE, SIG_DFL);
11008 if (redir->type == NHERE)
11009 full_write(pip[1], redir->nhere.doc->narg.text, len);
11010 else
11011 expandhere(redir->nhere.doc, pip[1]);
11012 _exit(0);
11013 }
11014out:
11015 close(pip[1]);
11016 return pip[0];
11017}
11018
11019static int
11020openredirect(union node *redir)
11021{
11022 char *fname;
11023 int f;
11024
11025 switch (redir->nfile.type) {
11026 case NFROM:
11027 fname = redir->nfile.expfname;
11028 if ((f = open(fname, O_RDONLY)) < 0)
11029 goto eopen;
11030 break;
11031 case NFROMTO:
11032 fname = redir->nfile.expfname;
11033 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11034 goto ecreate;
11035 break;
11036 case NTO:
11037 /* Take care of noclobber mode. */
11038 if (Cflag) {
11039 fname = redir->nfile.expfname;
11040 if ((f = noclobberopen(fname)) < 0)
11041 goto ecreate;
11042 break;
11043 }
11044 /* FALLTHROUGH */
11045 case NCLOBBER:
11046 fname = redir->nfile.expfname;
11047 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11048 goto ecreate;
11049 break;
11050 case NAPPEND:
11051 fname = redir->nfile.expfname;
11052 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11053 goto ecreate;
11054 break;
11055 default:
11056#if DEBUG
11057 abort();
11058#endif
11059 /* Fall through to eliminate warning. */
11060 case NTOFD:
11061 case NFROMFD:
11062 f = -1;
11063 break;
11064 case NHERE:
11065 case NXHERE:
11066 f = openhere(redir);
11067 break;
11068 }
11069
11070 return f;
11071ecreate:
11072 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11073eopen:
11074 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11075}
11076
11077static void dupredirect(union node *redir, int f)
11078{
11079 int fd = redir->nfile.fd;
11080
11081 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11082 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11083 copyfd(redir->ndup.dupfd, fd);
11084 }
11085 return;
11086 }
11087
11088 if (f != fd) {
11089 copyfd(f, fd);
11090 close(f);
11091 }
11092 return;
11093}
11094
11095/*
11096 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11097 * old file descriptors are stashed away so that the redirection can be
11098 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11099 * standard output, and the standard error if it becomes a duplicate of
11100 * stdout, is saved in memory.
11101 */
11102
11103static void
11104redirect(union node *redir, int flags)
11105{
11106 union node *n;
11107 struct redirtab *sv;
11108 int i;
11109 int fd;
11110 int newfd;
11111 int *p;
11112 nullredirs++;
11113 if (!redir) {
11114 return;
11115 }
11116 sv = NULL;
11117 INTOFF;
11118 if (flags & REDIR_PUSH) {
11119 struct redirtab *q;
11120 q = ckmalloc(sizeof (struct redirtab));
11121 q->next = redirlist;
11122 redirlist = q;
11123 q->nullredirs = nullredirs - 1;
11124 for (i = 0 ; i < 10 ; i++)
11125 q->renamed[i] = EMPTY;
11126 nullredirs = 0;
11127 sv = q;
11128 }
11129 n = redir;
11130 do {
11131 fd = n->nfile.fd;
11132 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11133 n->ndup.dupfd == fd)
11134 continue; /* redirect from/to same file descriptor */
11135
11136 newfd = openredirect(n);
11137 if (fd == newfd)
11138 continue;
11139 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11140 i = fcntl(fd, F_DUPFD, 10);
11141
11142 if (i == -1) {
11143 i = errno;
11144 if (i != EBADF) {
11145 close(newfd);
11146 errno = i;
11147 sh_error("%d: %m", fd);
11148 /* NOTREACHED */
11149 }
11150 } else {
11151 *p = i;
11152 close(fd);
11153 }
11154 } else {
11155 close(fd);
11156 }
11157 dupredirect(n, newfd);
11158 } while ((n = n->nfile.next));
11159 INTON;
11160 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11161 preverrout_fd = sv->renamed[2];
11162}
11163
11164
11165/*
11166 * Undo the effects of the last redirection.
11167 */
11168
11169void
11170popredir(int drop)
11171{
11172 struct redirtab *rp;
11173 int i;
11174
11175 if (--nullredirs >= 0)
11176 return;
11177 INTOFF;
11178 rp = redirlist;
11179 for (i = 0 ; i < 10 ; i++) {
11180 if (rp->renamed[i] != EMPTY) {
11181 if (!drop) {
11182 close(i);
11183 copyfd(rp->renamed[i], i);
11184 }
11185 close(rp->renamed[i]);
11186 }
11187 }
11188 redirlist = rp->next;
11189 nullredirs = rp->nullredirs;
11190 ckfree(rp);
11191 INTON;
11192}
11193
11194/*
11195 * Undo all redirections. Called on error or interrupt.
11196 */
11197
11198/*
11199 * Discard all saved file descriptors.
11200 */
11201
11202void
11203clearredir(int drop)
11204{
11205 for (;;) {
11206 nullredirs = 0;
11207 if (!redirlist)
11208 break;
11209 popredir(drop);
11210 }
11211}
11212
11213
11214/*
11215 * Copy a file descriptor to be >= to. Returns -1
11216 * if the source file descriptor is closed, EMPTY if there are no unused
11217 * file descriptors left.
11218 */
11219
11220int
11221copyfd(int from, int to)
11222{
11223 int newfd;
11224
11225 newfd = fcntl(from, F_DUPFD, to);
11226 if (newfd < 0) {
11227 if (errno == EMFILE)
11228 return EMPTY;
11229 else
11230 sh_error("%d: %m", from);
11231 }
11232 return newfd;
11233}
11234
11235
11236int
11237redirectsafe(union node *redir, int flags)
11238{
11239 int err;
11240 volatile int saveint;
11241 struct jmploc *volatile savehandler = handler;
11242 struct jmploc jmploc;
11243
11244 SAVEINT(saveint);
11245 if (!(err = setjmp(jmploc.loc) * 2)) {
11246 handler = &jmploc;
11247 redirect(redir, flags);
11248 }
11249 handler = savehandler;
11250 if (err && exception != EXERROR)
11251 longjmp(handler->loc, 1);
11252 RESTOREINT(saveint);
11253 return err;
11254}
11255
11256/* show.c */
11257
11258#if DEBUG
11259static void shtree(union node *, int, char *, FILE*);
11260static void shcmd(union node *, FILE *);
11261static void sharg(union node *, FILE *);
11262static void indent(int, char *, FILE *);
11263static void trstring(char *);
11264
11265
11266void
11267showtree(union node *n)
11268{
11269 trputs("showtree called\n");
11270 shtree(n, 1, NULL, stdout);
11271}
11272
11273
11274static void
11275shtree(union node *n, int ind, char *pfx, FILE *fp)
11276{
11277 struct nodelist *lp;
11278 const char *s;
11279
11280 if (n == NULL)
11281 return;
11282
11283 indent(ind, pfx, fp);
11284 switch(n->type) {
11285 case NSEMI:
11286 s = "; ";
11287 goto binop;
11288 case NAND:
11289 s = " && ";
11290 goto binop;
11291 case NOR:
11292 s = " || ";
11293binop:
11294 shtree(n->nbinary.ch1, ind, NULL, fp);
11295 /* if (ind < 0) */
11296 fputs(s, fp);
11297 shtree(n->nbinary.ch2, ind, NULL, fp);
11298 break;
11299 case NCMD:
11300 shcmd(n, fp);
11301 if (ind >= 0)
11302 putc('\n', fp);
11303 break;
11304 case NPIPE:
11305 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11306 shcmd(lp->n, fp);
11307 if (lp->next)
11308 fputs(" | ", fp);
11309 }
11310 if (n->npipe.backgnd)
11311 fputs(" &", fp);
11312 if (ind >= 0)
11313 putc('\n', fp);
11314 break;
11315 default:
11316 fprintf(fp, "<node type %d>", n->type);
11317 if (ind >= 0)
11318 putc('\n', fp);
11319 break;
11320 }
11321}
11322
11323
11324static void
11325shcmd(union node *cmd, FILE *fp)
11326{
11327 union node *np;
11328 int first;
11329 const char *s;
11330 int dftfd;
11331
11332 first = 1;
11333 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11334 if (! first)
11335 putchar(' ');
11336 sharg(np, fp);
11337 first = 0;
11338 }
11339 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11340 if (! first)
11341 putchar(' ');
11342 switch (np->nfile.type) {
11343 case NTO: s = ">"; dftfd = 1; break;
11344 case NCLOBBER: s = ">|"; dftfd = 1; break;
11345 case NAPPEND: s = ">>"; dftfd = 1; break;
11346 case NTOFD: s = ">&"; dftfd = 1; break;
11347 case NFROM: s = "<"; dftfd = 0; break;
11348 case NFROMFD: s = "<&"; dftfd = 0; break;
11349 case NFROMTO: s = "<>"; dftfd = 0; break;
11350 default: s = "*error*"; dftfd = 0; break;
11351 }
11352 if (np->nfile.fd != dftfd)
11353 fprintf(fp, "%d", np->nfile.fd);
11354 fputs(s, fp);
11355 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11356 fprintf(fp, "%d", np->ndup.dupfd);
11357 } else {
11358 sharg(np->nfile.fname, fp);
11359 }
11360 first = 0;
11361 }
11362}
11363
11364
11365
11366static void
11367sharg(union node *arg, FILE *fp)
11368{
11369 char *p;
11370 struct nodelist *bqlist;
11371 int subtype;
11372
11373 if (arg->type != NARG) {
11374 out1fmt("<node type %d>\n", arg->type);
11375 abort();
11376 }
11377 bqlist = arg->narg.backquote;
11378 for (p = arg->narg.text ; *p ; p++) {
11379 switch (*p) {
11380 case CTLESC:
11381 putc(*++p, fp);
11382 break;
11383 case CTLVAR:
11384 putc('$', fp);
11385 putc('{', fp);
11386 subtype = *++p;
11387 if (subtype == VSLENGTH)
11388 putc('#', fp);
11389
11390 while (*p != '=')
11391 putc(*p++, fp);
11392
11393 if (subtype & VSNUL)
11394 putc(':', fp);
11395
11396 switch (subtype & VSTYPE) {
11397 case VSNORMAL:
11398 putc('}', fp);
11399 break;
11400 case VSMINUS:
11401 putc('-', fp);
11402 break;
11403 case VSPLUS:
11404 putc('+', fp);
11405 break;
11406 case VSQUESTION:
11407 putc('?', fp);
11408 break;
11409 case VSASSIGN:
11410 putc('=', fp);
11411 break;
11412 case VSTRIMLEFT:
11413 putc('#', fp);
11414 break;
11415 case VSTRIMLEFTMAX:
11416 putc('#', fp);
11417 putc('#', fp);
11418 break;
11419 case VSTRIMRIGHT:
11420 putc('%', fp);
11421 break;
11422 case VSTRIMRIGHTMAX:
11423 putc('%', fp);
11424 putc('%', fp);
11425 break;
11426 case VSLENGTH:
11427 break;
11428 default:
11429 out1fmt("<subtype %d>", subtype);
11430 }
11431 break;
11432 case CTLENDVAR:
11433 putc('}', fp);
11434 break;
11435 case CTLBACKQ:
11436 case CTLBACKQ|CTLQUOTE:
11437 putc('$', fp);
11438 putc('(', fp);
11439 shtree(bqlist->n, -1, NULL, fp);
11440 putc(')', fp);
11441 break;
11442 default:
11443 putc(*p, fp);
11444 break;
11445 }
11446 }
11447}
11448
11449
11450static void
11451indent(int amount, char *pfx, FILE *fp)
11452{
11453 int i;
11454
11455 for (i = 0 ; i < amount ; i++) {
11456 if (pfx && i == amount - 1)
11457 fputs(pfx, fp);
11458 putc('\t', fp);
11459 }
11460}
11461
11462
11463
11464/*
11465 * Debugging stuff.
11466 */
11467
11468
11469FILE *tracefile;
11470
11471
11472void
11473trputc(int c)
11474{
11475 if (debug != 1)
11476 return;
11477 putc(c, tracefile);
11478}
11479
11480void
11481trace(const char *fmt, ...)
11482{
11483 va_list va;
11484
11485 if (debug != 1)
11486 return;
11487 va_start(va, fmt);
11488 (void) vfprintf(tracefile, fmt, va);
11489 va_end(va);
11490}
11491
11492void
11493tracev(const char *fmt, va_list va)
11494{
11495 if (debug != 1)
11496 return;
11497 (void) vfprintf(tracefile, fmt, va);
11498}
11499
11500
11501void
11502trputs(const char *s)
11503{
11504 if (debug != 1)
11505 return;
11506 fputs(s, tracefile);
11507}
11508
11509
11510static void
11511trstring(char *s)
11512{
11513 char *p;
11514 char c;
11515
11516 if (debug != 1)
11517 return;
11518 putc('"', tracefile);
11519 for (p = s ; *p ; p++) {
11520 switch (*p) {
11521 case '\n': c = 'n'; goto backslash;
11522 case '\t': c = 't'; goto backslash;
11523 case '\r': c = 'r'; goto backslash;
11524 case '"': c = '"'; goto backslash;
11525 case '\\': c = '\\'; goto backslash;
11526 case CTLESC: c = 'e'; goto backslash;
11527 case CTLVAR: c = 'v'; goto backslash;
11528 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11529 case CTLBACKQ: c = 'q'; goto backslash;
11530 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11531backslash: putc('\\', tracefile);
11532 putc(c, tracefile);
11533 break;
11534 default:
11535 if (*p >= ' ' && *p <= '~')
11536 putc(*p, tracefile);
11537 else {
11538 putc('\\', tracefile);
11539 putc(*p >> 6 & 03, tracefile);
11540 putc(*p >> 3 & 07, tracefile);
11541 putc(*p & 07, tracefile);
11542 }
11543 break;
11544 }
11545 }
11546 putc('"', tracefile);
11547}
11548
11549
11550void
11551trargs(char **ap)
11552{
11553 if (debug != 1)
11554 return;
11555 while (*ap) {
11556 trstring(*ap++);
11557 if (*ap)
11558 putc(' ', tracefile);
11559 else
11560 putc('\n', tracefile);
11561 }
11562}
11563
11564
11565void
11566opentrace(void)
11567{
11568 char s[100];
11569#ifdef O_APPEND
11570 int flags;
11571#endif
11572
11573 if (debug != 1) {
11574 if (tracefile)
11575 fflush(tracefile);
11576 /* leave open because libedit might be using it */
11577 return;
11578 }
11579 scopy("./trace", s);
11580 if (tracefile) {
11581 if (!freopen(s, "a", tracefile)) {
11582 fprintf(stderr, "Can't re-open %s\n", s);
11583 debug = 0;
11584 return;
11585 }
11586 } else {
11587 if ((tracefile = fopen(s, "a")) == NULL) {
11588 fprintf(stderr, "Can't open %s\n", s);
11589 debug = 0;
11590 return;
11591 }
11592 }
11593#ifdef O_APPEND
11594 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11595 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11596#endif
11597 setlinebuf(tracefile);
11598 fputs("\nTracing started.\n", tracefile);
11599}
11600#endif /* DEBUG */
11601
11602
11603/* trap.c */
11604
11605/*
11606 * Sigmode records the current value of the signal handlers for the various
11607 * modes. A value of zero means that the current handler is not known.
11608 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11609 */
11610
11611#define S_DFL 1 /* default signal handling (SIG_DFL) */
11612#define S_CATCH 2 /* signal is caught */
11613#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11614#define S_HARD_IGN 4 /* signal is ignored permenantly */
11615#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11616
11617
11618
11619/*
11620 * The trap builtin.
11621 */
11622
11623int
11624trapcmd(int argc, char **argv)
11625{
11626 char *action;
11627 char **ap;
11628 int signo;
11629
11630 nextopt(nullstr);
11631 ap = argptr;
11632 if (!*ap) {
11633 for (signo = 0 ; signo < NSIG ; signo++) {
11634 if (trap[signo] != NULL) {
11635 const char *sn;
11636
11637 sn = get_signame(signo);
11638 out1fmt("trap -- %s %s\n",
11639 single_quote(trap[signo]), sn);
11640 }
11641 }
11642 return 0;
11643 }
11644 if (!ap[1])
11645 action = NULL;
11646 else
11647 action = *ap++;
11648 while (*ap) {
11649 if ((signo = get_signum(*ap)) < 0)
11650 sh_error("%s: bad trap", *ap);
11651 INTOFF;
11652 if (action) {
11653 if (action[0] == '-' && action[1] == '\0')
11654 action = NULL;
11655 else
11656 action = savestr(action);
11657 }
11658 if (trap[signo])
11659 ckfree(trap[signo]);
11660 trap[signo] = action;
11661 if (signo != 0)
11662 setsignal(signo);
11663 INTON;
11664 ap++;
11665 }
11666 return 0;
11667}
11668
11669
11670/*
11671 * Clear traps on a fork.
11672 */
11673
11674void
11675clear_traps(void)
11676{
11677 char **tp;
11678
11679 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11680 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11681 INTOFF;
11682 ckfree(*tp);
11683 *tp = NULL;
11684 if (tp != &trap[0])
11685 setsignal(tp - trap);
11686 INTON;
11687 }
11688 }
11689}
11690
11691
11692/*
11693 * Set the signal handler for the specified signal. The routine figures
11694 * out what it should be set to.
11695 */
11696
11697void
11698setsignal(int signo)
11699{
11700 int action;
11701 char *t, tsig;
11702 struct sigaction act;
11703
11704 if ((t = trap[signo]) == NULL)
11705 action = S_DFL;
11706 else if (*t != '\0')
11707 action = S_CATCH;
11708 else
11709 action = S_IGN;
11710 if (rootshell && action == S_DFL) {
11711 switch (signo) {
11712 case SIGINT:
11713 if (iflag || minusc || sflag == 0)
11714 action = S_CATCH;
11715 break;
11716 case SIGQUIT:
11717#if DEBUG
11718 if (debug)
11719 break;
11720#endif
11721 /* FALLTHROUGH */
11722 case SIGTERM:
11723 if (iflag)
11724 action = S_IGN;
11725 break;
11726#if JOBS
11727 case SIGTSTP:
11728 case SIGTTOU:
11729 if (mflag)
11730 action = S_IGN;
11731 break;
11732#endif
11733 }
11734 }
11735
11736 t = &sigmode[signo - 1];
11737 tsig = *t;
11738 if (tsig == 0) {
11739 /*
11740 * current setting unknown
11741 */
11742 if (sigaction(signo, 0, &act) == -1) {
11743 /*
11744 * Pretend it worked; maybe we should give a warning
11745 * here, but other shells don't. We don't alter
11746 * sigmode, so that we retry every time.
11747 */
11748 return;
11749 }
11750 if (act.sa_handler == SIG_IGN) {
11751 if (mflag && (signo == SIGTSTP ||
11752 signo == SIGTTIN || signo == SIGTTOU)) {
11753 tsig = S_IGN; /* don't hard ignore these */
11754 } else
11755 tsig = S_HARD_IGN;
11756 } else {
11757 tsig = S_RESET; /* force to be set */
11758 }
11759 }
11760 if (tsig == S_HARD_IGN || tsig == action)
11761 return;
11762 switch (action) {
11763 case S_CATCH:
11764 act.sa_handler = onsig;
11765 break;
11766 case S_IGN:
11767 act.sa_handler = SIG_IGN;
11768 break;
11769 default:
11770 act.sa_handler = SIG_DFL;
11771 }
11772 *t = action;
11773 act.sa_flags = 0;
11774 sigfillset(&act.sa_mask);
11775 sigaction(signo, &act, 0);
11776}
11777
11778/*
11779 * Ignore a signal.
11780 */
11781
11782void
11783ignoresig(int signo)
11784{
11785 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11786 signal(signo, SIG_IGN);
11787 }
11788 sigmode[signo - 1] = S_HARD_IGN;
11789}
11790
11791
11792/*
11793 * Signal handler.
11794 */
11795
11796void
11797onsig(int signo)
11798{
11799 gotsig[signo - 1] = 1;
11800 pendingsigs = signo;
11801
11802 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11803 if (!suppressint)
11804 onint();
11805 intpending = 1;
11806 }
11807}
11808
11809
11810/*
11811 * Called to execute a trap. Perhaps we should avoid entering new trap
11812 * handlers while we are executing a trap handler.
11813 */
11814
11815int
11816dotrap(void)
11817{
11818 char *p;
11819 char *q;
11820 int i;
11821 int savestatus;
11822 int skip = 0;
11823
11824 savestatus = exitstatus;
11825 pendingsigs = 0;
11826 xbarrier();
11827
11828 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11829 if (!*q)
11830 continue;
11831 *q = 0;
11832
11833 p = trap[i + 1];
11834 if (!p)
11835 continue;
11836 skip = evalstring(p, SKIPEVAL);
11837 exitstatus = savestatus;
11838 if (skip)
11839 break;
11840 }
11841
11842 return skip;
11843}
11844
11845
11846/*
11847 * Controls whether the shell is interactive or not.
11848 */
11849
11850void
11851setinteractive(int on)
11852{
11853 static int is_interactive;
11854
11855 if (++on == is_interactive)
11856 return;
11857 is_interactive = on;
11858 setsignal(SIGINT);
11859 setsignal(SIGQUIT);
11860 setsignal(SIGTERM);
11861#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11862 if(is_interactive > 1) {
11863 /* Looks like they want an interactive shell */
11864 static int do_banner;
11865
11866 if(!do_banner) {
11867 out1fmt(
11868 "\n\n%s Built-in shell (ash)\n"
11869 "Enter 'help' for a list of built-in commands.\n\n",
11870 BB_BANNER);
11871 do_banner++;
11872 }
11873 }
11874#endif
11875}
11876
11877
11878#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11879/*** List the available builtins ***/
11880
11881static int helpcmd(int argc, char **argv)
11882{
11883 int col, i;
11884
11885 out1fmt("\nBuilt-in commands:\n-------------------\n");
11886 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11887 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11888 builtincmd[i].name + 1);
11889 if (col > 60) {
11890 out1fmt("\n");
11891 col = 0;
11892 }
11893 }
11894#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11895 {
11896 extern const struct BB_applet applets[];
11897 extern const size_t NUM_APPLETS;
11898
11899 for (i = 0; i < NUM_APPLETS; i++) {
11900
11901 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11902 if (col > 60) {
11903 out1fmt("\n");
11904 col = 0;
11905 }
11906 }
11907 }
11908#endif
11909 out1fmt("\n\n");
11910 return EXIT_SUCCESS;
11911}
11912#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11913
11914/*
11915 * Called to exit the shell.
11916 */
11917
11918void
11919exitshell(void)
11920{
11921 struct jmploc loc;
11922 char *p;
11923 int status;
11924
11925 status = exitstatus;
11926 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11927 if (setjmp(loc.loc)) {
11928 if (exception == EXEXIT)
11929 _exit(exitstatus);
11930 goto out;
11931 }
11932 handler = &loc;
11933 if ((p = trap[0])) {
11934 trap[0] = NULL;
11935 evalstring(p, 0);
11936 }
11937 flushall();
11938 setjobctl(0);
11939#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11940 if (iflag && rootshell) {
11941 const char *hp = lookupvar("HISTFILE");
11942
11943 if(hp != NULL )
11944 save_history ( hp );
11945 }
11946#endif
11947out:
11948 _exit(status);
11949 /* NOTREACHED */
11950}
11951
11952/* var.c */
11953
11954static struct var *vartab[VTABSIZE];
11955
11956static int vpcmp(const void *, const void *);
11957static struct var **findvar(struct var **, const char *);
11958
11959/*
11960 * Initialize the variable symbol tables and import the environment
11961 */
11962
11963
11964#ifdef CONFIG_ASH_GETOPTS
11965/*
11966 * Safe version of setvar, returns 1 on success 0 on failure.
11967 */
11968
11969int
11970setvarsafe(const char *name, const char *val, int flags)
11971{
11972 int err;
11973 volatile int saveint;
11974 struct jmploc *volatile savehandler = handler;
11975 struct jmploc jmploc;
11976
11977 SAVEINT(saveint);
11978 if (setjmp(jmploc.loc))
11979 err = 1;
11980 else {
11981 handler = &jmploc;
11982 setvar(name, val, flags);
11983 err = 0;
11984 }
11985 handler = savehandler;
11986 RESTOREINT(saveint);
11987 return err;
11988}
11989#endif
11990
11991/*
11992 * Set the value of a variable. The flags argument is ored with the
11993 * flags of the variable. If val is NULL, the variable is unset.
11994 */
11995
11996static void
11997setvar(const char *name, const char *val, int flags)
11998{
11999 char *p, *q;
12000 size_t namelen;
12001 char *nameeq;
12002 size_t vallen;
12003
12004 q = endofname(name);
12005 p = strchrnul(q, '=');
12006 namelen = p - name;
12007 if (!namelen || p != q)
12008 sh_error("%.*s: bad variable name", namelen, name);
12009 vallen = 0;
12010 if (val == NULL) {
12011 flags |= VUNSET;
12012 } else {
12013 vallen = strlen(val);
12014 }
12015 INTOFF;
12016 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12017 if (val) {
12018 *p++ = '=';
12019 p = mempcpy(p, val, vallen);
12020 }
12021 *p = '\0';
12022 setvareq(nameeq, flags | VNOSAVE);
12023 INTON;
12024}
12025
12026
12027/*
12028 * Same as setvar except that the variable and value are passed in
12029 * the first argument as name=value. Since the first argument will
12030 * be actually stored in the table, it should not be a string that
12031 * will go away.
12032 * Called with interrupts off.
12033 */
12034
12035void
12036setvareq(char *s, int flags)
12037{
12038 struct var *vp, **vpp;
12039
12040 vpp = hashvar(s);
12041 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12042 vp = *findvar(vpp, s);
12043 if (vp) {
12044 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12045 const char *n;
12046
12047 if (flags & VNOSAVE)
12048 free(s);
12049 n = vp->text;
12050 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
12051 }
12052
12053 if (flags & VNOSET)
12054 return;
12055
12056 if (vp->func && (flags & VNOFUNC) == 0)
12057 (*vp->func)(strchrnul(s, '=') + 1);
12058
12059 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12060 ckfree(vp->text);
12061
12062 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12063 } else {
12064 if (flags & VNOSET)
12065 return;
12066 /* not found */
12067 vp = ckmalloc(sizeof (*vp));
12068 vp->next = *vpp;
12069 vp->func = NULL;
12070 *vpp = vp;
12071 }
12072 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12073 s = savestr(s);
12074 vp->text = s;
12075 vp->flags = flags;
12076}
12077
12078
12079/*
12080 * Process a linked list of variable assignments.
12081 */
12082
12083static void
12084listsetvar(struct strlist *list_set_var, int flags)
12085{
12086 struct strlist *lp = list_set_var;
12087
12088 if (!lp)
12089 return;
12090 INTOFF;
12091 do {
12092 setvareq(lp->text, flags);
12093 } while ((lp = lp->next));
12094 INTON;
12095}
12096
12097
12098/*
12099 * Find the value of a variable. Returns NULL if not set.
12100 */
12101
12102static char *
12103lookupvar(const char *name)
12104{
12105 struct var *v;
12106
12107 if ((v = *findvar(hashvar(name), name))) {
12108#ifdef DYNAMIC_VAR
12109 /*
12110 * Dynamic variables are implemented roughly the same way they are
12111 * in bash. Namely, they're "special" so long as they aren't unset.
12112 * As soon as they're unset, they're no longer dynamic, and dynamic
12113 * lookup will no longer happen at that point. -- PFM.
12114 */
12115 if((v->flags & VDYNAMIC))
12116 (*v->func)(NULL);
12117#endif
12118 if(!(v->flags & VUNSET))
12119 return strchrnul(v->text, '=') + 1;
12120 }
12121
12122 return NULL;
12123}
12124
12125
12126/*
12127 * Search the environment of a builtin command.
12128 */
12129
12130static char *
12131bltinlookup(const char *name)
12132{
12133 struct strlist *sp;
12134
12135 for (sp = cmdenviron ; sp ; sp = sp->next) {
12136 if (varequal(sp->text, name))
12137 return strchrnul(sp->text, '=') + 1;
12138 }
12139 return lookupvar(name);
12140}
12141
12142
12143/*
12144 * Generate a list of variables satisfying the given conditions.
12145 */
12146
12147static char **
12148listvars(int on, int off, char ***end)
12149{
12150 struct var **vpp;
12151 struct var *vp;
12152 char **ep;
12153 int mask;
12154
12155 STARTSTACKSTR(ep);
12156 vpp = vartab;
12157 mask = on | off;
12158 do {
12159 for (vp = *vpp ; vp ; vp = vp->next)
12160 if ((vp->flags & mask) == on) {
12161 if (ep == stackstrend())
12162 ep = growstackstr();
12163 *ep++ = (char *) vp->text;
12164 }
12165 } while (++vpp < vartab + VTABSIZE);
12166 if (ep == stackstrend())
12167 ep = growstackstr();
12168 if (end)
12169 *end = ep;
12170 *ep++ = NULL;
12171 return grabstackstr(ep);
12172}
12173
12174
12175/*
12176 * POSIX requires that 'set' (but not export or readonly) output the
12177 * variables in lexicographic order - by the locale's collating order (sigh).
12178 * Maybe we could keep them in an ordered balanced binary tree
12179 * instead of hashed lists.
12180 * For now just roll 'em through qsort for printing...
12181 */
12182
12183static int
12184showvars(const char *sep_prefix, int on, int off)
12185{
12186 const char *sep;
12187 char **ep, **epend;
12188
12189 ep = listvars(on, off, &epend);
12190 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12191
12192 sep = *sep_prefix ? spcstr : sep_prefix;
12193
12194 for (; ep < epend; ep++) {
12195 const char *p;
12196 const char *q;
12197
12198 p = strchrnul(*ep, '=');
12199 q = nullstr;
12200 if (*p)
12201 q = single_quote(++p);
12202
12203 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12204 }
12205
12206 return 0;
12207}
12208
12209
12210
12211/*
12212 * The export and readonly commands.
12213 */
12214
12215static int
12216exportcmd(int argc, char **argv)
12217{
12218 struct var *vp;
12219 char *name;
12220 const char *p;
12221 char **aptr;
12222 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12223 int notp;
12224
12225 notp = nextopt("p") - 'p';
12226 if (notp && ((name = *(aptr = argptr)))) {
12227 do {
12228 if ((p = strchr(name, '=')) != NULL) {
12229 p++;
12230 } else {
12231 if ((vp = *findvar(hashvar(name), name))) {
12232 vp->flags |= flag;
12233 continue;
12234 }
12235 }
12236 setvar(name, p, flag);
12237 } while ((name = *++aptr) != NULL);
12238 } else {
12239 showvars(argv[0], flag, 0);
12240 }
12241 return 0;
12242}
12243
12244
12245/*
12246 * Make a variable a local variable. When a variable is made local, it's
12247 * value and flags are saved in a localvar structure. The saved values
12248 * will be restored when the shell function returns. We handle the name
12249 * "-" as a special case.
12250 */
12251
12252static void mklocal(char *name)
12253{
12254 struct localvar *lvp;
12255 struct var **vpp;
12256 struct var *vp;
12257
12258 INTOFF;
12259 lvp = ckmalloc(sizeof (struct localvar));
12260 if (name[0] == '-' && name[1] == '\0') {
12261 char *p;
12262 p = ckmalloc(sizeof(optlist));
12263 lvp->text = memcpy(p, optlist, sizeof(optlist));
12264 vp = NULL;
12265 } else {
12266 char *eq;
12267
12268 vpp = hashvar(name);
12269 vp = *findvar(vpp, name);
12270 eq = strchr(name, '=');
12271 if (vp == NULL) {
12272 if (eq)
12273 setvareq(name, VSTRFIXED);
12274 else
12275 setvar(name, NULL, VSTRFIXED);
12276 vp = *vpp; /* the new variable */
12277 lvp->flags = VUNSET;
12278 } else {
12279 lvp->text = vp->text;
12280 lvp->flags = vp->flags;
12281 vp->flags |= VSTRFIXED|VTEXTFIXED;
12282 if (eq)
12283 setvareq(name, 0);
12284 }
12285 }
12286 lvp->vp = vp;
12287 lvp->next = localvars;
12288 localvars = lvp;
12289 INTON;
12290}
12291
12292/*
12293 * The "local" command.
12294 */
12295
12296static int
12297localcmd(int argc, char **argv)
12298{
12299 char *name;
12300
12301 argv = argptr;
12302 while ((name = *argv++) != NULL) {
12303 mklocal(name);
12304 }
12305 return 0;
12306}
12307
12308
12309/*
12310 * Called after a function returns.
12311 * Interrupts must be off.
12312 */
12313
12314static void
12315poplocalvars(void)
12316{
12317 struct localvar *lvp;
12318 struct var *vp;
12319
12320 while ((lvp = localvars) != NULL) {
12321 localvars = lvp->next;
12322 vp = lvp->vp;
12323 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12324 if (vp == NULL) { /* $- saved */
12325 memcpy(optlist, lvp->text, sizeof(optlist));
12326 ckfree(lvp->text);
12327 optschanged();
12328 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12329 unsetvar(vp->text);
12330 } else {
12331 if (vp->func)
12332 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12333 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12334 ckfree(vp->text);
12335 vp->flags = lvp->flags;
12336 vp->text = lvp->text;
12337 }
12338 ckfree(lvp);
12339 }
12340}
12341
12342
12343/*
12344 * The unset builtin command. We unset the function before we unset the
12345 * variable to allow a function to be unset when there is a readonly variable
12346 * with the same name.
12347 */
12348
12349int
12350unsetcmd(int argc, char **argv)
12351{
12352 char **ap;
12353 int i;
12354 int flag = 0;
12355 int ret = 0;
12356
12357 while ((i = nextopt("vf")) != '\0') {
12358 flag = i;
12359 }
12360
12361 for (ap = argptr; *ap ; ap++) {
12362 if (flag != 'f') {
12363 i = unsetvar(*ap);
12364 ret |= i;
12365 if (!(i & 2))
12366 continue;
12367 }
12368 if (flag != 'v')
12369 unsetfunc(*ap);
12370 }
12371 return ret & 1;
12372}
12373
12374
12375/*
12376 * Unset the specified variable.
12377 */
12378
12379int
12380unsetvar(const char *s)
12381{
12382 struct var **vpp;
12383 struct var *vp;
12384 int retval;
12385
12386 vpp = findvar(hashvar(s), s);
12387 vp = *vpp;
12388 retval = 2;
12389 if (vp) {
12390 int flags = vp->flags;
12391
12392 retval = 1;
12393 if (flags & VREADONLY)
12394 goto out;
12395#ifdef DYNAMIC_VAR
12396 vp->flags &= ~VDYNAMIC;
12397#endif
12398 if (flags & VUNSET)
12399 goto ok;
12400 if ((flags & VSTRFIXED) == 0) {
12401 INTOFF;
12402 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12403 ckfree(vp->text);
12404 *vpp = vp->next;
12405 ckfree(vp);
12406 INTON;
12407 } else {
12408 setvar(s, 0, 0);
12409 vp->flags &= ~VEXPORT;
12410 }
12411ok:
12412 retval = 0;
12413 }
12414
12415out:
12416 return retval;
12417}
12418
12419
12420
12421/*
12422 * Find the appropriate entry in the hash table from the name.
12423 */
12424
12425static struct var **
12426hashvar(const char *p)
12427{
12428 unsigned int hashval;
12429
12430 hashval = ((unsigned char) *p) << 4;
12431 while (*p && *p != '=')
12432 hashval += (unsigned char) *p++;
12433 return &vartab[hashval % VTABSIZE];
12434}
12435
12436
12437
12438/*
12439 * Compares two strings up to the first = or '\0'. The first
12440 * string must be terminated by '='; the second may be terminated by
12441 * either '=' or '\0'.
12442 */
12443
12444int
12445varcmp(const char *p, const char *q)
12446{
12447 int c, d;
12448
12449 while ((c = *p) == (d = *q)) {
12450 if (!c || c == '=')
12451 goto out;
12452 p++;
12453 q++;
12454 }
12455 if (c == '=')
12456 c = 0;
12457 if (d == '=')
12458 d = 0;
12459out:
12460 return c - d;
12461}
12462
12463static int
12464vpcmp(const void *a, const void *b)
12465{
12466 return varcmp(*(const char **)a, *(const char **)b);
12467}
12468
12469static struct var **
12470findvar(struct var **vpp, const char *name)
12471{
12472 for (; *vpp; vpp = &(*vpp)->next) {
12473 if (varequal((*vpp)->text, name)) {
12474 break;
12475 }
12476 }
12477 return vpp;
12478}
12479/* setmode.c */
12480
12481#include <sys/times.h>
12482
12483static const unsigned char timescmd_str[] = {
12484 ' ', offsetof(struct tms, tms_utime),
12485 '\n', offsetof(struct tms, tms_stime),
12486 ' ', offsetof(struct tms, tms_cutime),
12487 '\n', offsetof(struct tms, tms_cstime),
12488 0
12489};
12490
12491static int timescmd(int ac, char **av)
12492{
12493 long int clk_tck, s, t;
12494 const unsigned char *p;
12495 struct tms buf;
12496
12497 clk_tck = sysconf(_SC_CLK_TCK);
12498 times(&buf);
12499
12500 p = timescmd_str;
12501 do {
12502 t = *(clock_t *)(((char *) &buf) + p[1]);
12503 s = t / clk_tck;
12504 out1fmt("%ldm%ld.%.3lds%c",
12505 s/60, s%60,
12506 ((t - s * clk_tck) * 1000) / clk_tck,
12507 p[0]);
12508 } while (*(p += 2));
12509
12510 return 0;
12511}
12512
12513#ifdef CONFIG_ASH_MATH_SUPPORT
12514static arith_t
12515dash_arith(const char *s)
12516{
12517 arith_t result;
12518 int errcode = 0;
12519
12520 INTOFF;
12521 result = arith(s, &errcode);
12522 if (errcode < 0) {
12523 if (errcode == -3)
12524 sh_error("exponent less than 0");
12525 else if (errcode == -2)
12526 sh_error("divide by zero");
12527 else if (errcode == -5)
12528 sh_error("expression recursion loop detected");
12529 else
12530 synerror(s);
12531 }
12532 INTON;
12533
12534 return result;
12535}
12536
12537
12538/*
12539 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12540 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12541 *
12542 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12543 */
12544
12545static int
12546letcmd(int argc, char **argv)
12547{
12548 char **ap;
12549 arith_t i = 0;
12550
12551 ap = argv + 1;
12552 if(!*ap)
12553 sh_error("expression expected");
12554 for (ap = argv + 1; *ap; ap++) {
12555 i = dash_arith(*ap);
12556 }
12557
12558 return !i;
12559}
12560#endif /* CONFIG_ASH_MATH_SUPPORT */
12561
12562/* miscbltin.c */
12563
12564/*
12565 * Miscellaneous builtins.
12566 */
12567
12568#undef rflag
12569
12570#ifdef __GLIBC__
12571#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12572typedef enum __rlimit_resource rlim_t;
12573#endif
12574#endif
12575
12576
12577/*
12578 * The read builtin. The -e option causes backslashes to escape the
12579 * following character.
12580 *
12581 * This uses unbuffered input, which may be avoidable in some cases.
12582 */
12583
12584static int
12585readcmd(int argc, char **argv)
12586{
12587 char **ap;
12588 int backslash;
12589 char c;
12590 int rflag;
12591 char *prompt;
12592 const char *ifs;
12593 char *p;
12594 int startword;
12595 int status;
12596 int i;
12597#if defined(CONFIG_ASH_READ_NCHARS)
12598 int nch_flag = 0;
12599 int nchars = 0;
12600 int silent = 0;
12601 struct termios tty, old_tty;
12602#endif
12603#if defined(CONFIG_ASH_READ_TIMEOUT)
12604 fd_set set;
12605 struct timeval ts;
12606
12607 ts.tv_sec = ts.tv_usec = 0;
12608#endif
12609
12610 rflag = 0;
12611 prompt = NULL;
12612#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12613 while ((i = nextopt("p:rt:n:s")) != '\0')
12614#elif defined(CONFIG_ASH_READ_NCHARS)
12615 while ((i = nextopt("p:rn:s")) != '\0')
12616#elif defined(CONFIG_ASH_READ_TIMEOUT)
12617 while ((i = nextopt("p:rt:")) != '\0')
12618#else
12619 while ((i = nextopt("p:r")) != '\0')
12620#endif
12621 {
12622 switch(i) {
12623 case 'p':
12624 prompt = optionarg;
12625 break;
12626#if defined(CONFIG_ASH_READ_NCHARS)
12627 case 'n':
12628 nchars = strtol(optionarg, &p, 10);
12629 if (*p)
12630 sh_error("invalid count");
12631 nch_flag = (nchars > 0);
12632 break;
12633 case 's':
12634 silent = 1;
12635 break;
12636#endif
12637#if defined(CONFIG_ASH_READ_TIMEOUT)
12638 case 't':
12639 ts.tv_sec = strtol(optionarg, &p, 10);
12640 ts.tv_usec = 0;
12641 if (*p == '.') {
12642 char *p2;
12643 if (*++p) {
12644 int scale;
12645 ts.tv_usec = strtol(p, &p2, 10);
12646 if (*p2)
12647 sh_error("invalid timeout");
12648 scale = p2 - p;
12649 /* normalize to usec */
12650 if (scale > 6)
12651 sh_error("invalid timeout");
12652 while (scale++ < 6)
12653 ts.tv_usec *= 10;
12654 }
12655 } else if (*p) {
12656 sh_error("invalid timeout");
12657 }
12658 if ( ! ts.tv_sec && ! ts.tv_usec)
12659 sh_error("invalid timeout");
12660 break;
12661#endif
12662 case 'r':
12663 rflag = 1;
12664 break;
12665 default:
12666 break;
12667 }
12668 }
12669 if (prompt && isatty(0)) {
12670 out2str(prompt);
12671 }
12672 if (*(ap = argptr) == NULL)
12673 sh_error("arg count");
12674 if ((ifs = bltinlookup("IFS")) == NULL)
12675 ifs = defifs;
12676#if defined(CONFIG_ASH_READ_NCHARS)
12677 if (nch_flag || silent) {
12678 tcgetattr(0, &tty);
12679 old_tty = tty;
12680 if (nch_flag) {
12681 tty.c_lflag &= ~ICANON;
12682 tty.c_cc[VMIN] = nchars;
12683 }
12684 if (silent) {
12685 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12686
12687 }
12688 tcsetattr(0, TCSANOW, &tty);
12689 }
12690#endif
12691#if defined(CONFIG_ASH_READ_TIMEOUT)
12692 if (ts.tv_sec || ts.tv_usec) {
12693 FD_ZERO (&set);
12694 FD_SET (0, &set);
12695
12696 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12697 if (!i) {
12698#if defined(CONFIG_ASH_READ_NCHARS)
12699 if (nch_flag)
12700 tcsetattr(0, TCSANOW, &old_tty);
12701#endif
12702 return 1;
12703 }
12704 }
12705#endif
12706 status = 0;
12707 startword = 1;
12708 backslash = 0;
12709 STARTSTACKSTR(p);
12710#if defined(CONFIG_ASH_READ_NCHARS)
12711 while (!nch_flag || nchars--)
12712#else
12713 for (;;)
12714#endif
12715 {
12716 if (read(0, &c, 1) != 1) {
12717 status = 1;
12718 break;
12719 }
12720 if (c == '\0')
12721 continue;
12722 if (backslash) {
12723 backslash = 0;
12724 if (c != '\n')
12725 goto put;
12726 continue;
12727 }
12728 if (!rflag && c == '\\') {
12729 backslash++;
12730 continue;
12731 }
12732 if (c == '\n')
12733 break;
12734 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12735 continue;
12736 }
12737 startword = 0;
12738 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12739 STACKSTRNUL(p);
12740 setvar(*ap, stackblock(), 0);
12741 ap++;
12742 startword = 1;
12743 STARTSTACKSTR(p);
12744 } else {
12745put:
12746 STPUTC(c, p);
12747 }
12748 }
12749#if defined(CONFIG_ASH_READ_NCHARS)
12750 if (nch_flag || silent)
12751 tcsetattr(0, TCSANOW, &old_tty);
12752#endif
12753
12754 STACKSTRNUL(p);
12755 /* Remove trailing blanks */
12756 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12757 *p = '\0';
12758 setvar(*ap, stackblock(), 0);
12759 while (*++ap != NULL)
12760 setvar(*ap, nullstr, 0);
12761 return status;
12762}
12763
12764
12765static int umaskcmd(int argc, char **argv)
12766{
12767 static const char permuser[3] = "ugo";
12768 static const char permmode[3] = "rwx";
12769 static const short int permmask[] = {
12770 S_IRUSR, S_IWUSR, S_IXUSR,
12771 S_IRGRP, S_IWGRP, S_IXGRP,
12772 S_IROTH, S_IWOTH, S_IXOTH
12773 };
12774
12775 char *ap;
12776 mode_t mask;
12777 int i;
12778 int symbolic_mode = 0;
12779
12780 while (nextopt("S") != '\0') {
12781 symbolic_mode = 1;
12782 }
12783
12784 INTOFF;
12785 mask = umask(0);
12786 umask(mask);
12787 INTON;
12788
12789 if ((ap = *argptr) == NULL) {
12790 if (symbolic_mode) {
12791 char buf[18];
12792 char *p = buf;
12793
12794 for (i = 0; i < 3; i++) {
12795 int j;
12796
12797 *p++ = permuser[i];
12798 *p++ = '=';
12799 for (j = 0; j < 3; j++) {
12800 if ((mask & permmask[3 * i + j]) == 0) {
12801 *p++ = permmode[j];
12802 }
12803 }
12804 *p++ = ',';
12805 }
12806 *--p = 0;
12807 puts(buf);
12808 } else {
12809 out1fmt("%.4o\n", mask);
12810 }
12811 } else {
12812 if (is_digit((unsigned char) *ap)) {
12813 mask = 0;
12814 do {
12815 if (*ap >= '8' || *ap < '0')
12816 sh_error(illnum, argv[1]);
12817 mask = (mask << 3) + (*ap - '0');
12818 } while (*++ap != '\0');
12819 umask(mask);
12820 } else {
12821 mask = ~mask & 0777;
12822 if (!bb_parse_mode(ap, &mask)) {
12823 sh_error("Illegal mode: %s", ap);
12824 }
12825 umask(~mask & 0777);
12826 }
12827 }
12828 return 0;
12829}
12830
12831/*
12832 * ulimit builtin
12833 *
12834 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12835 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12836 * ash by J.T. Conklin.
12837 *
12838 * Public domain.
12839 */
12840
12841struct limits {
12842 const char *name;
12843 int cmd;
12844 int factor; /* multiply by to get rlim_{cur,max} values */
12845 char option;
12846};
12847
12848static const struct limits limits[] = {
12849#ifdef RLIMIT_CPU
12850 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12851#endif
12852#ifdef RLIMIT_FSIZE
12853 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12854#endif
12855#ifdef RLIMIT_DATA
12856 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12857#endif
12858#ifdef RLIMIT_STACK
12859 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12860#endif
12861#ifdef RLIMIT_CORE
12862 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12863#endif
12864#ifdef RLIMIT_RSS
12865 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12866#endif
12867#ifdef RLIMIT_MEMLOCK
12868 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12869#endif
12870#ifdef RLIMIT_NPROC
12871 { "process", RLIMIT_NPROC, 1, 'p' },
12872#endif
12873#ifdef RLIMIT_NOFILE
12874 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12875#endif
12876#ifdef RLIMIT_AS
12877 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12878#endif
12879#ifdef RLIMIT_LOCKS
12880 { "locks", RLIMIT_LOCKS, 1, 'w' },
12881#endif
12882 { (char *) 0, 0, 0, '\0' }
12883};
12884
12885enum limtype { SOFT = 0x1, HARD = 0x2 };
12886
12887static void printlim(enum limtype how, const struct rlimit *limit,
12888 const struct limits *l)
12889{
12890 rlim_t val;
12891
12892 val = limit->rlim_max;
12893 if (how & SOFT)
12894 val = limit->rlim_cur;
12895
12896 if (val == RLIM_INFINITY)
12897 out1fmt("unlimited\n");
12898 else {
12899 val /= l->factor;
12900 out1fmt("%lld\n", (long long) val);
12901 }
12902}
12903
12904int
12905ulimitcmd(int argc, char **argv)
12906{
12907 int c;
12908 rlim_t val = 0;
12909 enum limtype how = SOFT | HARD;
12910 const struct limits *l;
12911 int set, all = 0;
12912 int optc, what;
12913 struct rlimit limit;
12914
12915 what = 'f';
12916 while ((optc = nextopt("HSa"
12917#ifdef RLIMIT_CPU
12918 "t"
12919#endif
12920#ifdef RLIMIT_FSIZE
12921 "f"
12922#endif
12923#ifdef RLIMIT_DATA
12924 "d"
12925#endif
12926#ifdef RLIMIT_STACK
12927 "s"
12928#endif
12929#ifdef RLIMIT_CORE
12930 "c"
12931#endif
12932#ifdef RLIMIT_RSS
12933 "m"
12934#endif
12935#ifdef RLIMIT_MEMLOCK
12936 "l"
12937#endif
12938#ifdef RLIMIT_NPROC
12939 "p"
12940#endif
12941#ifdef RLIMIT_NOFILE
12942 "n"
12943#endif
12944#ifdef RLIMIT_AS
12945 "v"
12946#endif
12947#ifdef RLIMIT_LOCKS
12948 "w"
12949#endif
12950 )) != '\0')
12951 switch (optc) {
12952 case 'H':
12953 how = HARD;
12954 break;
12955 case 'S':
12956 how = SOFT;
12957 break;
12958 case 'a':
12959 all = 1;
12960 break;
12961 default:
12962 what = optc;
12963 }
12964
12965 for (l = limits; l->option != what; l++)
12966 ;
12967
12968 set = *argptr ? 1 : 0;
12969 if (set) {
12970 char *p = *argptr;
12971
12972 if (all || argptr[1])
12973 sh_error("too many arguments");
12974 if (strncmp(p, "unlimited\n", 9) == 0)
12975 val = RLIM_INFINITY;
12976 else {
12977 val = (rlim_t) 0;
12978
12979 while ((c = *p++) >= '0' && c <= '9')
12980 {
12981 val = (val * 10) + (long)(c - '0');
12982 if (val < (rlim_t) 0)
12983 break;
12984 }
12985 if (c)
12986 sh_error("bad number");
12987 val *= l->factor;
12988 }
12989 }
12990 if (all) {
12991 for (l = limits; l->name; l++) {
12992 getrlimit(l->cmd, &limit);
12993 out1fmt("%-20s ", l->name);
12994 printlim(how, &limit, l);
12995 }
12996 return 0;
12997 }
12998
12999 getrlimit(l->cmd, &limit);
13000 if (set) {
13001 if (how & HARD)
13002 limit.rlim_max = val;
13003 if (how & SOFT)
13004 limit.rlim_cur = val;
13005 if (setrlimit(l->cmd, &limit) < 0)
13006 sh_error("error setting limit (%m)");
13007 } else {
13008 printlim(how, &limit, l);
13009 }
13010 return 0;
13011}
13012
13013
13014#ifdef CONFIG_ASH_MATH_SUPPORT
13015
13016/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
13017
13018 Permission is hereby granted, free of charge, to any person obtaining
13019 a copy of this software and associated documentation files (the
13020 "Software"), to deal in the Software without restriction, including
13021 without limitation the rights to use, copy, modify, merge, publish,
13022 distribute, sublicense, and/or sell copies of the Software, and to
13023 permit persons to whom the Software is furnished to do so, subject to
13024 the following conditions:
13025
13026 The above copyright notice and this permission notice shall be
13027 included in all copies or substantial portions of the Software.
13028
13029 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13030 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13031 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13032 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13033 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13034 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13035 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13036*/
13037
13038/* This is my infix parser/evaluator. It is optimized for size, intended
13039 * as a replacement for yacc-based parsers. However, it may well be faster
13040 * than a comparable parser written in yacc. The supported operators are
13041 * listed in #defines below. Parens, order of operations, and error handling
13042 * are supported. This code is thread safe. The exact expression format should
13043 * be that which POSIX specifies for shells. */
13044
13045/* The code uses a simple two-stack algorithm. See
13046 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
13047 * for a detailed explanation of the infix-to-postfix algorithm on which
13048 * this is based (this code differs in that it applies operators immediately
13049 * to the stack instead of adding them to a queue to end up with an
13050 * expression). */
13051
13052/* To use the routine, call it with an expression string and error return
13053 * pointer */
13054
13055/*
13056 * Aug 24, 2001 Manuel Novoa III
13057 *
13058 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13059 *
13060 * 1) In arith_apply():
13061 * a) Cached values of *numptr and &(numptr[-1]).
13062 * b) Removed redundant test for zero denominator.
13063 *
13064 * 2) In arith():
13065 * a) Eliminated redundant code for processing operator tokens by moving
13066 * to a table-based implementation. Also folded handling of parens
13067 * into the table.
13068 * b) Combined all 3 loops which called arith_apply to reduce generated
13069 * code size at the cost of speed.
13070 *
13071 * 3) The following expressions were treated as valid by the original code:
13072 * 1() , 0! , 1 ( *3 ) .
13073 * These bugs have been fixed by internally enclosing the expression in
13074 * parens and then checking that all binary ops and right parens are
13075 * preceded by a valid expression (NUM_TOKEN).
13076 *
13077 * Note: It may be desirable to replace Aaron's test for whitespace with
13078 * ctype's isspace() if it is used by another busybox applet or if additional
13079 * whitespace chars should be considered. Look below the "#include"s for a
13080 * precompiler test.
13081 */
13082
13083/*
13084 * Aug 26, 2001 Manuel Novoa III
13085 *
13086 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13087 *
13088 * Merge in Aaron's comments previously posted to the busybox list,
13089 * modified slightly to take account of my changes to the code.
13090 *
13091 */
13092
13093/*
13094 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13095 *
13096 * - allow access to variable,
13097 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13098 * - realize assign syntax (VAR=expr, +=, *= etc)
13099 * - realize exponentiation (** operator)
13100 * - realize comma separated - expr, expr
13101 * - realise ++expr --expr expr++ expr--
13102 * - realise expr ? expr : expr (but, second expr calculate always)
13103 * - allow hexadecimal and octal numbers
13104 * - was restored loses XOR operator
13105 * - remove one goto label, added three ;-)
13106 * - protect $((num num)) as true zero expr (Manuel`s error)
13107 * - always use special isspace(), see comment from bash ;-)
13108 */
13109
13110
13111#define arith_isspace(arithval) \
13112 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13113
13114
13115typedef unsigned char operator;
13116
13117/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13118 * precedence, and 3 high bits are an ID unique across operators of that
13119 * precedence. The ID portion is so that multiple operators can have the
13120 * same precedence, ensuring that the leftmost one is evaluated first.
13121 * Consider * and /. */
13122
13123#define tok_decl(prec,id) (((id)<<5)|(prec))
13124#define PREC(op) ((op) & 0x1F)
13125
13126#define TOK_LPAREN tok_decl(0,0)
13127
13128#define TOK_COMMA tok_decl(1,0)
13129
13130#define TOK_ASSIGN tok_decl(2,0)
13131#define TOK_AND_ASSIGN tok_decl(2,1)
13132#define TOK_OR_ASSIGN tok_decl(2,2)
13133#define TOK_XOR_ASSIGN tok_decl(2,3)
13134#define TOK_PLUS_ASSIGN tok_decl(2,4)
13135#define TOK_MINUS_ASSIGN tok_decl(2,5)
13136#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13137#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13138
13139#define TOK_MUL_ASSIGN tok_decl(3,0)
13140#define TOK_DIV_ASSIGN tok_decl(3,1)
13141#define TOK_REM_ASSIGN tok_decl(3,2)
13142
13143/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13144#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13145
13146/* conditional is right associativity too */
13147#define TOK_CONDITIONAL tok_decl(4,0)
13148#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13149
13150#define TOK_OR tok_decl(5,0)
13151
13152#define TOK_AND tok_decl(6,0)
13153
13154#define TOK_BOR tok_decl(7,0)
13155
13156#define TOK_BXOR tok_decl(8,0)
13157
13158#define TOK_BAND tok_decl(9,0)
13159
13160#define TOK_EQ tok_decl(10,0)
13161#define TOK_NE tok_decl(10,1)
13162
13163#define TOK_LT tok_decl(11,0)
13164#define TOK_GT tok_decl(11,1)
13165#define TOK_GE tok_decl(11,2)
13166#define TOK_LE tok_decl(11,3)
13167
13168#define TOK_LSHIFT tok_decl(12,0)
13169#define TOK_RSHIFT tok_decl(12,1)
13170
13171#define TOK_ADD tok_decl(13,0)
13172#define TOK_SUB tok_decl(13,1)
13173
13174#define TOK_MUL tok_decl(14,0)
13175#define TOK_DIV tok_decl(14,1)
13176#define TOK_REM tok_decl(14,2)
13177
13178/* exponent is right associativity */
13179#define TOK_EXPONENT tok_decl(15,1)
13180
13181/* For now unary operators. */
13182#define UNARYPREC 16
13183#define TOK_BNOT tok_decl(UNARYPREC,0)
13184#define TOK_NOT tok_decl(UNARYPREC,1)
13185
13186#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13187#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13188
13189#define PREC_PRE (UNARYPREC+2)
13190
13191#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13192#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13193
13194#define PREC_POST (UNARYPREC+3)
13195
13196#define TOK_POST_INC tok_decl(PREC_POST, 0)
13197#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13198
13199#define SPEC_PREC (UNARYPREC+4)
13200
13201#define TOK_NUM tok_decl(SPEC_PREC, 0)
13202#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13203
13204#define NUMPTR (*numstackptr)
13205
13206static int tok_have_assign(operator op)
13207{
13208 operator prec = PREC(op);
13209
13210 convert_prec_is_assing(prec);
13211 return (prec == PREC(TOK_ASSIGN) ||
13212 prec == PREC_PRE || prec == PREC_POST);
13213}
13214
13215static int is_right_associativity(operator prec)
13216{
13217 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13218 prec == PREC(TOK_CONDITIONAL));
13219}
13220
13221
13222typedef struct ARITCH_VAR_NUM {
13223 arith_t val;
13224 arith_t contidional_second_val;
13225 char contidional_second_val_initialized;
13226 char *var; /* if NULL then is regular number,
13227 else is variable name */
13228} v_n_t;
13229
13230
13231typedef struct CHK_VAR_RECURSIVE_LOOPED {
13232 const char *var;
13233 struct CHK_VAR_RECURSIVE_LOOPED *next;
13234} chk_var_recursive_looped_t;
13235
13236static chk_var_recursive_looped_t *prev_chk_var_recursive;
13237
13238
13239static int arith_lookup_val(v_n_t *t)
13240{
13241 if(t->var) {
13242 const char * p = lookupvar(t->var);
13243
13244 if(p) {
13245 int errcode;
13246
13247 /* recursive try as expression */
13248 chk_var_recursive_looped_t *cur;
13249 chk_var_recursive_looped_t cur_save;
13250
13251 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13252 if(strcmp(cur->var, t->var) == 0) {
13253 /* expression recursion loop detected */
13254 return -5;
13255 }
13256 }
13257 /* save current lookuped var name */
13258 cur = prev_chk_var_recursive;
13259 cur_save.var = t->var;
13260 cur_save.next = cur;
13261 prev_chk_var_recursive = &cur_save;
13262
13263 t->val = arith (p, &errcode);
13264 /* restore previous ptr after recursiving */
13265 prev_chk_var_recursive = cur;
13266 return errcode;
13267 } else {
13268 /* allow undefined var as 0 */
13269 t->val = 0;
13270 }
13271 }
13272 return 0;
13273}
13274
13275/* "applying" a token means performing it on the top elements on the integer
13276 * stack. For a unary operator it will only change the top element, but a
13277 * binary operator will pop two arguments and push a result */
13278static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13279{
13280 v_n_t *numptr_m1;
13281 arith_t numptr_val, rez;
13282 int ret_arith_lookup_val;
13283
13284 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13285 without arguments */
13286 numptr_m1 = NUMPTR - 1;
13287
13288 /* check operand is var with noninteger value */
13289 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13290 if(ret_arith_lookup_val)
13291 return ret_arith_lookup_val;
13292
13293 rez = numptr_m1->val;
13294 if (op == TOK_UMINUS)
13295 rez *= -1;
13296 else if (op == TOK_NOT)
13297 rez = !rez;
13298 else if (op == TOK_BNOT)
13299 rez = ~rez;
13300 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13301 rez++;
13302 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13303 rez--;
13304 else if (op != TOK_UPLUS) {
13305 /* Binary operators */
13306
13307 /* check and binary operators need two arguments */
13308 if (numptr_m1 == numstack) goto err;
13309
13310 /* ... and they pop one */
13311 --NUMPTR;
13312 numptr_val = rez;
13313 if (op == TOK_CONDITIONAL) {
13314 if(! numptr_m1->contidional_second_val_initialized) {
13315 /* protect $((expr1 ? expr2)) without ": expr" */
13316 goto err;
13317 }
13318 rez = numptr_m1->contidional_second_val;
13319 } else if(numptr_m1->contidional_second_val_initialized) {
13320 /* protect $((expr1 : expr2)) without "expr ? " */
13321 goto err;
13322 }
13323 numptr_m1 = NUMPTR - 1;
13324 if(op != TOK_ASSIGN) {
13325 /* check operand is var with noninteger value for not '=' */
13326 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13327 if(ret_arith_lookup_val)
13328 return ret_arith_lookup_val;
13329 }
13330 if (op == TOK_CONDITIONAL) {
13331 numptr_m1->contidional_second_val = rez;
13332 }
13333 rez = numptr_m1->val;
13334 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13335 rez |= numptr_val;
13336 else if (op == TOK_OR)
13337 rez = numptr_val || rez;
13338 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13339 rez &= numptr_val;
13340 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13341 rez ^= numptr_val;
13342 else if (op == TOK_AND)
13343 rez = rez && numptr_val;
13344 else if (op == TOK_EQ)
13345 rez = (rez == numptr_val);
13346 else if (op == TOK_NE)
13347 rez = (rez != numptr_val);
13348 else if (op == TOK_GE)
13349 rez = (rez >= numptr_val);
13350 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13351 rez >>= numptr_val;
13352 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13353 rez <<= numptr_val;
13354 else if (op == TOK_GT)
13355 rez = (rez > numptr_val);
13356 else if (op == TOK_LT)
13357 rez = (rez < numptr_val);
13358 else if (op == TOK_LE)
13359 rez = (rez <= numptr_val);
13360 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13361 rez *= numptr_val;
13362 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13363 rez += numptr_val;
13364 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13365 rez -= numptr_val;
13366 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13367 rez = numptr_val;
13368 else if (op == TOK_CONDITIONAL_SEP) {
13369 if (numptr_m1 == numstack) {
13370 /* protect $((expr : expr)) without "expr ? " */
13371 goto err;
13372 }
13373 numptr_m1->contidional_second_val_initialized = op;
13374 numptr_m1->contidional_second_val = numptr_val;
13375 }
13376 else if (op == TOK_CONDITIONAL) {
13377 rez = rez ?
13378 numptr_val : numptr_m1->contidional_second_val;
13379 }
13380 else if(op == TOK_EXPONENT) {
13381 if(numptr_val < 0)
13382 return -3; /* exponent less than 0 */
13383 else {
13384 arith_t c = 1;
13385
13386 if(numptr_val)
13387 while(numptr_val--)
13388 c *= rez;
13389 rez = c;
13390 }
13391 }
13392 else if(numptr_val==0) /* zero divisor check */
13393 return -2;
13394 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13395 rez /= numptr_val;
13396 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13397 rez %= numptr_val;
13398 }
13399 if(tok_have_assign(op)) {
13400 char buf[32];
13401
13402 if(numptr_m1->var == NULL) {
13403 /* Hmm, 1=2 ? */
13404 goto err;
13405 }
13406 /* save to shell variable */
13407#ifdef CONFIG_ASH_MATH_SUPPORT_64
13408 snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
13409#else
13410 snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
13411#endif
13412 setvar(numptr_m1->var, buf, 0);
13413 /* after saving, make previous value for v++ or v-- */
13414 if(op == TOK_POST_INC)
13415 rez--;
13416 else if(op == TOK_POST_DEC)
13417 rez++;
13418 }
13419 numptr_m1->val = rez;
13420 /* protect geting var value, is number now */
13421 numptr_m1->var = NULL;
13422 return 0;
13423 err:
13424 return -1;
13425}
13426
13427/* longest must first */
13428static const char op_tokens[] = {
13429 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13430 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13431 '<','<', 0, TOK_LSHIFT,
13432 '>','>', 0, TOK_RSHIFT,
13433 '|','|', 0, TOK_OR,
13434 '&','&', 0, TOK_AND,
13435 '!','=', 0, TOK_NE,
13436 '<','=', 0, TOK_LE,
13437 '>','=', 0, TOK_GE,
13438 '=','=', 0, TOK_EQ,
13439 '|','=', 0, TOK_OR_ASSIGN,
13440 '&','=', 0, TOK_AND_ASSIGN,
13441 '*','=', 0, TOK_MUL_ASSIGN,
13442 '/','=', 0, TOK_DIV_ASSIGN,
13443 '%','=', 0, TOK_REM_ASSIGN,
13444 '+','=', 0, TOK_PLUS_ASSIGN,
13445 '-','=', 0, TOK_MINUS_ASSIGN,
13446 '-','-', 0, TOK_POST_DEC,
13447 '^','=', 0, TOK_XOR_ASSIGN,
13448 '+','+', 0, TOK_POST_INC,
13449 '*','*', 0, TOK_EXPONENT,
13450 '!', 0, TOK_NOT,
13451 '<', 0, TOK_LT,
13452 '>', 0, TOK_GT,
13453 '=', 0, TOK_ASSIGN,
13454 '|', 0, TOK_BOR,
13455 '&', 0, TOK_BAND,
13456 '*', 0, TOK_MUL,
13457 '/', 0, TOK_DIV,
13458 '%', 0, TOK_REM,
13459 '+', 0, TOK_ADD,
13460 '-', 0, TOK_SUB,
13461 '^', 0, TOK_BXOR,
13462 /* uniq */
13463 '~', 0, TOK_BNOT,
13464 ',', 0, TOK_COMMA,
13465 '?', 0, TOK_CONDITIONAL,
13466 ':', 0, TOK_CONDITIONAL_SEP,
13467 ')', 0, TOK_RPAREN,
13468 '(', 0, TOK_LPAREN,
13469 0
13470};
13471/* ptr to ")" */
13472#define endexpression &op_tokens[sizeof(op_tokens)-7]
13473
13474
13475static arith_t arith (const char *expr, int *perrcode)
13476{
13477 char arithval; /* Current character under analysis */
13478 operator lasttok, op;
13479 operator prec;
13480
13481 const char *p = endexpression;
13482 int errcode;
13483
13484 size_t datasizes = strlen(expr) + 2;
13485
13486 /* Stack of integers */
13487 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13488 * in any given correct or incorrect expression is left as an exercise to
13489 * the reader. */
13490 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13491 *numstackptr = numstack;
13492 /* Stack of operator tokens */
13493 operator *stack = alloca((datasizes) * sizeof(operator)),
13494 *stackptr = stack;
13495
13496 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13497 *perrcode = errcode = 0;
13498
13499 while(1) {
13500 if ((arithval = *expr) == 0) {
13501 if (p == endexpression) {
13502 /* Null expression. */
13503 return 0;
13504 }
13505
13506 /* This is only reached after all tokens have been extracted from the
13507 * input stream. If there are still tokens on the operator stack, they
13508 * are to be applied in order. At the end, there should be a final
13509 * result on the integer stack */
13510
13511 if (expr != endexpression + 1) {
13512 /* If we haven't done so already, */
13513 /* append a closing right paren */
13514 expr = endexpression;
13515 /* and let the loop process it. */
13516 continue;
13517 }
13518 /* At this point, we're done with the expression. */
13519 if (numstackptr != numstack+1) {
13520 /* ... but if there isn't, it's bad */
13521 err:
13522 return (*perrcode = -1);
13523 }
13524 if(numstack->var) {
13525 /* expression is $((var)) only, lookup now */
13526 errcode = arith_lookup_val(numstack);
13527 }
13528 ret:
13529 *perrcode = errcode;
13530 return numstack->val;
13531 } else {
13532 /* Continue processing the expression. */
13533 if (arith_isspace(arithval)) {
13534 /* Skip whitespace */
13535 goto prologue;
13536 }
13537 if((p = endofname(expr)) != expr) {
13538 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13539
13540 numstackptr->var = alloca(var_name_size);
13541 safe_strncpy(numstackptr->var, expr, var_name_size);
13542 expr = p;
13543 num:
13544 numstackptr->contidional_second_val_initialized = 0;
13545 numstackptr++;
13546 lasttok = TOK_NUM;
13547 continue;
13548 } else if (is_digit(arithval)) {
13549 numstackptr->var = NULL;
13550#ifdef CONFIG_ASH_MATH_SUPPORT_64
13551 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13552#else
13553 numstackptr->val = strtol(expr, (char **) &expr, 0);
13554#endif
13555 goto num;
13556 }
13557 for(p = op_tokens; ; p++) {
13558 const char *o;
13559
13560 if(*p == 0) {
13561 /* strange operator not found */
13562 goto err;
13563 }
13564 for(o = expr; *p && *o == *p; p++)
13565 o++;
13566 if(! *p) {
13567 /* found */
13568 expr = o - 1;
13569 break;
13570 }
13571 /* skip tail uncompared token */
13572 while(*p)
13573 p++;
13574 /* skip zero delim */
13575 p++;
13576 }
13577 op = p[1];
13578
13579 /* post grammar: a++ reduce to num */
13580 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13581 lasttok = TOK_NUM;
13582
13583 /* Plus and minus are binary (not unary) _only_ if the last
13584 * token was as number, or a right paren (which pretends to be
13585 * a number, since it evaluates to one). Think about it.
13586 * It makes sense. */
13587 if (lasttok != TOK_NUM) {
13588 switch(op) {
13589 case TOK_ADD:
13590 op = TOK_UPLUS;
13591 break;
13592 case TOK_SUB:
13593 op = TOK_UMINUS;
13594 break;
13595 case TOK_POST_INC:
13596 op = TOK_PRE_INC;
13597 break;
13598 case TOK_POST_DEC:
13599 op = TOK_PRE_DEC;
13600 break;
13601 }
13602 }
13603 /* We don't want a unary operator to cause recursive descent on the
13604 * stack, because there can be many in a row and it could cause an
13605 * operator to be evaluated before its argument is pushed onto the
13606 * integer stack. */
13607 /* But for binary operators, "apply" everything on the operator
13608 * stack until we find an operator with a lesser priority than the
13609 * one we have just extracted. */
13610 /* Left paren is given the lowest priority so it will never be
13611 * "applied" in this way.
13612 * if associativity is right and priority eq, applied also skip
13613 */
13614 prec = PREC(op);
13615 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13616 /* not left paren or unary */
13617 if (lasttok != TOK_NUM) {
13618 /* binary op must be preceded by a num */
13619 goto err;
13620 }
13621 while (stackptr != stack) {
13622 if (op == TOK_RPAREN) {
13623 /* The algorithm employed here is simple: while we don't
13624 * hit an open paren nor the bottom of the stack, pop
13625 * tokens and apply them */
13626 if (stackptr[-1] == TOK_LPAREN) {
13627 --stackptr;
13628 /* Any operator directly after a */
13629 lasttok = TOK_NUM;
13630 /* close paren should consider itself binary */
13631 goto prologue;
13632 }
13633 } else {
13634 operator prev_prec = PREC(stackptr[-1]);
13635
13636 convert_prec_is_assing(prec);
13637 convert_prec_is_assing(prev_prec);
13638 if (prev_prec < prec)
13639 break;
13640 /* check right assoc */
13641 if(prev_prec == prec && is_right_associativity(prec))
13642 break;
13643 }
13644 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13645 if(errcode) goto ret;
13646 }
13647 if (op == TOK_RPAREN) {
13648 goto err;
13649 }
13650 }
13651
13652 /* Push this operator to the stack and remember it. */
13653 *stackptr++ = lasttok = op;
13654
13655 prologue:
13656 ++expr;
13657 }
13658 }
13659}
13660#endif /* CONFIG_ASH_MATH_SUPPORT */
13661
13662
13663#if DEBUG
13664const char *applet_name = "debug stuff usage";
13665int main(int argc, char **argv)
13666{
13667 return ash_main(argc, argv);
13668}
13669#endif
13670
13671/*-
13672 * Copyright (c) 1989, 1991, 1993, 1994
13673 * The Regents of the University of California. All rights reserved.
13674 *
13675 * This code is derived from software contributed to Berkeley by
13676 * Kenneth Almquist.
13677 *
13678 * Redistribution and use in source and binary forms, with or without
13679 * modification, are permitted provided that the following conditions
13680 * are met:
13681 * 1. Redistributions of source code must retain the above copyright
13682 * notice, this list of conditions and the following disclaimer.
13683 * 2. Redistributions in binary form must reproduce the above copyright
13684 * notice, this list of conditions and the following disclaimer in the
13685 * documentation and/or other materials provided with the distribution.
13686 * 3. Neither the name of the University nor the names of its contributors
13687 * may be used to endorse or promote products derived from this software
13688 * without specific prior written permission.
13689 *
13690 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13691 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13692 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13693 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13694 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13695 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13696 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13697 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13698 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13699 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13700 * SUCH DAMAGE.
13701 */
diff --git a/shell/bbsh.c b/shell/bbsh.c
new file mode 100644
index 000000000..99e4f61fb
--- /dev/null
+++ b/shell/bbsh.c
@@ -0,0 +1,222 @@
1/* vi: set ts=4 :
2 *
3 * bbsh - busybox shell
4 *
5 * Copyright 2006 Rob Landley <rob@landley.net>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10// A section of code that gets repeatedly or conditionally executed is stored
11// as a string and parsed each time it's run.
12
13
14
15// Wheee, debugging.
16
17// Terminal control
18#define ENABLE_BBSH_TTY 0
19
20// &, fg, bg, jobs. (ctrl-z with tty.)
21#define ENABLE_BBSH_JOBCTL 0
22
23// Flow control (if, while, for, functions { })
24#define ENABLE_BBSH_FLOWCTL 0
25
26#define ENABLE_BBSH_ENVVARS 0 // Environment variable support
27
28// Local and synthetic variables, fancy prompts, set, $?, etc.
29#define ENABLE_BBSH_LOCALVARS 0
30
31// Pipes and redirects: | > < >> << && || & () ;
32#define ENABLE_BBSH_PIPES 0
33
34/* Fun:
35
36 echo `echo hello#comment " woot` and more
37*/
38
39#include "busybox.h"
40
41// A single executable, its arguments, and other information we know about it.
42#define BBSH_FLAG_EXIT 1
43#define BBSH_FLAG_SUSPEND 2
44#define BBSH_FLAG_PIPE 4
45#define BBSH_FLAG_AND 8
46#define BBSH_FLAG_OR 16
47#define BBSH_FLAG_AMP 32
48#define BBSH_FLAG_SEMI 64
49#define BBSH_FLAG_PAREN 128
50
51// What we know about a single process.
52struct command {
53 struct command *next;
54 int flags; // exit, suspend, && ||
55 int pid; // pid (or exit code)
56 int argc;
57 char *argv[0];
58};
59
60// A collection of processes piped into/waiting on each other.
61struct pipeline {
62 struct pipeline *next;
63 int job_id;
64 struct command *cmd;
65 char *cmdline;
66 int cmdlinelen;
67};
68
69static void free_list(void *list, void (*freeit)(void *data))
70{
71 while(list) {
72 void **next = (void **)list;
73 void *list_next = *next;
74 freeit(list);
75 free(list);
76 list = list_next;
77 }
78}
79
80// Parse one word from the command line, appending one or more argv[] entries
81// to struct command. Handles environment variable substitution and
82// substrings. Returns pointer to next used byte, or NULL if it
83// hit an ending token.
84static char *parse_word(char *start, struct command **cmd)
85{
86 char *end;
87
88 // Detect end of line (and truncate line at comment)
89 if (ENABLE_BBSH_PIPES && strchr("><&|(;", *start)) return 0;
90
91 // Grab next word. (Add dequote and envvar logic here)
92 end = start;
93 while (*end && !isspace(*end)) end++;
94 (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start);
95
96 // Allocate more space if there's no room for NULL terminator.
97
98 if (!((*cmd)->argc & 7))
99 *cmd = xrealloc(*cmd,
100 sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *));
101 (*cmd)->argv[(*cmd)->argc] = 0;
102 return end;
103}
104
105// Parse a line of text into a pipeline.
106// Returns a pointer to the next line.
107
108static char *parse_pipeline(char *cmdline, struct pipeline *line)
109{
110 struct command **cmd = &(line->cmd);
111 char *start = line->cmdline = cmdline;
112
113 if (!cmdline) return 0;
114
115 if (ENABLE_BBSH_JOBCTL) line->cmdline = cmdline;
116
117 // Parse command into argv[]
118 for (;;) {
119 char *end;
120
121 // Skip leading whitespace and detect end of line.
122 start = skip_whitespace(start);
123 if (!*start || *start=='#') {
124 if (ENABLE_BBSH_JOBCTL) line->cmdlinelen = start-cmdline;
125 return 0;
126 }
127
128 // Allocate next command structure if necessary
129 if (!*cmd) *cmd = xzalloc(sizeof(struct command)+8*sizeof(char *));
130
131 // Parse next argument and add the results to argv[]
132 end = parse_word(start, cmd);
133
134 // If we hit the end of this command, how did it end?
135 if (!end) {
136 if (ENABLE_BBSH_PIPES && *start) {
137 if (*start==';') {
138 start++;
139 break;
140 }
141 // handle | & < > >> << || &&
142 }
143 break;
144 }
145 start = end;
146 }
147
148 if (ENABLE_BBSH_JOBCTL) line->cmdlinelen = start-cmdline;
149
150 return start;
151}
152
153// Execute the commands in a pipeline
154static int run_pipeline(struct pipeline *line)
155{
156 struct command *cmd = line->cmd;
157 if (!cmd || !cmd->argc) return 0;
158
159 // Handle local commands. This is totally fake and plastic.
160 if (cmd->argc==2 && !strcmp(cmd->argv[0],"cd"))
161 chdir(cmd->argv[1]);
162 else if(!strcmp(cmd->argv[0],"exit"))
163 exit(cmd->argc>1 ? atoi(cmd->argv[1]) : 0);
164 else {
165 int status;
166 pid_t pid=fork();
167 if(!pid) {
168 run_applet_by_name(cmd->argv[0],cmd->argc,cmd->argv);
169 execvp(cmd->argv[0],cmd->argv);
170 printf("No %s",cmd->argv[0]);
171 exit(1);
172 } else waitpid(pid, &status, 0);
173 }
174
175 return 0;
176}
177
178static void free_cmd(void *data)
179{
180 struct command *cmd=(struct command *)data;
181
182 while(cmd->argc) free(cmd->argv[--cmd->argc]);
183}
184
185
186static void handle(char *command)
187{
188 struct pipeline line;
189 char *start = command;
190
191 for (;;) {
192 memset(&line,0,sizeof(struct pipeline));
193 start = parse_pipeline(start, &line);
194 if (!line.cmd) break;
195
196 run_pipeline(&line);
197 free_list(line.cmd, free_cmd);
198 }
199}
200
201int bbsh_main(int argc, char *argv[])
202{
203 char *command=NULL;
204 FILE *f;
205
206 getopt32(argc, argv, "c:", &command);
207
208 f = argv[optind] ? xfopen(argv[optind],"r") : NULL;
209 if (command) handle(command);
210 else {
211 unsigned cmdlen=0;
212 for (;;) {
213 if(!f) putchar('$');
214 if(1 > getline(&command, &cmdlen,f ? : stdin)) break;
215
216 handle(command);
217 }
218 if (ENABLE_FEATURE_CLEAN_UP) free(command);
219 }
220
221 return 1;
222}
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
new file mode 100644
index 000000000..ceaa2e885
--- /dev/null
+++ b/shell/cmdedit.c
@@ -0,0 +1,1924 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Termios command line History and Editing.
4 *
5 * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
6 * Written by: Vladimir Oleynik <dzo@simtreas.ru>
7 *
8 * Used ideas:
9 * Adam Rogoyski <rogoyski@cs.utexas.edu>
10 * Dave Cinege <dcinege@psychosis.com>
11 * Jakub Jelinek (c) 1995
12 * Erik Andersen <andersen@codepoet.org> (Majorly adjusted for busybox)
13 *
14 * This code is 'as is' with no warranty.
15 *
16 *
17 */
18
19/*
20 Usage and Known bugs:
21 Terminal key codes are not extensive, and more will probably
22 need to be added. This version was created on Debian GNU/Linux 2.x.
23 Delete, Backspace, Home, End, and the arrow keys were tested
24 to work in an Xterm and console. Ctrl-A also works as Home.
25 Ctrl-E also works as End.
26
27 Small bugs (simple effect):
28 - not true viewing if terminal size (x*y symbols) less
29 size (prompt + editor`s line + 2 symbols)
30 - not true viewing if length prompt less terminal width
31 */
32
33
34#include "busybox.h"
35#include <stdio.h>
36#include <errno.h>
37#include <unistd.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/ioctl.h>
41#include <ctype.h>
42#include <signal.h>
43#include <limits.h>
44
45#include "cmdedit.h"
46
47
48#ifdef CONFIG_LOCALE_SUPPORT
49#define Isprint(c) isprint((c))
50#else
51#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') )
52#endif
53
54#ifdef TEST
55
56/* pretect redefined for test */
57#undef CONFIG_FEATURE_COMMAND_EDITING
58#undef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
59#undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
60#undef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
61#undef CONFIG_FEATURE_CLEAN_UP
62
63#define CONFIG_FEATURE_COMMAND_EDITING
64#define CONFIG_FEATURE_COMMAND_TAB_COMPLETION
65#define CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
66#define CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
67#define CONFIG_FEATURE_CLEAN_UP
68
69#endif /* TEST */
70
71#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
72#include <dirent.h>
73#include <sys/stat.h>
74#endif
75
76#ifdef CONFIG_FEATURE_COMMAND_EDITING
77
78#if defined(CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
79#define CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
80#endif
81
82/* Maximum length of the linked list for the command line history */
83#ifndef CONFIG_FEATURE_COMMAND_HISTORY
84#define MAX_HISTORY 15
85#else
86#define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0)
87#endif
88
89#if MAX_HISTORY > 0
90static char *history[MAX_HISTORY+1]; /* history + current */
91/* saved history lines */
92static int n_history;
93/* current pointer to history line */
94static int cur_history;
95#endif
96
97#include <termios.h>
98#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
99#define getTermSettings(fd,argp) tcgetattr(fd, argp);
100
101/* Current termio and the previous termio before starting sh */
102static struct termios initial_settings, new_settings;
103
104
105static
106volatile int cmdedit_termw = 80; /* actual terminal width */
107static
108volatile int handlers_sets = 0; /* Set next bites: */
109
110enum {
111 SET_ATEXIT = 1, /* when atexit() has been called
112 and get euid,uid,gid to fast compare */
113 SET_WCHG_HANDLERS = 2, /* winchg signal handler */
114 SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */
115};
116
117
118static int cmdedit_x; /* real x terminal position */
119static int cmdedit_y; /* pseudoreal y terminal position */
120static int cmdedit_prmt_len; /* lenght prompt without colores string */
121
122static int cursor; /* required global for signal handler */
123static int len; /* --- "" - - "" - -"- --""-- --""--- */
124static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */
125static
126#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
127 const
128#endif
129char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */
130
131#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
132static char *user_buf = "";
133static char *home_pwd_buf = "";
134static int my_euid;
135#endif
136
137#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
138static char *hostname_buf;
139static int num_ok_lines = 1;
140#endif
141
142
143#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
144
145#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
146static int my_euid;
147#endif
148
149static int my_uid;
150static int my_gid;
151
152#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
153
154static void cmdedit_setwidth(int w, int redraw_flg);
155
156static void win_changed(int nsig)
157{
158 static sighandler_t previous_SIGWINCH_handler; /* for reset */
159
160 /* emulate || signal call */
161 if (nsig == -SIGWINCH || nsig == SIGWINCH) {
162 int width = 0;
163 get_terminal_width_height(0, &width, NULL);
164 cmdedit_setwidth(width, nsig == SIGWINCH);
165 }
166 /* Unix not all standart in recall signal */
167
168 if (nsig == -SIGWINCH) /* save previous handler */
169 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
170 else if (nsig == SIGWINCH) /* signaled called handler */
171 signal(SIGWINCH, win_changed); /* set for next call */
172 else /* nsig == 0 */
173 /* set previous handler */
174 signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */
175}
176
177static void cmdedit_reset_term(void)
178{
179 if ((handlers_sets & SET_RESET_TERM) != 0) {
180/* sparc and other have broken termios support: use old termio handling. */
181 setTermSettings(STDIN_FILENO, (void *) &initial_settings);
182 handlers_sets &= ~SET_RESET_TERM;
183 }
184 if ((handlers_sets & SET_WCHG_HANDLERS) != 0) {
185 /* reset SIGWINCH handler to previous (default) */
186 win_changed(0);
187 handlers_sets &= ~SET_WCHG_HANDLERS;
188 }
189 fflush(stdout);
190}
191
192
193/* special for recount position for scroll and remove terminal margin effect */
194static void cmdedit_set_out_char(int next_char)
195{
196
197 int c = (int)((unsigned char) command_ps[cursor]);
198
199 if (c == 0)
200 c = ' '; /* destroy end char? */
201#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
202 if (!Isprint(c)) { /* Inverse put non-printable characters */
203 if (c >= 128)
204 c -= 128;
205 if (c < ' ')
206 c += '@';
207 if (c == 127)
208 c = '?';
209 printf("\033[7m%c\033[0m", c);
210 } else
211#endif
212 if (initial_settings.c_lflag & ECHO) putchar(c);
213 if (++cmdedit_x >= cmdedit_termw) {
214 /* terminal is scrolled down */
215 cmdedit_y++;
216 cmdedit_x = 0;
217
218 if (!next_char)
219 next_char = ' ';
220 /* destroy "(auto)margin" */
221 putchar(next_char);
222 putchar('\b');
223 }
224 cursor++;
225}
226
227/* Move to end line. Bonus: rewrite line from cursor */
228static void input_end(void)
229{
230 while (cursor < len)
231 cmdedit_set_out_char(0);
232}
233
234/* Go to the next line */
235static void goto_new_line(void)
236{
237 input_end();
238 if (cmdedit_x)
239 putchar('\n');
240}
241
242
243static void out1str(const char *s)
244{
245 if ( s )
246 fputs(s, stdout);
247}
248
249static void beep(void)
250{
251 putchar('\007');
252}
253
254/* Move back one character */
255/* special for slow terminal */
256static void input_backward(int num)
257{
258 if (num > cursor)
259 num = cursor;
260 cursor -= num; /* new cursor (in command, not terminal) */
261
262 if (cmdedit_x >= num) { /* no to up line */
263 cmdedit_x -= num;
264 if (num < 4)
265 while (num-- > 0)
266 putchar('\b');
267 else
268 printf("\033[%dD", num);
269 } else {
270 int count_y;
271
272 if (cmdedit_x) {
273 putchar('\r'); /* back to first terminal pos. */
274 num -= cmdedit_x; /* set previous backward */
275 }
276 count_y = 1 + num / cmdedit_termw;
277 printf("\033[%dA", count_y);
278 cmdedit_y -= count_y;
279 /* require forward after uping */
280 cmdedit_x = cmdedit_termw * count_y - num;
281 printf("\033[%dC", cmdedit_x); /* set term cursor */
282 }
283}
284
285static void put_prompt(void)
286{
287 out1str(cmdedit_prompt);
288 cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */
289 cursor = 0;
290 cmdedit_y = 0; /* new quasireal y */
291}
292
293#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
294static void parse_prompt(const char *prmt_ptr)
295{
296 cmdedit_prompt = prmt_ptr;
297 cmdedit_prmt_len = strlen(prmt_ptr);
298 put_prompt();
299}
300#else
301static void parse_prompt(const char *prmt_ptr)
302{
303 int prmt_len = 0;
304 size_t cur_prmt_len = 0;
305 char flg_not_length = '[';
306 char *prmt_mem_ptr = xzalloc(1);
307 char *pwd_buf = xgetcwd(0);
308 char buf2[PATH_MAX + 1];
309 char buf[2];
310 char c;
311 char *pbuf;
312
313 if (!pwd_buf) {
314 pwd_buf=(char *)bb_msg_unknown;
315 }
316
317 while (*prmt_ptr) {
318 pbuf = buf;
319 pbuf[1] = 0;
320 c = *prmt_ptr++;
321 if (c == '\\') {
322 const char *cp = prmt_ptr;
323 int l;
324
325 c = bb_process_escape_sequence(&prmt_ptr);
326 if(prmt_ptr==cp) {
327 if (*cp == 0)
328 break;
329 c = *prmt_ptr++;
330 switch (c) {
331#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
332 case 'u':
333 pbuf = user_buf;
334 break;
335#endif
336 case 'h':
337 pbuf = hostname_buf;
338 if (pbuf == 0) {
339 pbuf = xzalloc(256);
340 if (gethostname(pbuf, 255) < 0) {
341 strcpy(pbuf, "?");
342 } else {
343 char *s = strchr(pbuf, '.');
344
345 if (s)
346 *s = 0;
347 }
348 hostname_buf = pbuf;
349 }
350 break;
351 case '$':
352 c = my_euid == 0 ? '#' : '$';
353 break;
354#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
355 case 'w':
356 pbuf = pwd_buf;
357 l = strlen(home_pwd_buf);
358 if (home_pwd_buf[0] != 0 &&
359 strncmp(home_pwd_buf, pbuf, l) == 0 &&
360 (pbuf[l]=='/' || pbuf[l]=='\0') &&
361 strlen(pwd_buf+l)<PATH_MAX) {
362 pbuf = buf2;
363 *pbuf = '~';
364 strcpy(pbuf+1, pwd_buf+l);
365 }
366 break;
367#endif
368 case 'W':
369 pbuf = pwd_buf;
370 cp = strrchr(pbuf,'/');
371 if ( (cp != NULL) && (cp != pbuf) )
372 pbuf += (cp-pbuf)+1;
373 break;
374 case '!':
375 snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
376 break;
377 case 'e': case 'E': /* \e \E = \033 */
378 c = '\033';
379 break;
380 case 'x': case 'X':
381 for (l = 0; l < 3;) {
382 int h;
383 buf2[l++] = *prmt_ptr;
384 buf2[l] = 0;
385 h = strtol(buf2, &pbuf, 16);
386 if (h > UCHAR_MAX || (pbuf - buf2) < l) {
387 l--;
388 break;
389 }
390 prmt_ptr++;
391 }
392 buf2[l] = 0;
393 c = (char)strtol(buf2, 0, 16);
394 if(c==0)
395 c = '?';
396 pbuf = buf;
397 break;
398 case '[': case ']':
399 if (c == flg_not_length) {
400 flg_not_length = flg_not_length == '[' ? ']' : '[';
401 continue;
402 }
403 break;
404 }
405 }
406 }
407 if(pbuf == buf)
408 *pbuf = c;
409 cur_prmt_len = strlen(pbuf);
410 prmt_len += cur_prmt_len;
411 if (flg_not_length != ']')
412 cmdedit_prmt_len += cur_prmt_len;
413 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
414 }
415 if(pwd_buf!=(char *)bb_msg_unknown)
416 free(pwd_buf);
417 cmdedit_prompt = prmt_mem_ptr;
418 put_prompt();
419}
420#endif
421
422
423/* draw prompt, editor line, and clear tail */
424static void redraw(int y, int back_cursor)
425{
426 if (y > 0) /* up to start y */
427 printf("\033[%dA", y);
428 putchar('\r');
429 put_prompt();
430 input_end(); /* rewrite */
431 printf("\033[J"); /* destroy tail after cursor */
432 input_backward(back_cursor);
433}
434
435#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
436#define DELBUFSIZ 128
437static char *delbuf; /* a (malloced) place to store deleted characters */
438static char *delp;
439static char newdelflag; /* whether delbuf should be reused yet */
440#endif
441
442/* Delete the char in front of the cursor, optionally saving it
443 * for later putback */
444static void input_delete(int save)
445{
446 int j = cursor;
447
448 if (j == len)
449 return;
450
451#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
452 if (save) {
453 if (newdelflag) {
454 if (!delbuf)
455 delbuf = malloc(DELBUFSIZ);
456 /* safe if malloc fails */
457 delp = delbuf;
458 newdelflag = 0;
459 }
460 if (delbuf && (delp - delbuf < DELBUFSIZ))
461 *delp++ = command_ps[j];
462 }
463#endif
464
465 strcpy(command_ps + j, command_ps + j + 1);
466 len--;
467 input_end(); /* rewrite new line */
468 cmdedit_set_out_char(0); /* destroy end char */
469 input_backward(cursor - j); /* back to old pos cursor */
470}
471
472#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
473static void put(void)
474{
475 int ocursor, j = delp - delbuf;
476 if (j == 0)
477 return;
478 ocursor = cursor;
479 /* open hole and then fill it */
480 memmove(command_ps + cursor + j, command_ps + cursor, len - cursor + 1);
481 strncpy(command_ps + cursor, delbuf, j);
482 len += j;
483 input_end(); /* rewrite new line */
484 input_backward(cursor-ocursor-j+1); /* at end of new text */
485}
486#endif
487
488/* Delete the char in back of the cursor */
489static void input_backspace(void)
490{
491 if (cursor > 0) {
492 input_backward(1);
493 input_delete(0);
494 }
495}
496
497
498/* Move forward one character */
499static void input_forward(void)
500{
501 if (cursor < len)
502 cmdedit_set_out_char(command_ps[cursor + 1]);
503}
504
505static void cmdedit_setwidth(int w, int redraw_flg)
506{
507 cmdedit_termw = cmdedit_prmt_len + 2;
508 if (w <= cmdedit_termw) {
509 cmdedit_termw = cmdedit_termw % w;
510 }
511 if (w > cmdedit_termw) {
512 cmdedit_termw = w;
513
514 if (redraw_flg) {
515 /* new y for current cursor */
516 int new_y = (cursor + cmdedit_prmt_len) / w;
517
518 /* redraw */
519 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
520 fflush(stdout);
521 }
522 }
523}
524
525static void cmdedit_init(void)
526{
527 cmdedit_prmt_len = 0;
528 if ((handlers_sets & SET_WCHG_HANDLERS) == 0) {
529 /* emulate usage handler to set handler and call yours work */
530 win_changed(-SIGWINCH);
531 handlers_sets |= SET_WCHG_HANDLERS;
532 }
533
534 if ((handlers_sets & SET_ATEXIT) == 0) {
535#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
536 struct passwd *entry;
537
538 my_euid = geteuid();
539 entry = getpwuid(my_euid);
540 if (entry) {
541 user_buf = xstrdup(entry->pw_name);
542 home_pwd_buf = xstrdup(entry->pw_dir);
543 }
544#endif
545
546#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
547
548#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
549 my_euid = geteuid();
550#endif
551 my_uid = getuid();
552 my_gid = getgid();
553#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
554 handlers_sets |= SET_ATEXIT;
555 atexit(cmdedit_reset_term); /* be sure to do this only once */
556 }
557}
558
559#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
560
561static char **matches;
562static int num_matches;
563static char *add_char_to_match;
564
565static void add_match(char *matched, int add_char)
566{
567 int nm = num_matches;
568 int nm1 = nm + 1;
569
570 matches = xrealloc(matches, nm1 * sizeof(char *));
571 add_char_to_match = xrealloc(add_char_to_match, nm1);
572 matches[nm] = matched;
573 add_char_to_match[nm] = (char)add_char;
574 num_matches++;
575}
576
577static int is_execute(const struct stat *st)
578{
579 if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) ||
580 (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) ||
581 (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) ||
582 (st->st_mode & S_IXOTH)) return TRUE;
583 return FALSE;
584}
585
586#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
587
588static void username_tab_completion(char *ud, char *with_shash_flg)
589{
590 struct passwd *entry;
591 int userlen;
592
593 ud++; /* ~user/... to user/... */
594 userlen = strlen(ud);
595
596 if (with_shash_flg) { /* "~/..." or "~user/..." */
597 char *sav_ud = ud - 1;
598 char *home = 0;
599 char *temp;
600
601 if (*ud == '/') { /* "~/..." */
602 home = home_pwd_buf;
603 } else {
604 /* "~user/..." */
605 temp = strchr(ud, '/');
606 *temp = 0; /* ~user\0 */
607 entry = getpwnam(ud);
608 *temp = '/'; /* restore ~user/... */
609 ud = temp;
610 if (entry)
611 home = entry->pw_dir;
612 }
613 if (home) {
614 if ((userlen + strlen(home) + 1) < BUFSIZ) {
615 char temp2[BUFSIZ]; /* argument size */
616
617 /* /home/user/... */
618 sprintf(temp2, "%s%s", home, ud);
619 strcpy(sav_ud, temp2);
620 }
621 }
622 } else {
623 /* "~[^/]*" */
624 setpwent();
625
626 while ((entry = getpwent()) != NULL) {
627 /* Null usernames should result in all users as possible completions. */
628 if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
629 add_match(xasprintf("~%s", entry->pw_name), '/');
630 }
631 }
632
633 endpwent();
634 }
635}
636#endif /* CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION */
637
638enum {
639 FIND_EXE_ONLY = 0,
640 FIND_DIR_ONLY = 1,
641 FIND_FILE_ONLY = 2,
642};
643
644#ifdef CONFIG_ASH
645const char *cmdedit_path_lookup;
646#else
647#define cmdedit_path_lookup getenv("PATH")
648#endif
649
650static int path_parse(char ***p, int flags)
651{
652 int npth;
653 const char *tmp;
654 const char *pth;
655
656 /* if not setenv PATH variable, to search cur dir "." */
657 if (flags != FIND_EXE_ONLY || (pth = cmdedit_path_lookup) == 0 ||
658 /* PATH=<empty> or PATH=:<empty> */
659 *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) {
660 return 1;
661 }
662
663 tmp = pth;
664 npth = 0;
665
666 for (;;) {
667 npth++; /* count words is + 1 count ':' */
668 tmp = strchr(tmp, ':');
669 if (tmp) {
670 if (*++tmp == 0)
671 break; /* :<empty> */
672 } else
673 break;
674 }
675
676 *p = xmalloc(npth * sizeof(char *));
677
678 tmp = pth;
679 (*p)[0] = xstrdup(tmp);
680 npth = 1; /* count words is + 1 count ':' */
681
682 for (;;) {
683 tmp = strchr(tmp, ':');
684 if (tmp) {
685 (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */
686 if (*++tmp == 0)
687 break; /* :<empty> */
688 } else
689 break;
690 (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */
691 }
692
693 return npth;
694}
695
696static char *add_quote_for_spec_chars(char *found, int add)
697{
698 int l = 0;
699 char *s = xmalloc((strlen(found) + 1) * 2);
700
701 while (*found) {
702 if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
703 s[l++] = '\\';
704 s[l++] = *found++;
705 }
706 if(add)
707 s[l++] = (char)add;
708 s[l] = 0;
709 return s;
710}
711
712static void exe_n_cwd_tab_completion(char *command, int type)
713{
714 DIR *dir;
715 struct dirent *next;
716 char dirbuf[BUFSIZ];
717 struct stat st;
718 char *path1[1];
719 char **paths = path1;
720 int npaths;
721 int i;
722 char *found;
723 char *pfind = strrchr(command, '/');
724
725 path1[0] = ".";
726
727 if (pfind == NULL) {
728 /* no dir, if flags==EXE_ONLY - get paths, else "." */
729 npaths = path_parse(&paths, type);
730 pfind = command;
731 } else {
732 /* with dir */
733 /* save for change */
734 strcpy(dirbuf, command);
735 /* set dir only */
736 dirbuf[(pfind - command) + 1] = 0;
737#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
738 if (dirbuf[0] == '~') /* ~/... or ~user/... */
739 username_tab_completion(dirbuf, dirbuf);
740#endif
741 /* "strip" dirname in command */
742 pfind++;
743
744 paths[0] = dirbuf;
745 npaths = 1; /* only 1 dir */
746 }
747
748 for (i = 0; i < npaths; i++) {
749
750 dir = opendir(paths[i]);
751 if (!dir) /* Don't print an error */
752 continue;
753
754 while ((next = readdir(dir)) != NULL) {
755 char *str_found = next->d_name;
756 int add_chr = 0;
757
758 /* matched ? */
759 if (strncmp(str_found, pfind, strlen(pfind)))
760 continue;
761 /* not see .name without .match */
762 if (*str_found == '.' && *pfind == 0) {
763 if (*paths[i] == '/' && paths[i][1] == 0
764 && str_found[1] == 0) str_found = ""; /* only "/" */
765 else
766 continue;
767 }
768 found = concat_path_file(paths[i], str_found);
769 /* hmm, remover in progress? */
770 if (stat(found, &st) < 0)
771 goto cont;
772 /* find with dirs ? */
773 if (paths[i] != dirbuf)
774 strcpy(found, next->d_name); /* only name */
775 if (S_ISDIR(st.st_mode)) {
776 /* name is directory */
777 char *e = found + strlen(found) - 1;
778
779 add_chr = '/';
780 if(*e == '/')
781 *e = '\0';
782 } else {
783 /* not put found file if search only dirs for cd */
784 if (type == FIND_DIR_ONLY)
785 goto cont;
786 if (type == FIND_FILE_ONLY ||
787 (type == FIND_EXE_ONLY && is_execute(&st)))
788 add_chr = ' ';
789 }
790 /* Add it to the list */
791 add_match(found, add_chr);
792 continue;
793cont:
794 free(found);
795 }
796 closedir(dir);
797 }
798 if (paths != path1) {
799 free(paths[0]); /* allocated memory only in first member */
800 free(paths);
801 }
802}
803
804
805#define QUOT (UCHAR_MAX+1)
806
807#define collapse_pos(is, in) { \
808 memmove(int_buf+(is), int_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); \
809 memmove(pos_buf+(is), pos_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); }
810
811static int find_match(char *matchBuf, int *len_with_quotes)
812{
813 int i, j;
814 int command_mode;
815 int c, c2;
816 int int_buf[BUFSIZ + 1];
817 int pos_buf[BUFSIZ + 1];
818
819 /* set to integer dimension characters and own positions */
820 for (i = 0;; i++) {
821 int_buf[i] = (int) ((unsigned char) matchBuf[i]);
822 if (int_buf[i] == 0) {
823 pos_buf[i] = -1; /* indicator end line */
824 break;
825 } else
826 pos_buf[i] = i;
827 }
828
829 /* mask \+symbol and convert '\t' to ' ' */
830 for (i = j = 0; matchBuf[i]; i++, j++)
831 if (matchBuf[i] == '\\') {
832 collapse_pos(j, j + 1);
833 int_buf[j] |= QUOT;
834 i++;
835#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
836 if (matchBuf[i] == '\t') /* algorithm equivalent */
837 int_buf[j] = ' ' | QUOT;
838#endif
839 }
840#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
841 else if (matchBuf[i] == '\t')
842 int_buf[j] = ' ';
843#endif
844
845 /* mask "symbols" or 'symbols' */
846 c2 = 0;
847 for (i = 0; int_buf[i]; i++) {
848 c = int_buf[i];
849 if (c == '\'' || c == '"') {
850 if (c2 == 0)
851 c2 = c;
852 else {
853 if (c == c2)
854 c2 = 0;
855 else
856 int_buf[i] |= QUOT;
857 }
858 } else if (c2 != 0 && c != '$')
859 int_buf[i] |= QUOT;
860 }
861
862 /* skip commands with arguments if line have commands delimiters */
863 /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
864 for (i = 0; int_buf[i]; i++) {
865 c = int_buf[i];
866 c2 = int_buf[i + 1];
867 j = i ? int_buf[i - 1] : -1;
868 command_mode = 0;
869 if (c == ';' || c == '&' || c == '|') {
870 command_mode = 1 + (c == c2);
871 if (c == '&') {
872 if (j == '>' || j == '<')
873 command_mode = 0;
874 } else if (c == '|' && j == '>')
875 command_mode = 0;
876 }
877 if (command_mode) {
878 collapse_pos(0, i + command_mode);
879 i = -1; /* hack incremet */
880 }
881 }
882 /* collapse `command...` */
883 for (i = 0; int_buf[i]; i++)
884 if (int_buf[i] == '`') {
885 for (j = i + 1; int_buf[j]; j++)
886 if (int_buf[j] == '`') {
887 collapse_pos(i, j + 1);
888 j = 0;
889 break;
890 }
891 if (j) {
892 /* not found close ` - command mode, collapse all previous */
893 collapse_pos(0, i + 1);
894 break;
895 } else
896 i--; /* hack incremet */
897 }
898
899 /* collapse (command...(command...)...) or {command...{command...}...} */
900 c = 0; /* "recursive" level */
901 c2 = 0;
902 for (i = 0; int_buf[i]; i++)
903 if (int_buf[i] == '(' || int_buf[i] == '{') {
904 if (int_buf[i] == '(')
905 c++;
906 else
907 c2++;
908 collapse_pos(0, i + 1);
909 i = -1; /* hack incremet */
910 }
911 for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
912 if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
913 if (int_buf[i] == ')')
914 c--;
915 else
916 c2--;
917 collapse_pos(0, i + 1);
918 i = -1; /* hack incremet */
919 }
920
921 /* skip first not quote space */
922 for (i = 0; int_buf[i]; i++)
923 if (int_buf[i] != ' ')
924 break;
925 if (i)
926 collapse_pos(0, i);
927
928 /* set find mode for completion */
929 command_mode = FIND_EXE_ONLY;
930 for (i = 0; int_buf[i]; i++)
931 if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
932 if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
933 && matchBuf[pos_buf[0]]=='c'
934 && matchBuf[pos_buf[1]]=='d' )
935 command_mode = FIND_DIR_ONLY;
936 else {
937 command_mode = FIND_FILE_ONLY;
938 break;
939 }
940 }
941 /* "strlen" */
942 for (i = 0; int_buf[i]; i++);
943 /* find last word */
944 for (--i; i >= 0; i--) {
945 c = int_buf[i];
946 if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
947 collapse_pos(0, i + 1);
948 break;
949 }
950 }
951 /* skip first not quoted '\'' or '"' */
952 for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++);
953 /* collapse quote or unquote // or /~ */
954 while ((int_buf[i] & ~QUOT) == '/' &&
955 ((int_buf[i + 1] & ~QUOT) == '/'
956 || (int_buf[i + 1] & ~QUOT) == '~')) {
957 i++;
958 }
959
960 /* set only match and destroy quotes */
961 j = 0;
962 for (c = 0; pos_buf[i] >= 0; i++) {
963 matchBuf[c++] = matchBuf[pos_buf[i]];
964 j = pos_buf[i] + 1;
965 }
966 matchBuf[c] = 0;
967 /* old lenght matchBuf with quotes symbols */
968 *len_with_quotes = j ? j - pos_buf[0] : 0;
969
970 return command_mode;
971}
972
973/*
974 display by column original ideas from ls applet,
975 very optimize by my :)
976*/
977static void showfiles(void)
978{
979 int ncols, row;
980 int column_width = 0;
981 int nfiles = num_matches;
982 int nrows = nfiles;
983 char str_add_chr[2];
984 int l;
985
986 /* find the longest file name- use that as the column width */
987 for (row = 0; row < nrows; row++) {
988 l = strlen(matches[row]);
989 if(add_char_to_match[row])
990 l++;
991 if (column_width < l)
992 column_width = l;
993 }
994 column_width += 2; /* min space for columns */
995 ncols = cmdedit_termw / column_width;
996
997 if (ncols > 1) {
998 nrows /= ncols;
999 if(nfiles % ncols)
1000 nrows++; /* round up fractionals */
1001 } else {
1002 ncols = 1;
1003 }
1004 str_add_chr[1] = 0;
1005 for (row = 0; row < nrows; row++) {
1006 int n = row;
1007 int nc;
1008 int acol;
1009
1010 for(nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) {
1011 str_add_chr[0] = add_char_to_match[n];
1012 acol = str_add_chr[0] ? column_width - 1 : column_width;
1013 printf("%s%s", matches[n], str_add_chr);
1014 l = strlen(matches[n]);
1015 while(l < acol) {
1016 putchar(' ');
1017 l++;
1018 }
1019 }
1020 str_add_chr[0] = add_char_to_match[n];
1021 printf("%s%s\n", matches[n], str_add_chr);
1022 }
1023}
1024
1025
1026static void input_tab(int *lastWasTab)
1027{
1028 /* Do TAB completion */
1029 if (lastWasTab == 0) { /* free all memory */
1030 if (matches) {
1031 while (num_matches > 0)
1032 free(matches[--num_matches]);
1033 free(matches);
1034 matches = (char **) NULL;
1035 free(add_char_to_match);
1036 add_char_to_match = NULL;
1037 }
1038 return;
1039 }
1040 if (! *lastWasTab) {
1041
1042 char *tmp, *tmp1;
1043 int len_found;
1044 char matchBuf[BUFSIZ];
1045 int find_type;
1046 int recalc_pos;
1047
1048 *lastWasTab = TRUE; /* flop trigger */
1049
1050 /* Make a local copy of the string -- up
1051 * to the position of the cursor */
1052 tmp = strncpy(matchBuf, command_ps, cursor);
1053 tmp[cursor] = 0;
1054
1055 find_type = find_match(matchBuf, &recalc_pos);
1056
1057 /* Free up any memory already allocated */
1058 input_tab(0);
1059
1060#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
1061 /* If the word starts with `~' and there is no slash in the word,
1062 * then try completing this word as a username. */
1063
1064 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
1065 username_tab_completion(matchBuf, NULL);
1066 if (!matches)
1067#endif
1068 /* Try to match any executable in our path and everything
1069 * in the current working directory that matches. */
1070 exe_n_cwd_tab_completion(matchBuf, find_type);
1071 /* Remove duplicate found and sort */
1072 if(matches) {
1073 int i, j, n, srt;
1074 /* bubble */
1075 n = num_matches;
1076 for(i=0; i<(n-1); i++) {
1077 for(j=i+1; j<n; j++) {
1078 if(matches[i]!=NULL && matches[j]!=NULL) {
1079 srt = strcmp(matches[i], matches[j]);
1080 if(srt == 0) {
1081 free(matches[j]);
1082 matches[j]=0;
1083 } else if(srt > 0) {
1084 tmp1 = matches[i];
1085 matches[i] = matches[j];
1086 matches[j] = tmp1;
1087 srt = add_char_to_match[i];
1088 add_char_to_match[i] = add_char_to_match[j];
1089 add_char_to_match[j] = srt;
1090 }
1091 }
1092 }
1093 }
1094 j = n;
1095 n = 0;
1096 for(i=0; i<j; i++)
1097 if(matches[i]) {
1098 matches[n]=matches[i];
1099 add_char_to_match[n]=add_char_to_match[i];
1100 n++;
1101 }
1102 num_matches = n;
1103 }
1104 /* Did we find exactly one match? */
1105 if (!matches || num_matches > 1) {
1106
1107 beep();
1108 if (!matches)
1109 return; /* not found */
1110 /* find minimal match */
1111 tmp1 = xstrdup(matches[0]);
1112 for (tmp = tmp1; *tmp; tmp++)
1113 for (len_found = 1; len_found < num_matches; len_found++)
1114 if (matches[len_found][(tmp - tmp1)] != *tmp) {
1115 *tmp = 0;
1116 break;
1117 }
1118 if (*tmp1 == 0) { /* have unique */
1119 free(tmp1);
1120 return;
1121 }
1122 tmp = add_quote_for_spec_chars(tmp1, 0);
1123 free(tmp1);
1124 } else { /* one match */
1125 tmp = add_quote_for_spec_chars(matches[0], add_char_to_match[0]);
1126 /* for next completion current found */
1127 *lastWasTab = FALSE;
1128 }
1129 len_found = strlen(tmp);
1130 /* have space to placed match? */
1131 if ((len_found - strlen(matchBuf) + len) < BUFSIZ) {
1132
1133 /* before word for match */
1134 command_ps[cursor - recalc_pos] = 0;
1135 /* save tail line */
1136 strcpy(matchBuf, command_ps + cursor);
1137 /* add match */
1138 strcat(command_ps, tmp);
1139 /* add tail */
1140 strcat(command_ps, matchBuf);
1141 /* back to begin word for match */
1142 input_backward(recalc_pos);
1143 /* new pos */
1144 recalc_pos = cursor + len_found;
1145 /* new len */
1146 len = strlen(command_ps);
1147 /* write out the matched command */
1148 redraw(cmdedit_y, len - recalc_pos);
1149 }
1150 free(tmp);
1151 } else {
1152 /* Ok -- the last char was a TAB. Since they
1153 * just hit TAB again, print a list of all the
1154 * available choices... */
1155 if (matches && num_matches > 0) {
1156 int sav_cursor = cursor; /* change goto_new_line() */
1157
1158 /* Go to the next line */
1159 goto_new_line();
1160 showfiles();
1161 redraw(0, len - sav_cursor);
1162 }
1163 }
1164}
1165#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
1166
1167#if MAX_HISTORY > 0
1168static void get_previous_history(void)
1169{
1170 if(command_ps[0] != 0 || history[cur_history] == 0) {
1171 free(history[cur_history]);
1172 history[cur_history] = xstrdup(command_ps);
1173 }
1174 cur_history--;
1175}
1176
1177static int get_next_history(void)
1178{
1179 int ch = cur_history;
1180
1181 if (ch < n_history) {
1182 get_previous_history(); /* save the current history line */
1183 cur_history = ch + 1;
1184 return cur_history;
1185 } else {
1186 beep();
1187 return 0;
1188 }
1189}
1190
1191#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1192void load_history ( const char *fromfile )
1193{
1194 FILE *fp;
1195 int hi;
1196
1197 /* cleanup old */
1198
1199 for(hi = n_history; hi > 0; ) {
1200 hi--;
1201 free ( history [hi] );
1202 }
1203
1204 if (( fp = fopen ( fromfile, "r" ))) {
1205
1206 for ( hi = 0; hi < MAX_HISTORY; ) {
1207 char * hl = xmalloc_getline(fp);
1208 int l;
1209
1210 if(!hl)
1211 break;
1212 l = strlen(hl);
1213 if(l >= BUFSIZ)
1214 hl[BUFSIZ-1] = 0;
1215 if(l == 0 || hl[0] == ' ') {
1216 free(hl);
1217 continue;
1218 }
1219 history [hi++] = hl;
1220 }
1221 fclose ( fp );
1222 }
1223 cur_history = n_history = hi;
1224}
1225
1226void save_history ( const char *tofile )
1227{
1228 FILE *fp = fopen ( tofile, "w" );
1229
1230 if ( fp ) {
1231 int i;
1232
1233 for ( i = 0; i < n_history; i++ ) {
1234 fprintf(fp, "%s\n", history [i]);
1235 }
1236 fclose ( fp );
1237 }
1238}
1239#endif
1240
1241#endif
1242
1243enum {
1244 ESC = 27,
1245 DEL = 127,
1246};
1247
1248
1249/*
1250 * This function is used to grab a character buffer
1251 * from the input file descriptor and allows you to
1252 * a string with full command editing (sort of like
1253 * a mini readline).
1254 *
1255 * The following standard commands are not implemented:
1256 * ESC-b -- Move back one word
1257 * ESC-f -- Move forward one word
1258 * ESC-d -- Delete back one word
1259 * ESC-h -- Delete forward one word
1260 * CTL-t -- Transpose two characters
1261 *
1262 * Minimalist vi-style command line editing available if configured.
1263 * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us>
1264 *
1265 */
1266
1267#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
1268static int vi_mode;
1269
1270void setvimode ( int viflag )
1271{
1272 vi_mode = viflag;
1273}
1274
1275static void
1276vi_Word_motion(char *command, int eat)
1277{
1278 while (cursor < len && !isspace(command[cursor]))
1279 input_forward();
1280 if (eat) while (cursor < len && isspace(command[cursor]))
1281 input_forward();
1282}
1283
1284static void
1285vi_word_motion(char *command, int eat)
1286{
1287 if (isalnum(command[cursor]) || command[cursor] == '_') {
1288 while (cursor < len &&
1289 (isalnum(command[cursor+1]) ||
1290 command[cursor+1] == '_'))
1291 input_forward();
1292 } else if (ispunct(command[cursor])) {
1293 while (cursor < len &&
1294 (ispunct(command[cursor+1])))
1295 input_forward();
1296 }
1297
1298 if (cursor < len)
1299 input_forward();
1300
1301 if (eat && cursor < len && isspace(command[cursor]))
1302 while (cursor < len && isspace(command[cursor]))
1303 input_forward();
1304}
1305
1306static void
1307vi_End_motion(char *command)
1308{
1309 input_forward();
1310 while (cursor < len && isspace(command[cursor]))
1311 input_forward();
1312 while (cursor < len-1 && !isspace(command[cursor+1]))
1313 input_forward();
1314}
1315
1316static void
1317vi_end_motion(char *command)
1318{
1319 if (cursor >= len-1)
1320 return;
1321 input_forward();
1322 while (cursor < len-1 && isspace(command[cursor]))
1323 input_forward();
1324 if (cursor >= len-1)
1325 return;
1326 if (isalnum(command[cursor]) || command[cursor] == '_') {
1327 while (cursor < len-1 &&
1328 (isalnum(command[cursor+1]) ||
1329 command[cursor+1] == '_'))
1330 input_forward();
1331 } else if (ispunct(command[cursor])) {
1332 while (cursor < len-1 &&
1333 (ispunct(command[cursor+1])))
1334 input_forward();
1335 }
1336}
1337
1338static void
1339vi_Back_motion(char *command)
1340{
1341 while (cursor > 0 && isspace(command[cursor-1]))
1342 input_backward(1);
1343 while (cursor > 0 && !isspace(command[cursor-1]))
1344 input_backward(1);
1345}
1346
1347static void
1348vi_back_motion(char *command)
1349{
1350 if (cursor <= 0)
1351 return;
1352 input_backward(1);
1353 while (cursor > 0 && isspace(command[cursor]))
1354 input_backward(1);
1355 if (cursor <= 0)
1356 return;
1357 if (isalnum(command[cursor]) || command[cursor] == '_') {
1358 while (cursor > 0 &&
1359 (isalnum(command[cursor-1]) ||
1360 command[cursor-1] == '_'))
1361 input_backward(1);
1362 } else if (ispunct(command[cursor])) {
1363 while (cursor > 0 &&
1364 (ispunct(command[cursor-1])))
1365 input_backward(1);
1366 }
1367}
1368#endif
1369
1370/*
1371 * the emacs and vi modes share much of the code in the big
1372 * command loop. commands entered when in vi's command mode (aka
1373 * "escape mode") get an extra bit added to distinguish them --
1374 * this keeps them from being self-inserted. this clutters the
1375 * big switch a bit, but keeps all the code in one place.
1376 */
1377
1378#define vbit 0x100
1379
1380/* leave out the "vi-mode"-only case labels if vi editing isn't
1381 * configured. */
1382#define vi_case(caselabel) USE_FEATURE_COMMAND_EDITING(caselabel)
1383
1384/* convert uppercase ascii to equivalent control char, for readability */
1385#define CNTRL(uc_char) ((uc_char) - 0x40)
1386
1387
1388int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1389{
1390
1391 int break_out = 0;
1392 int lastWasTab = FALSE;
1393 unsigned char c;
1394 unsigned int ic;
1395#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
1396 unsigned int prevc;
1397 int vi_cmdmode = 0;
1398#endif
1399 /* prepare before init handlers */
1400 cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */
1401 len = 0;
1402 command_ps = command;
1403
1404 getTermSettings(0, (void *) &initial_settings);
1405 memcpy(&new_settings, &initial_settings, sizeof(struct termios));
1406 new_settings.c_lflag &= ~ICANON; /* unbuffered input */
1407 /* Turn off echoing and CTRL-C, so we can trap it */
1408 new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
1409 /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
1410 new_settings.c_cc[VMIN] = 1;
1411 new_settings.c_cc[VTIME] = 0;
1412 /* Turn off CTRL-C, so we can trap it */
1413# ifndef _POSIX_VDISABLE
1414# define _POSIX_VDISABLE '\0'
1415# endif
1416 new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
1417 command[0] = 0;
1418
1419 setTermSettings(0, (void *) &new_settings);
1420 handlers_sets |= SET_RESET_TERM;
1421
1422 /* Now initialize things */
1423 cmdedit_init();
1424 /* Print out the command prompt */
1425 parse_prompt(prompt);
1426
1427 while (1) {
1428
1429 fflush(stdout); /* buffered out to fast */
1430
1431 if (safe_read(0, &c, 1) < 1)
1432 /* if we can't read input then exit */
1433 goto prepare_to_die;
1434
1435 ic = c;
1436
1437#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
1438 newdelflag = 1;
1439 if (vi_cmdmode)
1440 ic |= vbit;
1441#endif
1442 switch (ic)
1443 {
1444 case '\n':
1445 case '\r':
1446 vi_case( case '\n'|vbit: )
1447 vi_case( case '\r'|vbit: )
1448 /* Enter */
1449 goto_new_line();
1450 break_out = 1;
1451 break;
1452 case CNTRL('A'):
1453 vi_case( case '0'|vbit: )
1454 /* Control-a -- Beginning of line */
1455 input_backward(cursor);
1456 break;
1457 case CNTRL('B'):
1458 vi_case( case 'h'|vbit: )
1459 vi_case( case '\b'|vbit: )
1460 vi_case( case DEL|vbit: )
1461 /* Control-b -- Move back one character */
1462 input_backward(1);
1463 break;
1464 case CNTRL('C'):
1465 vi_case( case CNTRL('C')|vbit: )
1466 /* Control-c -- stop gathering input */
1467 goto_new_line();
1468#ifndef CONFIG_ASH
1469 command[0] = 0;
1470 len = 0;
1471 lastWasTab = FALSE;
1472 put_prompt();
1473#else
1474 len = 0;
1475 break_out = -1; /* to control traps */
1476#endif
1477 break;
1478 case CNTRL('D'):
1479 /* Control-d -- Delete one character, or exit
1480 * if the len=0 and no chars to delete */
1481 if (len == 0) {
1482 errno = 0;
1483prepare_to_die:
1484#if !defined(CONFIG_ASH)
1485 printf("exit");
1486 goto_new_line();
1487 /* cmdedit_reset_term() called in atexit */
1488 exit(EXIT_SUCCESS);
1489#else
1490 /* to control stopped jobs */
1491 len = break_out = -1;
1492 break;
1493#endif
1494 } else {
1495 input_delete(0);
1496 }
1497 break;
1498 case CNTRL('E'):
1499 vi_case( case '$'|vbit: )
1500 /* Control-e -- End of line */
1501 input_end();
1502 break;
1503 case CNTRL('F'):
1504 vi_case( case 'l'|vbit: )
1505 vi_case( case ' '|vbit: )
1506 /* Control-f -- Move forward one character */
1507 input_forward();
1508 break;
1509 case '\b':
1510 case DEL:
1511 /* Control-h and DEL */
1512 input_backspace();
1513 break;
1514 case '\t':
1515#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
1516 input_tab(&lastWasTab);
1517#endif
1518 break;
1519 case CNTRL('K'):
1520 /* Control-k -- clear to end of line */
1521 *(command + cursor) = 0;
1522 len = cursor;
1523 printf("\033[J");
1524 break;
1525 case CNTRL('L'):
1526 vi_case( case CNTRL('L')|vbit: )
1527 /* Control-l -- clear screen */
1528 printf("\033[H");
1529 redraw(0, len-cursor);
1530 break;
1531#if MAX_HISTORY > 0
1532 case CNTRL('N'):
1533 vi_case( case CNTRL('N')|vbit: )
1534 vi_case( case 'j'|vbit: )
1535 /* Control-n -- Get next command in history */
1536 if (get_next_history())
1537 goto rewrite_line;
1538 break;
1539 case CNTRL('P'):
1540 vi_case( case CNTRL('P')|vbit: )
1541 vi_case( case 'k'|vbit: )
1542 /* Control-p -- Get previous command from history */
1543 if (cur_history > 0) {
1544 get_previous_history();
1545 goto rewrite_line;
1546 } else {
1547 beep();
1548 }
1549 break;
1550#endif
1551 case CNTRL('U'):
1552 vi_case( case CNTRL('U')|vbit: )
1553 /* Control-U -- Clear line before cursor */
1554 if (cursor) {
1555 strcpy(command, command + cursor);
1556 redraw(cmdedit_y, len -= cursor);
1557 }
1558 break;
1559 case CNTRL('W'):
1560 vi_case( case CNTRL('W')|vbit: )
1561 /* Control-W -- Remove the last word */
1562 while (cursor > 0 && isspace(command[cursor-1]))
1563 input_backspace();
1564 while (cursor > 0 &&!isspace(command[cursor-1]))
1565 input_backspace();
1566 break;
1567#if ENABLE_FEATURE_COMMAND_EDITING_VI
1568 case 'i'|vbit:
1569 vi_cmdmode = 0;
1570 break;
1571 case 'I'|vbit:
1572 input_backward(cursor);
1573 vi_cmdmode = 0;
1574 break;
1575 case 'a'|vbit:
1576 input_forward();
1577 vi_cmdmode = 0;
1578 break;
1579 case 'A'|vbit:
1580 input_end();
1581 vi_cmdmode = 0;
1582 break;
1583 case 'x'|vbit:
1584 input_delete(1);
1585 break;
1586 case 'X'|vbit:
1587 if (cursor > 0) {
1588 input_backward(1);
1589 input_delete(1);
1590 }
1591 break;
1592 case 'W'|vbit:
1593 vi_Word_motion(command, 1);
1594 break;
1595 case 'w'|vbit:
1596 vi_word_motion(command, 1);
1597 break;
1598 case 'E'|vbit:
1599 vi_End_motion(command);
1600 break;
1601 case 'e'|vbit:
1602 vi_end_motion(command);
1603 break;
1604 case 'B'|vbit:
1605 vi_Back_motion(command);
1606 break;
1607 case 'b'|vbit:
1608 vi_back_motion(command);
1609 break;
1610 case 'C'|vbit:
1611 vi_cmdmode = 0;
1612 /* fall through */
1613 case 'D'|vbit:
1614 goto clear_to_eol;
1615
1616 case 'c'|vbit:
1617 vi_cmdmode = 0;
1618 /* fall through */
1619 case 'd'|vbit:
1620 {
1621 int nc, sc;
1622 sc = cursor;
1623 prevc = ic;
1624 if (safe_read(0, &c, 1) < 1)
1625 goto prepare_to_die;
1626 if (c == (prevc & 0xff)) {
1627 /* "cc", "dd" */
1628 input_backward(cursor);
1629 goto clear_to_eol;
1630 break;
1631 }
1632 switch(c) {
1633 case 'w':
1634 case 'W':
1635 case 'e':
1636 case 'E':
1637 switch (c) {
1638 case 'w': /* "dw", "cw" */
1639 vi_word_motion(command, vi_cmdmode);
1640 break;
1641 case 'W': /* 'dW', 'cW' */
1642 vi_Word_motion(command, vi_cmdmode);
1643 break;
1644 case 'e': /* 'de', 'ce' */
1645 vi_end_motion(command);
1646 input_forward();
1647 break;
1648 case 'E': /* 'dE', 'cE' */
1649 vi_End_motion(command);
1650 input_forward();
1651 break;
1652 }
1653 nc = cursor;
1654 input_backward(cursor - sc);
1655 while (nc-- > cursor)
1656 input_delete(1);
1657 break;
1658 case 'b': /* "db", "cb" */
1659 case 'B': /* implemented as B */
1660 if (c == 'b')
1661 vi_back_motion(command);
1662 else
1663 vi_Back_motion(command);
1664 while (sc-- > cursor)
1665 input_delete(1);
1666 break;
1667 case ' ': /* "d ", "c " */
1668 input_delete(1);
1669 break;
1670 case '$': /* "d$", "c$" */
1671 clear_to_eol:
1672 while (cursor < len)
1673 input_delete(1);
1674 break;
1675 }
1676 }
1677 break;
1678 case 'p'|vbit:
1679 input_forward();
1680 /* fallthrough */
1681 case 'P'|vbit:
1682 put();
1683 break;
1684 case 'r'|vbit:
1685 if (safe_read(0, &c, 1) < 1)
1686 goto prepare_to_die;
1687 if (c == 0)
1688 beep();
1689 else {
1690 *(command + cursor) = c;
1691 putchar(c);
1692 putchar('\b');
1693 }
1694 break;
1695#endif /* CONFIG_FEATURE_COMMAND_EDITING_VI */
1696
1697 case ESC:
1698
1699#if ENABLE_FEATURE_COMMAND_EDITING_VI
1700 if (vi_mode) {
1701 /* ESC: insert mode --> command mode */
1702 vi_cmdmode = 1;
1703 input_backward(1);
1704 break;
1705 }
1706#endif
1707 /* escape sequence follows */
1708 if (safe_read(0, &c, 1) < 1)
1709 goto prepare_to_die;
1710 /* different vt100 emulations */
1711 if (c == '[' || c == 'O') {
1712 vi_case( case '['|vbit: )
1713 vi_case( case 'O'|vbit: )
1714 if (safe_read(0, &c, 1) < 1)
1715 goto prepare_to_die;
1716 }
1717 if (c >= '1' && c <= '9') {
1718 unsigned char dummy;
1719
1720 if (safe_read(0, &dummy, 1) < 1)
1721 goto prepare_to_die;
1722 if(dummy != '~')
1723 c = 0;
1724 }
1725 switch (c) {
1726#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
1727 case '\t': /* Alt-Tab */
1728
1729 input_tab(&lastWasTab);
1730 break;
1731#endif
1732#if MAX_HISTORY > 0
1733 case 'A':
1734 /* Up Arrow -- Get previous command from history */
1735 if (cur_history > 0) {
1736 get_previous_history();
1737 goto rewrite_line;
1738 } else {
1739 beep();
1740 }
1741 break;
1742 case 'B':
1743 /* Down Arrow -- Get next command in history */
1744 if (!get_next_history())
1745 break;
1746 /* Rewrite the line with the selected history item */
1747rewrite_line:
1748 /* change command */
1749 len = strlen(strcpy(command, history[cur_history]));
1750 /* redraw and go to eol (bol, in vi */
1751#if ENABLE_FEATURE_COMMAND_EDITING_VI
1752 redraw(cmdedit_y, vi_mode ? 9999:0);
1753#else
1754 redraw(cmdedit_y, 0);
1755#endif
1756 break;
1757#endif
1758 case 'C':
1759 /* Right Arrow -- Move forward one character */
1760 input_forward();
1761 break;
1762 case 'D':
1763 /* Left Arrow -- Move back one character */
1764 input_backward(1);
1765 break;
1766 case '3':
1767 /* Delete */
1768 input_delete(0);
1769 break;
1770 case '1':
1771 case 'H':
1772 /* <Home> */
1773 input_backward(cursor);
1774 break;
1775 case '4':
1776 case 'F':
1777 /* <End> */
1778 input_end();
1779 break;
1780 default:
1781 c = 0;
1782 beep();
1783 }
1784 break;
1785
1786 default: /* If it's regular input, do the normal thing */
1787#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
1788 /* Control-V -- Add non-printable symbol */
1789 if (c == CNTRL('V')) {
1790 if (safe_read(0, &c, 1) < 1)
1791 goto prepare_to_die;
1792 if (c == 0) {
1793 beep();
1794 break;
1795 }
1796 } else
1797#endif
1798 {
1799#if ENABLE_FEATURE_COMMAND_EDITING_VI
1800 if (vi_cmdmode) /* don't self-insert */
1801 break;
1802#endif
1803 if (!Isprint(c)) /* Skip non-printable characters */
1804 break;
1805 }
1806
1807 if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */
1808 break;
1809
1810 len++;
1811
1812 if (cursor == (len - 1)) { /* Append if at the end of the line */
1813 *(command + cursor) = c;
1814 *(command + cursor + 1) = 0;
1815 cmdedit_set_out_char(0);
1816 } else { /* Insert otherwise */
1817 int sc = cursor;
1818
1819 memmove(command + sc + 1, command + sc, len - sc);
1820 *(command + sc) = c;
1821 sc++;
1822 /* rewrite from cursor */
1823 input_end();
1824 /* to prev x pos + 1 */
1825 input_backward(cursor - sc);
1826 }
1827
1828 break;
1829 }
1830 if (break_out) /* Enter is the command terminator, no more input. */
1831 break;
1832
1833 if (c != '\t')
1834 lastWasTab = FALSE;
1835 }
1836
1837 setTermSettings(0, (void *) &initial_settings);
1838 handlers_sets &= ~SET_RESET_TERM;
1839
1840#if MAX_HISTORY > 0
1841 /* Handle command history log */
1842 /* cleanup may be saved current command line */
1843 if (len> 0) { /* no put empty line */
1844 int i = n_history;
1845
1846 free(history[MAX_HISTORY]);
1847 history[MAX_HISTORY] = 0;
1848 /* After max history, remove the oldest command */
1849 if (i >= MAX_HISTORY) {
1850 free(history[0]);
1851 for(i = 0; i < (MAX_HISTORY-1); i++)
1852 history[i] = history[i+1];
1853 }
1854 history[i++] = xstrdup(command);
1855 cur_history = i;
1856 n_history = i;
1857#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1858 num_ok_lines++;
1859#endif
1860 }
1861#else /* MAX_HISTORY == 0 */
1862#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1863 if (len > 0) { /* no put empty line */
1864 num_ok_lines++;
1865 }
1866#endif
1867#endif /* MAX_HISTORY > 0 */
1868 if (break_out > 0) {
1869 command[len++] = '\n'; /* set '\n' */
1870 command[len] = 0;
1871 }
1872#if defined(CONFIG_FEATURE_CLEAN_UP) && defined(CONFIG_FEATURE_COMMAND_TAB_COMPLETION)
1873 input_tab(0); /* strong free */
1874#endif
1875#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1876 free(cmdedit_prompt);
1877#endif
1878 cmdedit_reset_term();
1879 return len;
1880}
1881
1882
1883
1884#endif /* CONFIG_FEATURE_COMMAND_EDITING */
1885
1886
1887#ifdef TEST
1888
1889const char *applet_name = "debug stuff usage";
1890
1891#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
1892#include <locale.h>
1893#endif
1894
1895int main(int argc, char **argv)
1896{
1897 char buff[BUFSIZ];
1898 char *prompt =
1899#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1900 "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\
1901\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \
1902\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
1903#else
1904 "% ";
1905#endif
1906
1907#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
1908 setlocale(LC_ALL, "");
1909#endif
1910 while(1) {
1911 int l;
1912 l = cmdedit_read_input(prompt, buff);
1913 if(l > 0 && buff[l-1] == '\n') {
1914 buff[l-1] = 0;
1915 printf("*** cmdedit_read_input() returned line =%s=\n", buff);
1916 } else {
1917 break;
1918 }
1919 }
1920 printf("*** cmdedit_read_input() detect ^D\n");
1921 return 0;
1922}
1923
1924#endif /* TEST */
diff --git a/shell/cmdedit.h b/shell/cmdedit.h
new file mode 100644
index 000000000..f5863921a
--- /dev/null
+++ b/shell/cmdedit.h
@@ -0,0 +1,20 @@
1/* vi: set sw=4 ts=4: */
2#ifndef CMDEDIT_H
3#define CMDEDIT_H
4
5int cmdedit_read_input(char* promptStr, char* command);
6
7#ifdef CONFIG_ASH
8extern const char *cmdedit_path_lookup;
9#endif
10
11#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
12void load_history(const char *fromfile);
13void save_history(const char *tofile);
14#endif
15
16#if ENABLE_FEATURE_COMMAND_EDITING_VI
17void setvimode(int viflag);
18#endif
19
20#endif /* CMDEDIT_H */
diff --git a/shell/hush.c b/shell/hush.c
new file mode 100644
index 000000000..a6e029e4e
--- /dev/null
+++ b/shell/hush.c
@@ -0,0 +1,2875 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * sh.c -- a prototype Bourne shell grammar parser
4 * Intended to follow the original Thompson and Ritchie
5 * "small and simple is beautiful" philosophy, which
6 * incidentally is a good match to today's BusyBox.
7 *
8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
9 *
10 * Credits:
11 * The parser routines proper are all original material, first
12 * written Dec 2000 and Jan 2001 by Larry Doolittle. The
13 * execution engine, the builtins, and much of the underlying
14 * support has been adapted from busybox-0.49pre's lash, which is
15 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
16 * written by Erik Andersen <andersen@codepoet.org>. That, in turn,
17 * is based in part on ladsh.c, by Michael K. Johnson and Erik W.
18 * Troan, which they placed in the public domain. I don't know
19 * how much of the Johnson/Troan code has survived the repeated
20 * rewrites.
21 *
22 * Other credits:
23 * simple_itoa() was lifted from boa-0.93.15
24 * b_addchr() derived from similar w_addchar function in glibc-2.2
25 * setup_redirect(), redirect_opt_num(), and big chunks of main()
26 * and many builtins derived from contributions by Erik Andersen
27 * miscellaneous bugfixes from Matt Kraai
28 *
29 * There are two big (and related) architecture differences between
30 * this parser and the lash parser. One is that this version is
31 * actually designed from the ground up to understand nearly all
32 * of the Bourne grammar. The second, consequential change is that
33 * the parser and input reader have been turned inside out. Now,
34 * the parser is in control, and asks for input as needed. The old
35 * way had the input reader in control, and it asked for parsing to
36 * take place as needed. The new way makes it much easier to properly
37 * handle the recursion implicit in the various substitutions, especially
38 * across continuation lines.
39 *
40 * Bash grammar not implemented: (how many of these were in original sh?)
41 * $@ (those sure look like weird quoting rules)
42 * $_
43 * ! negation operator for pipes
44 * &> and >& redirection of stdout+stderr
45 * Brace Expansion
46 * Tilde Expansion
47 * fancy forms of Parameter Expansion
48 * aliases
49 * Arithmetic Expansion
50 * <(list) and >(list) Process Substitution
51 * reserved words: case, esac, select, function
52 * Here Documents ( << word )
53 * Functions
54 * Major bugs:
55 * job handling woefully incomplete and buggy
56 * reserved word execution woefully incomplete and buggy
57 * to-do:
58 * port selected bugfixes from post-0.49 busybox lash - done?
59 * finish implementing reserved words: for, while, until, do, done
60 * change { and } from special chars to reserved words
61 * builtins: break, continue, eval, return, set, trap, ulimit
62 * test magic exec
63 * handle children going into background
64 * clean up recognition of null pipes
65 * check setting of global_argc and global_argv
66 * control-C handling, probably with longjmp
67 * follow IFS rules more precisely, including update semantics
68 * figure out what to do with backslash-newline
69 * explain why we use signal instead of sigaction
70 * propagate syntax errors, die on resource errors?
71 * continuation lines, both explicit and implicit - done?
72 * memory leak finding and plugging - done?
73 * more testing, especially quoting rules and redirection
74 * document how quoting rules not precisely followed for variable assignments
75 * maybe change map[] to use 2-bit entries
76 * (eventually) remove all the printf's
77 *
78 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
79 */
80
81#include "busybox.h"
82#include <ctype.h> /* isalpha, isdigit */
83#include <unistd.h> /* getpid */
84#include <stdlib.h> /* getenv, atoi */
85#include <string.h> /* strchr */
86#include <stdio.h> /* popen etc. */
87#include <glob.h> /* glob, of course */
88#include <stdarg.h> /* va_list */
89#include <errno.h>
90#include <fcntl.h>
91#include <getopt.h> /* should be pretty obvious */
92
93#include <sys/stat.h> /* ulimit */
94#include <sys/types.h>
95#include <sys/wait.h>
96#include <signal.h>
97
98/* #include <dmalloc.h> */
99/* #define DEBUG_SHELL */
100
101#include "cmdedit.h"
102
103#define SPECIAL_VAR_SYMBOL 03
104#define FLAG_EXIT_FROM_LOOP 1
105#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
106#define FLAG_REPARSING (1 << 2) /* >=2nd pass */
107
108typedef enum {
109 REDIRECT_INPUT = 1,
110 REDIRECT_OVERWRITE = 2,
111 REDIRECT_APPEND = 3,
112 REDIRECT_HEREIS = 4,
113 REDIRECT_IO = 5
114} redir_type;
115
116/* The descrip member of this structure is only used to make debugging
117 * output pretty */
118static const struct {int mode; int default_fd; const char *descrip;} redir_table[] = {
119 { 0, 0, "()" },
120 { O_RDONLY, 0, "<" },
121 { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
122 { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
123 { O_RDONLY, -1, "<<" },
124 { O_RDWR, 1, "<>" }
125};
126
127typedef enum {
128 PIPE_SEQ = 1,
129 PIPE_AND = 2,
130 PIPE_OR = 3,
131 PIPE_BG = 4,
132} pipe_style;
133
134/* might eventually control execution */
135typedef enum {
136 RES_NONE = 0,
137 RES_IF = 1,
138 RES_THEN = 2,
139 RES_ELIF = 3,
140 RES_ELSE = 4,
141 RES_FI = 5,
142 RES_FOR = 6,
143 RES_WHILE = 7,
144 RES_UNTIL = 8,
145 RES_DO = 9,
146 RES_DONE = 10,
147 RES_XXXX = 11,
148 RES_IN = 12,
149 RES_SNTX = 13
150} reserved_style;
151#define FLAG_END (1<<RES_NONE)
152#define FLAG_IF (1<<RES_IF)
153#define FLAG_THEN (1<<RES_THEN)
154#define FLAG_ELIF (1<<RES_ELIF)
155#define FLAG_ELSE (1<<RES_ELSE)
156#define FLAG_FI (1<<RES_FI)
157#define FLAG_FOR (1<<RES_FOR)
158#define FLAG_WHILE (1<<RES_WHILE)
159#define FLAG_UNTIL (1<<RES_UNTIL)
160#define FLAG_DO (1<<RES_DO)
161#define FLAG_DONE (1<<RES_DONE)
162#define FLAG_IN (1<<RES_IN)
163#define FLAG_START (1<<RES_XXXX)
164
165/* This holds pointers to the various results of parsing */
166struct p_context {
167 struct child_prog *child;
168 struct pipe *list_head;
169 struct pipe *pipe;
170 struct redir_struct *pending_redirect;
171 reserved_style w;
172 int old_flag; /* for figuring out valid reserved words */
173 struct p_context *stack;
174 int type; /* define type of parser : ";$" common or special symbol */
175 /* How about quoting status? */
176};
177
178struct redir_struct {
179 redir_type type; /* type of redirection */
180 int fd; /* file descriptor being redirected */
181 int dup; /* -1, or file descriptor being duplicated */
182 struct redir_struct *next; /* pointer to the next redirect in the list */
183 glob_t word; /* *word.gl_pathv is the filename */
184};
185
186struct child_prog {
187 pid_t pid; /* 0 if exited */
188 char **argv; /* program name and arguments */
189 struct pipe *group; /* if non-NULL, first in group or subshell */
190 int subshell; /* flag, non-zero if group must be forked */
191 struct redir_struct *redirects; /* I/O redirections */
192 glob_t glob_result; /* result of parameter globbing */
193 int is_stopped; /* is the program currently running? */
194 struct pipe *family; /* pointer back to the child's parent pipe */
195 int sp; /* number of SPECIAL_VAR_SYMBOL */
196 int type;
197};
198
199struct pipe {
200 int jobid; /* job number */
201 int num_progs; /* total number of programs in job */
202 int running_progs; /* number of programs running */
203 char *text; /* name of job */
204 char *cmdbuf; /* buffer various argv's point into */
205 pid_t pgrp; /* process group ID for the job */
206 struct child_prog *progs; /* array of commands in pipe */
207 struct pipe *next; /* to track background commands */
208 int stopped_progs; /* number of programs alive, but stopped */
209 int job_context; /* bitmask defining current context */
210 pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
211 reserved_style r_mode; /* supports if, for, while, until */
212};
213
214struct close_me {
215 int fd;
216 struct close_me *next;
217};
218
219struct variables {
220 char *name;
221 char *value;
222 int flg_export;
223 int flg_read_only;
224 struct variables *next;
225};
226
227/* globals, connect us to the outside world
228 * the first three support $?, $#, and $1 */
229static char **global_argv;
230static int global_argc;
231static int last_return_code;
232extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
233
234/* "globals" within this file */
235static char *ifs;
236static unsigned char map[256];
237static int fake_mode;
238static int interactive;
239static struct close_me *close_me_head;
240static const char *cwd;
241static struct pipe *job_list;
242static unsigned int last_bg_pid;
243static int last_jobid;
244static unsigned int shell_terminal;
245static char *PS1;
246static char *PS2;
247static struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
248static struct variables *top_vars = &shell_ver;
249
250
251#define B_CHUNK (100)
252#define B_NOSPAC 1
253
254typedef struct {
255 char *data;
256 int length;
257 int maxlen;
258 int quote;
259 int nonnull;
260} o_string;
261#define NULL_O_STRING {NULL,0,0,0,0}
262/* used for initialization:
263 o_string foo = NULL_O_STRING; */
264
265/* I can almost use ordinary FILE *. Is open_memstream() universally
266 * available? Where is it documented? */
267struct in_str {
268 const char *p;
269 char peek_buf[2];
270 int __promptme;
271 int promptmode;
272 FILE *file;
273 int (*get) (struct in_str *);
274 int (*peek) (struct in_str *);
275};
276#define b_getch(input) ((input)->get(input))
277#define b_peek(input) ((input)->peek(input))
278
279#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
280
281struct built_in_command {
282 const char *cmd; /* name */
283 const char *descr; /* description */
284 int (*function) (struct child_prog *); /* function ptr */
285};
286
287/* belongs in busybox.h */
288static int max(int a, int b) {
289 return (a>b)?a:b;
290}
291
292/* This should be in utility.c */
293#ifdef DEBUG_SHELL
294static void debug_printf(const char *format, ...)
295{
296 va_list args;
297 va_start(args, format);
298 vfprintf(stderr, format, args);
299 va_end(args);
300}
301/* broken, of course, but OK for testing */
302static char *indenter(int i)
303{
304 static char blanks[]=" ";
305 return &blanks[sizeof(blanks)-i-1];
306}
307#else
308#define debug_printf(...) do {;} while(0);
309#endif
310#define final_printf debug_printf
311
312static void __syntax(char *file, int line) {
313 bb_error_msg("syntax error %s:%d", file, line);
314}
315// NB: was __FILE__, but that produces full path sometimess, so...
316#define syntax() __syntax("hush.c", __LINE__)
317
318/* Index of subroutines: */
319/* function prototypes for builtins */
320static int builtin_cd(struct child_prog *child);
321static int builtin_env(struct child_prog *child);
322static int builtin_eval(struct child_prog *child);
323static int builtin_exec(struct child_prog *child);
324static int builtin_exit(struct child_prog *child);
325static int builtin_export(struct child_prog *child);
326static int builtin_fg_bg(struct child_prog *child);
327static int builtin_help(struct child_prog *child);
328static int builtin_jobs(struct child_prog *child);
329static int builtin_pwd(struct child_prog *child);
330static int builtin_read(struct child_prog *child);
331static int builtin_set(struct child_prog *child);
332static int builtin_shift(struct child_prog *child);
333static int builtin_source(struct child_prog *child);
334static int builtin_umask(struct child_prog *child);
335static int builtin_unset(struct child_prog *child);
336static int builtin_not_written(struct child_prog *child);
337/* o_string manipulation: */
338static int b_check_space(o_string *o, int len);
339static int b_addchr(o_string *o, int ch);
340static void b_reset(o_string *o);
341static int b_addqchr(o_string *o, int ch, int quote);
342static int b_adduint(o_string *o, unsigned int i);
343/* in_str manipulations: */
344static int static_get(struct in_str *i);
345static int static_peek(struct in_str *i);
346static int file_get(struct in_str *i);
347static int file_peek(struct in_str *i);
348static void setup_file_in_str(struct in_str *i, FILE *f);
349static void setup_string_in_str(struct in_str *i, const char *s);
350/* close_me manipulations: */
351static void mark_open(int fd);
352static void mark_closed(int fd);
353static void close_all(void);
354/* "run" the final data structures: */
355static int free_pipe_list(struct pipe *head, int indent);
356static int free_pipe(struct pipe *pi, int indent);
357/* really run the final data structures: */
358static int setup_redirects(struct child_prog *prog, int squirrel[]);
359static int run_list_real(struct pipe *pi);
360static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN;
361static int run_pipe_real(struct pipe *pi);
362/* extended glob support: */
363static int globhack(const char *src, int flags, glob_t *pglob);
364static int glob_needed(const char *s);
365static int xglob(o_string *dest, int flags, glob_t *pglob);
366/* variable assignment: */
367static int is_assignment(const char *s);
368/* data structure manipulation: */
369static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
370static void initialize_context(struct p_context *ctx);
371static int done_word(o_string *dest, struct p_context *ctx);
372static int done_command(struct p_context *ctx);
373static int done_pipe(struct p_context *ctx, pipe_style type);
374/* primary string parsing: */
375static int redirect_dup_num(struct in_str *input);
376static int redirect_opt_num(o_string *o);
377static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
378static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
379static char *lookup_param(char *src);
380static char *make_string(char **inp);
381static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
382static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
383static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
384/* setup: */
385static int parse_stream_outer(struct in_str *inp, int flag);
386static int parse_string_outer(const char *s, int flag);
387static int parse_file_outer(FILE *f);
388/* job management: */
389static int checkjobs(struct pipe* fg_pipe);
390static void insert_bg_job(struct pipe *pi);
391static void remove_bg_job(struct pipe *pi);
392/* local variable support */
393static char **make_list_in(char **inp, char *name);
394static char *insert_var_value(char *inp);
395static char *get_local_var(const char *var);
396static void unset_local_var(const char *name);
397static int set_local_var(const char *s, int flg_export);
398
399/* Table of built-in functions. They can be forked or not, depending on
400 * context: within pipes, they fork. As simple commands, they do not.
401 * When used in non-forking context, they can change global variables
402 * in the parent shell process. If forked, of course they cannot.
403 * For example, 'unset foo | whatever' will parse and run, but foo will
404 * still be set at the end. */
405static const struct built_in_command bltins[] = {
406 {"bg", "Resume a job in the background", builtin_fg_bg},
407 {"break", "Exit for, while or until loop", builtin_not_written},
408 {"cd", "Change working directory", builtin_cd},
409 {"continue", "Continue for, while or until loop", builtin_not_written},
410 {"env", "Print all environment variables", builtin_env},
411 {"eval", "Construct and run shell command", builtin_eval},
412 {"exec", "Exec command, replacing this shell with the exec'd process",
413 builtin_exec},
414 {"exit", "Exit from shell()", builtin_exit},
415 {"export", "Set environment variable", builtin_export},
416 {"fg", "Bring job into the foreground", builtin_fg_bg},
417 {"jobs", "Lists the active jobs", builtin_jobs},
418 {"pwd", "Print current directory", builtin_pwd},
419 {"read", "Input environment variable", builtin_read},
420 {"return", "Return from a function", builtin_not_written},
421 {"set", "Set/unset shell local variables", builtin_set},
422 {"shift", "Shift positional parameters", builtin_shift},
423 {"trap", "Trap signals", builtin_not_written},
424 {"ulimit","Controls resource limits", builtin_not_written},
425 {"umask","Sets file creation mask", builtin_umask},
426 {"unset", "Unset environment variable", builtin_unset},
427 {".", "Source-in and run commands in a file", builtin_source},
428 {"help", "List shell built-in commands", builtin_help},
429 {NULL, NULL, NULL}
430};
431
432static const char *set_cwd(void)
433{
434 if(cwd==bb_msg_unknown)
435 cwd = NULL; /* xgetcwd(arg) called free(arg) */
436 cwd = xgetcwd((char *)cwd);
437 if (!cwd)
438 cwd = bb_msg_unknown;
439 return cwd;
440}
441
442/* built-in 'eval' handler */
443static int builtin_eval(struct child_prog *child)
444{
445 char *str = NULL;
446 int rcode = EXIT_SUCCESS;
447
448 if (child->argv[1]) {
449 str = make_string(child->argv + 1);
450 parse_string_outer(str, FLAG_EXIT_FROM_LOOP |
451 FLAG_PARSE_SEMICOLON);
452 free(str);
453 rcode = last_return_code;
454 }
455 return rcode;
456}
457
458/* built-in 'cd <path>' handler */
459static int builtin_cd(struct child_prog *child)
460{
461 char *newdir;
462 if (child->argv[1] == NULL)
463 newdir = getenv("HOME");
464 else
465 newdir = child->argv[1];
466 if (chdir(newdir)) {
467 printf("cd: %s: %s\n", newdir, strerror(errno));
468 return EXIT_FAILURE;
469 }
470 set_cwd();
471 return EXIT_SUCCESS;
472}
473
474/* built-in 'env' handler */
475static int builtin_env(struct child_prog *dummy ATTRIBUTE_UNUSED)
476{
477 char **e = environ;
478 if (e == NULL) return EXIT_FAILURE;
479 for (; *e; e++) {
480 puts(*e);
481 }
482 return EXIT_SUCCESS;
483}
484
485/* built-in 'exec' handler */
486static int builtin_exec(struct child_prog *child)
487{
488 if (child->argv[1] == NULL)
489 return EXIT_SUCCESS; /* Really? */
490 child->argv++;
491 pseudo_exec(child);
492 /* never returns */
493}
494
495/* built-in 'exit' handler */
496static int builtin_exit(struct child_prog *child)
497{
498 if (child->argv[1] == NULL)
499 exit(last_return_code);
500 exit (atoi(child->argv[1]));
501}
502
503/* built-in 'export VAR=value' handler */
504static int builtin_export(struct child_prog *child)
505{
506 int res = 0;
507 char *name = child->argv[1];
508
509 if (name == NULL) {
510 return builtin_env(child);
511 }
512
513 name = strdup(name);
514
515 if(name) {
516 char *value = strchr(name, '=');
517
518 if (!value) {
519 char *tmp;
520 /* They are exporting something without an =VALUE */
521
522 value = get_local_var(name);
523 if (value) {
524 size_t ln = strlen(name);
525
526 tmp = realloc(name, ln+strlen(value)+2);
527 if(tmp==NULL)
528 res = -1;
529 else {
530 sprintf(tmp+ln, "=%s", value);
531 name = tmp;
532 }
533 } else {
534 /* bash does not return an error when trying to export
535 * an undefined variable. Do likewise. */
536 res = 1;
537 }
538 }
539 }
540 if (res<0)
541 bb_perror_msg("export");
542 else if(res==0)
543 res = set_local_var(name, 1);
544 else
545 res = 0;
546 free(name);
547 return res;
548}
549
550/* built-in 'fg' and 'bg' handler */
551static int builtin_fg_bg(struct child_prog *child)
552{
553 int i, jobnum;
554 struct pipe *pi=NULL;
555
556 if (!interactive)
557 return EXIT_FAILURE;
558 /* If they gave us no args, assume they want the last backgrounded task */
559 if (!child->argv[1]) {
560 for (pi = job_list; pi; pi = pi->next) {
561 if (pi->jobid == last_jobid) {
562 break;
563 }
564 }
565 if (!pi) {
566 bb_error_msg("%s: no current job", child->argv[0]);
567 return EXIT_FAILURE;
568 }
569 } else {
570 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
571 bb_error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
572 return EXIT_FAILURE;
573 }
574 for (pi = job_list; pi; pi = pi->next) {
575 if (pi->jobid == jobnum) {
576 break;
577 }
578 }
579 if (!pi) {
580 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);
581 return EXIT_FAILURE;
582 }
583 }
584
585 if (*child->argv[0] == 'f') {
586 /* Put the job into the foreground. */
587 tcsetpgrp(shell_terminal, pi->pgrp);
588 }
589
590 /* Restart the processes in the job */
591 for (i = 0; i < pi->num_progs; i++)
592 pi->progs[i].is_stopped = 0;
593
594 if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) {
595 if (i == ESRCH) {
596 remove_bg_job(pi);
597 } else {
598 bb_perror_msg("kill (SIGCONT)");
599 }
600 }
601
602 pi->stopped_progs = 0;
603 return EXIT_SUCCESS;
604}
605
606/* built-in 'help' handler */
607static int builtin_help(struct child_prog *dummy ATTRIBUTE_UNUSED)
608{
609 const struct built_in_command *x;
610
611 printf("\nBuilt-in commands:\n");
612 printf("-------------------\n");
613 for (x = bltins; x->cmd; x++) {
614 if (x->descr==NULL)
615 continue;
616 printf("%s\t%s\n", x->cmd, x->descr);
617 }
618 printf("\n\n");
619 return EXIT_SUCCESS;
620}
621
622/* built-in 'jobs' handler */
623static int builtin_jobs(struct child_prog *child ATTRIBUTE_UNUSED)
624{
625 struct pipe *job;
626 char *status_string;
627
628 for (job = job_list; job; job = job->next) {
629 if (job->running_progs == job->stopped_progs)
630 status_string = "Stopped";
631 else
632 status_string = "Running";
633
634 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
635 }
636 return EXIT_SUCCESS;
637}
638
639
640/* built-in 'pwd' handler */
641static int builtin_pwd(struct child_prog *dummy ATTRIBUTE_UNUSED)
642{
643 puts(set_cwd());
644 return EXIT_SUCCESS;
645}
646
647/* built-in 'read VAR' handler */
648static int builtin_read(struct child_prog *child)
649{
650 int res;
651
652 if (child->argv[1]) {
653 char string[BUFSIZ];
654 char *var = 0;
655
656 string[0] = 0; /* In case stdin has only EOF */
657 /* read string */
658 fgets(string, sizeof(string), stdin);
659 chomp(string);
660 var = malloc(strlen(child->argv[1])+strlen(string)+2);
661 if(var) {
662 sprintf(var, "%s=%s", child->argv[1], string);
663 res = set_local_var(var, 0);
664 } else
665 res = -1;
666 if (res)
667 bb_perror_msg("read");
668 free(var); /* So not move up to avoid breaking errno */
669 return res;
670 } else {
671 do res=getchar(); while(res!='\n' && res!=EOF);
672 return 0;
673 }
674}
675
676/* built-in 'set VAR=value' handler */
677static int builtin_set(struct child_prog *child)
678{
679 char *temp = child->argv[1];
680 struct variables *e;
681
682 if (temp == NULL)
683 for(e = top_vars; e; e=e->next)
684 printf("%s=%s\n", e->name, e->value);
685 else
686 set_local_var(temp, 0);
687
688 return EXIT_SUCCESS;
689}
690
691
692/* Built-in 'shift' handler */
693static int builtin_shift(struct child_prog *child)
694{
695 int n=1;
696 if (child->argv[1]) {
697 n=atoi(child->argv[1]);
698 }
699 if (n>=0 && n<global_argc) {
700 /* XXX This probably breaks $0 */
701 global_argc -= n;
702 global_argv += n;
703 return EXIT_SUCCESS;
704 } else {
705 return EXIT_FAILURE;
706 }
707}
708
709/* Built-in '.' handler (read-in and execute commands from file) */
710static int builtin_source(struct child_prog *child)
711{
712 FILE *input;
713 int status;
714
715 if (child->argv[1] == NULL)
716 return EXIT_FAILURE;
717
718 /* XXX search through $PATH is missing */
719 input = fopen(child->argv[1], "r");
720 if (!input) {
721 bb_error_msg("cannot open '%s'", child->argv[1]);
722 return EXIT_FAILURE;
723 }
724
725 /* Now run the file */
726 /* XXX argv and argc are broken; need to save old global_argv
727 * (pointer only is OK!) on this stack frame,
728 * set global_argv=child->argv+1, recurse, and restore. */
729 mark_open(fileno(input));
730 status = parse_file_outer(input);
731 mark_closed(fileno(input));
732 fclose(input);
733 return status;
734}
735
736static int builtin_umask(struct child_prog *child)
737{
738 mode_t new_umask;
739 const char *arg = child->argv[1];
740 char *end;
741 if (arg) {
742 new_umask=strtoul(arg, &end, 8);
743 if (*end!='\0' || end == arg) {
744 return EXIT_FAILURE;
745 }
746 } else {
747 printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
748 }
749 umask(new_umask);
750 return EXIT_SUCCESS;
751}
752
753/* built-in 'unset VAR' handler */
754static int builtin_unset(struct child_prog *child)
755{
756 /* bash returned already true */
757 unset_local_var(child->argv[1]);
758 return EXIT_SUCCESS;
759}
760
761static int builtin_not_written(struct child_prog *child)
762{
763 printf("builtin_%s not written\n",child->argv[0]);
764 return EXIT_FAILURE;
765}
766
767static int b_check_space(o_string *o, int len)
768{
769 /* It would be easy to drop a more restrictive policy
770 * in here, such as setting a maximum string length */
771 if (o->length + len > o->maxlen) {
772 char *old_data = o->data;
773 /* assert (data == NULL || o->maxlen != 0); */
774 o->maxlen += max(2*len, B_CHUNK);
775 o->data = realloc(o->data, 1 + o->maxlen);
776 if (o->data == NULL) {
777 free(old_data);
778 }
779 }
780 return o->data == NULL;
781}
782
783static int b_addchr(o_string *o, int ch)
784{
785 debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
786 if (b_check_space(o, 1)) return B_NOSPAC;
787 o->data[o->length] = ch;
788 o->length++;
789 o->data[o->length] = '\0';
790 return 0;
791}
792
793static void b_reset(o_string *o)
794{
795 o->length = 0;
796 o->nonnull = 0;
797 if (o->data != NULL) *o->data = '\0';
798}
799
800static void b_free(o_string *o)
801{
802 b_reset(o);
803 free(o->data);
804 o->data = NULL;
805 o->maxlen = 0;
806}
807
808/* My analysis of quoting semantics tells me that state information
809 * is associated with a destination, not a source.
810 */
811static int b_addqchr(o_string *o, int ch, int quote)
812{
813 if (quote && strchr("*?[\\",ch)) {
814 int rc;
815 rc = b_addchr(o, '\\');
816 if (rc) return rc;
817 }
818 return b_addchr(o, ch);
819}
820
821/* belongs in utility.c */
822static char *simple_itoa(unsigned int i)
823{
824 /* 21 digits plus null terminator, good for 64-bit or smaller ints */
825 static char local[22];
826 char *p = &local[21];
827 *p-- = '\0';
828 do {
829 *p-- = '0' + i % 10;
830 i /= 10;
831 } while (i > 0);
832 return p + 1;
833}
834
835static int b_adduint(o_string *o, unsigned int i)
836{
837 int r;
838 char *p = simple_itoa(i);
839 /* no escape checking necessary */
840 do r=b_addchr(o, *p++); while (r==0 && *p);
841 return r;
842}
843
844static int static_get(struct in_str *i)
845{
846 int ch=*i->p++;
847 if (ch=='\0') return EOF;
848 return ch;
849}
850
851static int static_peek(struct in_str *i)
852{
853 return *i->p;
854}
855
856static void cmdedit_set_initial_prompt(void)
857{
858#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
859 PS1 = NULL;
860#else
861 PS1 = getenv("PS1");
862 if(PS1==0)
863 PS1 = "\\w \\$ ";
864#endif
865}
866
867static void setup_prompt_string(int promptmode, char **prompt_str)
868{
869 debug_printf("setup_prompt_string %d ",promptmode);
870#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
871 /* Set up the prompt */
872 if (promptmode == 1) {
873 free(PS1);
874 PS1=xmalloc(strlen(cwd)+4);
875 sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# ");
876 *prompt_str = PS1;
877 } else {
878 *prompt_str = PS2;
879 }
880#else
881 *prompt_str = (promptmode==1)? PS1 : PS2;
882#endif
883 debug_printf("result %s\n",*prompt_str);
884}
885
886static void get_user_input(struct in_str *i)
887{
888 char *prompt_str;
889 static char the_command[BUFSIZ];
890
891 setup_prompt_string(i->promptmode, &prompt_str);
892#ifdef CONFIG_FEATURE_COMMAND_EDITING
893 /*
894 ** enable command line editing only while a command line
895 ** is actually being read; otherwise, we'll end up bequeathing
896 ** atexit() handlers and other unwanted stuff to our
897 ** child processes (rob@sysgo.de)
898 */
899 cmdedit_read_input(prompt_str, the_command);
900#else
901 fputs(prompt_str, stdout);
902 fflush(stdout);
903 the_command[0]=fgetc(i->file);
904 the_command[1]='\0';
905#endif
906 fflush(stdout);
907 i->p = the_command;
908}
909
910/* This is the magic location that prints prompts
911 * and gets data back from the user */
912static int file_get(struct in_str *i)
913{
914 int ch;
915
916 ch = 0;
917 /* If there is data waiting, eat it up */
918 if (i->p && *i->p) {
919 ch=*i->p++;
920 } else {
921 /* need to double check i->file because we might be doing something
922 * more complicated by now, like sourcing or substituting. */
923 if (i->__promptme && interactive && i->file == stdin) {
924 while(! i->p || (interactive && strlen(i->p)==0) ) {
925 get_user_input(i);
926 }
927 i->promptmode=2;
928 i->__promptme = 0;
929 if (i->p && *i->p) {
930 ch=*i->p++;
931 }
932 } else {
933 ch = fgetc(i->file);
934 }
935
936 debug_printf("b_getch: got a %d\n", ch);
937 }
938 if (ch == '\n') i->__promptme=1;
939 return ch;
940}
941
942/* All the callers guarantee this routine will never be
943 * used right after a newline, so prompting is not needed.
944 */
945static int file_peek(struct in_str *i)
946{
947 if (i->p && *i->p) {
948 return *i->p;
949 } else {
950 i->peek_buf[0] = fgetc(i->file);
951 i->peek_buf[1] = '\0';
952 i->p = i->peek_buf;
953 debug_printf("b_peek: got a %d\n", *i->p);
954 return *i->p;
955 }
956}
957
958static void setup_file_in_str(struct in_str *i, FILE *f)
959{
960 i->peek = file_peek;
961 i->get = file_get;
962 i->__promptme=1;
963 i->promptmode=1;
964 i->file = f;
965 i->p = NULL;
966}
967
968static void setup_string_in_str(struct in_str *i, const char *s)
969{
970 i->peek = static_peek;
971 i->get = static_get;
972 i->__promptme=1;
973 i->promptmode=1;
974 i->p = s;
975}
976
977static void mark_open(int fd)
978{
979 struct close_me *new = xmalloc(sizeof(struct close_me));
980 new->fd = fd;
981 new->next = close_me_head;
982 close_me_head = new;
983}
984
985static void mark_closed(int fd)
986{
987 struct close_me *tmp;
988 if (close_me_head == NULL || close_me_head->fd != fd)
989 bb_error_msg_and_die("corrupt close_me");
990 tmp = close_me_head;
991 close_me_head = close_me_head->next;
992 free(tmp);
993}
994
995static void close_all(void)
996{
997 struct close_me *c;
998 for (c=close_me_head; c; c=c->next) {
999 close(c->fd);
1000 }
1001 close_me_head = NULL;
1002}
1003
1004/* squirrel != NULL means we squirrel away copies of stdin, stdout,
1005 * and stderr if they are redirected. */
1006static int setup_redirects(struct child_prog *prog, int squirrel[])
1007{
1008 int openfd, mode;
1009 struct redir_struct *redir;
1010
1011 for (redir=prog->redirects; redir; redir=redir->next) {
1012 if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
1013 /* something went wrong in the parse. Pretend it didn't happen */
1014 continue;
1015 }
1016 if (redir->dup == -1) {
1017 mode=redir_table[redir->type].mode;
1018 openfd = open(redir->word.gl_pathv[0], mode, 0666);
1019 if (openfd < 0) {
1020 /* this could get lost if stderr has been redirected, but
1021 bash and ash both lose it as well (though zsh doesn't!) */
1022 bb_perror_msg("error opening %s", redir->word.gl_pathv[0]);
1023 return 1;
1024 }
1025 } else {
1026 openfd = redir->dup;
1027 }
1028
1029 if (openfd != redir->fd) {
1030 if (squirrel && redir->fd < 3) {
1031 squirrel[redir->fd] = dup(redir->fd);
1032 }
1033 if (openfd == -3) {
1034 close(openfd);
1035 } else {
1036 dup2(openfd, redir->fd);
1037 if (redir->dup == -1)
1038 close (openfd);
1039 }
1040 }
1041 }
1042 return 0;
1043}
1044
1045static void restore_redirects(int squirrel[])
1046{
1047 int i, fd;
1048 for (i=0; i<3; i++) {
1049 fd = squirrel[i];
1050 if (fd != -1) {
1051 /* No error checking. I sure wouldn't know what
1052 * to do with an error if I found one! */
1053 dup2(fd, i);
1054 close(fd);
1055 }
1056 }
1057}
1058
1059/* never returns */
1060/* XXX no exit() here. If you don't exec, use _exit instead.
1061 * The at_exit handlers apparently confuse the calling process,
1062 * in particular stdin handling. Not sure why? */
1063static void pseudo_exec(struct child_prog *child)
1064{
1065 int i, rcode;
1066 char *p;
1067 const struct built_in_command *x;
1068 if (child->argv) {
1069 for (i=0; is_assignment(child->argv[i]); i++) {
1070 debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
1071 p = insert_var_value(child->argv[i]);
1072 putenv(strdup(p));
1073 if (p != child->argv[i]) free(p);
1074 }
1075 child->argv+=i; /* XXX this hack isn't so horrible, since we are about
1076 to exit, and therefore don't need to keep data
1077 structures consistent for free() use. */
1078 /* If a variable is assigned in a forest, and nobody listens,
1079 * was it ever really set?
1080 */
1081 if (child->argv[0] == NULL) {
1082 _exit(EXIT_SUCCESS);
1083 }
1084
1085 /*
1086 * Check if the command matches any of the builtins.
1087 * Depending on context, this might be redundant. But it's
1088 * easier to waste a few CPU cycles than it is to figure out
1089 * if this is one of those cases.
1090 */
1091 for (x = bltins; x->cmd; x++) {
1092 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1093 debug_printf("builtin exec %s\n", child->argv[0]);
1094 rcode = x->function(child);
1095 fflush(stdout);
1096 _exit(rcode);
1097 }
1098 }
1099
1100 /* Check if the command matches any busybox internal commands
1101 * ("applets") here.
1102 * FIXME: This feature is not 100% safe, since
1103 * BusyBox is not fully reentrant, so we have no guarantee the things
1104 * from the .bss are still zeroed, or that things from .data are still
1105 * at their defaults. We could exec ourself from /proc/self/exe, but I
1106 * really dislike relying on /proc for things. We could exec ourself
1107 * from global_argv[0], but if we are in a chroot, we may not be able
1108 * to find ourself... */
1109#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
1110 {
1111 int argc_l;
1112 char** argv_l=child->argv;
1113 char *name = child->argv[0];
1114
1115 /* Count argc for use in a second... */
1116 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
1117 optind = 1;
1118 debug_printf("running applet %s\n", name);
1119 run_applet_by_name(name, argc_l, child->argv);
1120 }
1121#endif
1122 debug_printf("exec of %s\n",child->argv[0]);
1123 execvp(child->argv[0],child->argv);
1124 bb_perror_msg("cannot exec: %s",child->argv[0]);
1125 _exit(1);
1126 } else if (child->group) {
1127 debug_printf("runtime nesting to group\n");
1128 interactive=0; /* crucial!!!! */
1129 rcode = run_list_real(child->group);
1130 /* OK to leak memory by not calling free_pipe_list,
1131 * since this process is about to exit */
1132 _exit(rcode);
1133 } else {
1134 /* Can happen. See what bash does with ">foo" by itself. */
1135 debug_printf("trying to pseudo_exec null command\n");
1136 _exit(EXIT_SUCCESS);
1137 }
1138}
1139
1140static void insert_bg_job(struct pipe *pi)
1141{
1142 struct pipe *thejob;
1143
1144 /* Linear search for the ID of the job to use */
1145 pi->jobid = 1;
1146 for (thejob = job_list; thejob; thejob = thejob->next)
1147 if (thejob->jobid >= pi->jobid)
1148 pi->jobid = thejob->jobid + 1;
1149
1150 /* add thejob to the list of running jobs */
1151 if (!job_list) {
1152 thejob = job_list = xmalloc(sizeof(*thejob));
1153 } else {
1154 for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
1155 thejob->next = xmalloc(sizeof(*thejob));
1156 thejob = thejob->next;
1157 }
1158
1159 /* physically copy the struct job */
1160 memcpy(thejob, pi, sizeof(struct pipe));
1161 thejob->next = NULL;
1162 thejob->running_progs = thejob->num_progs;
1163 thejob->stopped_progs = 0;
1164 thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
1165
1166 //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0])
1167 {
1168 char *bar=thejob->text;
1169 char **foo=pi->progs[0].argv;
1170 while(foo && *foo) {
1171 bar += sprintf(bar, "%s ", *foo++);
1172 }
1173 }
1174
1175 /* we don't wait for background thejobs to return -- append it
1176 to the list of backgrounded thejobs and leave it alone */
1177 printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
1178 last_bg_pid = thejob->progs[0].pid;
1179 last_jobid = thejob->jobid;
1180}
1181
1182/* remove a backgrounded job */
1183static void remove_bg_job(struct pipe *pi)
1184{
1185 struct pipe *prev_pipe;
1186
1187 if (pi == job_list) {
1188 job_list = pi->next;
1189 } else {
1190 prev_pipe = job_list;
1191 while (prev_pipe->next != pi)
1192 prev_pipe = prev_pipe->next;
1193 prev_pipe->next = pi->next;
1194 }
1195 if (job_list)
1196 last_jobid = job_list->jobid;
1197 else
1198 last_jobid = 0;
1199
1200 pi->stopped_progs = 0;
1201 free_pipe(pi, 0);
1202 free(pi);
1203}
1204
1205/* Checks to see if any processes have exited -- if they
1206 have, figure out why and see if a job has completed */
1207static int checkjobs(struct pipe* fg_pipe)
1208{
1209 int attributes;
1210 int status;
1211 int prognum = 0;
1212 struct pipe *pi;
1213 pid_t childpid;
1214
1215 attributes = WUNTRACED;
1216 if (fg_pipe==NULL) {
1217 attributes |= WNOHANG;
1218 }
1219
1220 while ((childpid = waitpid(-1, &status, attributes)) > 0) {
1221 if (fg_pipe) {
1222 int i, rcode = 0;
1223 for (i=0; i < fg_pipe->num_progs; i++) {
1224 if (fg_pipe->progs[i].pid == childpid) {
1225 if (i==fg_pipe->num_progs-1)
1226 rcode=WEXITSTATUS(status);
1227 (fg_pipe->num_progs)--;
1228 return rcode;
1229 }
1230 }
1231 }
1232
1233 for (pi = job_list; pi; pi = pi->next) {
1234 prognum = 0;
1235 while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
1236 prognum++;
1237 }
1238 if (prognum < pi->num_progs)
1239 break;
1240 }
1241
1242 if(pi==NULL) {
1243 debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
1244 continue;
1245 }
1246
1247 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1248 /* child exited */
1249 pi->running_progs--;
1250 pi->progs[prognum].pid = 0;
1251
1252 if (!pi->running_progs) {
1253 printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
1254 remove_bg_job(pi);
1255 }
1256 } else {
1257 /* child stopped */
1258 pi->stopped_progs++;
1259 pi->progs[prognum].is_stopped = 1;
1260 }
1261 }
1262
1263 if (childpid == -1 && errno != ECHILD)
1264 bb_perror_msg("waitpid");
1265
1266 /* move the shell to the foreground */
1267 //if (interactive && tcsetpgrp(shell_terminal, getpgid(0)))
1268 // bb_perror_msg("tcsetpgrp-2");
1269 return -1;
1270}
1271
1272/* run_pipe_real() starts all the jobs, but doesn't wait for anything
1273 * to finish. See checkjobs().
1274 *
1275 * return code is normally -1, when the caller has to wait for children
1276 * to finish to determine the exit status of the pipe. If the pipe
1277 * is a simple builtin command, however, the action is done by the
1278 * time run_pipe_real returns, and the exit code is provided as the
1279 * return value.
1280 *
1281 * The input of the pipe is always stdin, the output is always
1282 * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
1283 * because it tries to avoid running the command substitution in
1284 * subshell, when that is in fact necessary. The subshell process
1285 * now has its stdout directed to the input of the appropriate pipe,
1286 * so this routine is noticeably simpler.
1287 */
1288static int run_pipe_real(struct pipe *pi)
1289{
1290 int i;
1291 int nextin, nextout;
1292 int pipefds[2]; /* pipefds[0] is for reading */
1293 struct child_prog *child;
1294 const struct built_in_command *x;
1295 char *p;
1296
1297 nextin = 0;
1298 pi->pgrp = -1;
1299
1300 /* Check if this is a simple builtin (not part of a pipe).
1301 * Builtins within pipes have to fork anyway, and are handled in
1302 * pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
1303 */
1304 child = & (pi->progs[0]);
1305 if (pi->num_progs == 1 && child->group && child->subshell == 0) {
1306 int squirrel[] = {-1, -1, -1};
1307 int rcode;
1308 debug_printf("non-subshell grouping\n");
1309 setup_redirects(child, squirrel);
1310 /* XXX could we merge code with following builtin case,
1311 * by creating a pseudo builtin that calls run_list_real? */
1312 rcode = run_list_real(child->group);
1313 restore_redirects(squirrel);
1314 return rcode;
1315 } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
1316 for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
1317 if (i!=0 && child->argv[i]==NULL) {
1318 /* assignments, but no command: set the local environment */
1319 for (i=0; child->argv[i]!=NULL; i++) {
1320
1321 /* Ok, this case is tricky. We have to decide if this is a
1322 * local variable, or an already exported variable. If it is
1323 * already exported, we have to export the new value. If it is
1324 * not exported, we need only set this as a local variable.
1325 * This junk is all to decide whether or not to export this
1326 * variable. */
1327 int export_me=0;
1328 char *name, *value;
1329 name = xstrdup(child->argv[i]);
1330 debug_printf("Local environment set: %s\n", name);
1331 value = strchr(name, '=');
1332 if (value)
1333 *value=0;
1334 if ( get_local_var(name)) {
1335 export_me=1;
1336 }
1337 free(name);
1338 p = insert_var_value(child->argv[i]);
1339 set_local_var(p, export_me);
1340 if (p != child->argv[i]) free(p);
1341 }
1342 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
1343 }
1344 for (i = 0; is_assignment(child->argv[i]); i++) {
1345 p = insert_var_value(child->argv[i]);
1346 putenv(strdup(p));
1347 if (p != child->argv[i]) {
1348 child->sp--;
1349 free(p);
1350 }
1351 }
1352 if (child->sp) {
1353 char * str = NULL;
1354
1355 str = make_string((child->argv + i));
1356 parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
1357 free(str);
1358 return last_return_code;
1359 }
1360 for (x = bltins; x->cmd; x++) {
1361 if (strcmp(child->argv[i], x->cmd) == 0 ) {
1362 int squirrel[] = {-1, -1, -1};
1363 int rcode;
1364 if (x->function == builtin_exec && child->argv[i+1]==NULL) {
1365 debug_printf("magic exec\n");
1366 setup_redirects(child,NULL);
1367 return EXIT_SUCCESS;
1368 }
1369 debug_printf("builtin inline %s\n", child->argv[0]);
1370 /* XXX setup_redirects acts on file descriptors, not FILEs.
1371 * This is perfect for work that comes after exec().
1372 * Is it really safe for inline use? Experimentally,
1373 * things seem to work with glibc. */
1374 setup_redirects(child, squirrel);
1375 child->argv+=i; /* XXX horrible hack */
1376 rcode = x->function(child);
1377 child->argv-=i; /* XXX restore hack so free() can work right */
1378 restore_redirects(squirrel);
1379 return rcode;
1380 }
1381 }
1382 }
1383
1384 for (i = 0; i < pi->num_progs; i++) {
1385 child = & (pi->progs[i]);
1386
1387 /* pipes are inserted between pairs of commands */
1388 if ((i + 1) < pi->num_progs) {
1389 if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");
1390 nextout = pipefds[1];
1391 } else {
1392 nextout=1;
1393 pipefds[0] = -1;
1394 }
1395
1396 /* XXX test for failed fork()? */
1397#if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
1398 if (!(child->pid = fork()))
1399#else
1400 if (!(child->pid = vfork()))
1401#endif
1402 {
1403 /* Set the handling for job control signals back to the default. */
1404 signal(SIGINT, SIG_DFL);
1405 signal(SIGQUIT, SIG_DFL);
1406 signal(SIGTERM, SIG_DFL);
1407 signal(SIGTSTP, SIG_DFL);
1408 signal(SIGTTIN, SIG_DFL);
1409 signal(SIGTTOU, SIG_DFL);
1410 signal(SIGCHLD, SIG_DFL);
1411
1412 close_all();
1413
1414 if (nextin != 0) {
1415 dup2(nextin, 0);
1416 close(nextin);
1417 }
1418 if (nextout != 1) {
1419 dup2(nextout, 1);
1420 close(nextout);
1421 }
1422 if (pipefds[0]!=-1) {
1423 close(pipefds[0]); /* opposite end of our output pipe */
1424 }
1425
1426 /* Like bash, explicit redirects override pipes,
1427 * and the pipe fd is available for dup'ing. */
1428 setup_redirects(child,NULL);
1429
1430 if (interactive && pi->followup!=PIPE_BG) {
1431 /* If we (the child) win the race, put ourselves in the process
1432 * group whose leader is the first process in this pipe. */
1433 if (pi->pgrp < 0) {
1434 pi->pgrp = getpid();
1435 }
1436 if (setpgid(0, pi->pgrp) == 0) {
1437 tcsetpgrp(2, pi->pgrp);
1438 }
1439 }
1440
1441 pseudo_exec(child);
1442 }
1443
1444
1445 /* put our child in the process group whose leader is the
1446 first process in this pipe */
1447 if (pi->pgrp < 0) {
1448 pi->pgrp = child->pid;
1449 }
1450 /* Don't check for errors. The child may be dead already,
1451 * in which case setpgid returns error code EACCES. */
1452 setpgid(child->pid, pi->pgrp);
1453
1454 if (nextin != 0)
1455 close(nextin);
1456 if (nextout != 1)
1457 close(nextout);
1458
1459 /* If there isn't another process, nextin is garbage
1460 but it doesn't matter */
1461 nextin = pipefds[0];
1462 }
1463 return -1;
1464}
1465
1466static int run_list_real(struct pipe *pi)
1467{
1468 char *save_name = NULL;
1469 char **list = NULL;
1470 char **save_list = NULL;
1471 struct pipe *rpipe;
1472 int flag_rep = 0;
1473 int save_num_progs;
1474 int rcode=0, flag_skip=1;
1475 int flag_restore = 0;
1476 int if_code=0, next_if_code=0; /* need double-buffer to handle elif */
1477 reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
1478 /* check syntax for "for" */
1479 for (rpipe = pi; rpipe; rpipe = rpipe->next) {
1480 if ((rpipe->r_mode == RES_IN ||
1481 rpipe->r_mode == RES_FOR) &&
1482 (rpipe->next == NULL)) {
1483 syntax();
1484 return 1;
1485 }
1486 if ((rpipe->r_mode == RES_IN &&
1487 (rpipe->next->r_mode == RES_IN &&
1488 rpipe->next->progs->argv != NULL))||
1489 (rpipe->r_mode == RES_FOR &&
1490 rpipe->next->r_mode != RES_IN)) {
1491 syntax();
1492 return 1;
1493 }
1494 }
1495 for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
1496 if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL ||
1497 pi->r_mode == RES_FOR) {
1498 flag_restore = 0;
1499 if (!rpipe) {
1500 flag_rep = 0;
1501 rpipe = pi;
1502 }
1503 }
1504 rmode = pi->r_mode;
1505 debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode);
1506 if (rmode == skip_more_in_this_rmode && flag_skip) {
1507 if (pi->followup == PIPE_SEQ) flag_skip=0;
1508 continue;
1509 }
1510 flag_skip = 1;
1511 skip_more_in_this_rmode = RES_XXXX;
1512 if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
1513 if (rmode == RES_THEN && if_code) continue;
1514 if (rmode == RES_ELSE && !if_code) continue;
1515 if (rmode == RES_ELIF && !if_code) break;
1516 if (rmode == RES_FOR && pi->num_progs) {
1517 if (!list) {
1518 /* if no variable values after "in" we skip "for" */
1519 if (!pi->next->progs->argv) continue;
1520 /* create list of variable values */
1521 list = make_list_in(pi->next->progs->argv,
1522 pi->progs->argv[0]);
1523 save_list = list;
1524 save_name = pi->progs->argv[0];
1525 pi->progs->argv[0] = NULL;
1526 flag_rep = 1;
1527 }
1528 if (!(*list)) {
1529 free(pi->progs->argv[0]);
1530 free(save_list);
1531 list = NULL;
1532 flag_rep = 0;
1533 pi->progs->argv[0] = save_name;
1534 pi->progs->glob_result.gl_pathv[0] =
1535 pi->progs->argv[0];
1536 continue;
1537 } else {
1538 /* insert new value from list for variable */
1539 if (pi->progs->argv[0])
1540 free(pi->progs->argv[0]);
1541 pi->progs->argv[0] = *list++;
1542 pi->progs->glob_result.gl_pathv[0] =
1543 pi->progs->argv[0];
1544 }
1545 }
1546 if (rmode == RES_IN) continue;
1547 if (rmode == RES_DO) {
1548 if (!flag_rep) continue;
1549 }
1550 if ((rmode == RES_DONE)) {
1551 if (flag_rep) {
1552 flag_restore = 1;
1553 } else {
1554 rpipe = NULL;
1555 }
1556 }
1557 if (pi->num_progs == 0) continue;
1558 save_num_progs = pi->num_progs; /* save number of programs */
1559 rcode = run_pipe_real(pi);
1560 debug_printf("run_pipe_real returned %d\n",rcode);
1561 if (rcode!=-1) {
1562 /* We only ran a builtin: rcode was set by the return value
1563 * of run_pipe_real(), and we don't need to wait for anything. */
1564 } else if (pi->followup==PIPE_BG) {
1565 /* XXX check bash's behavior with nontrivial pipes */
1566 /* XXX compute jobid */
1567 /* XXX what does bash do with attempts to background builtins? */
1568 insert_bg_job(pi);
1569 rcode = EXIT_SUCCESS;
1570 } else {
1571 if (interactive) {
1572 /* move the new process group into the foreground */
1573 if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
1574 bb_perror_msg("tcsetpgrp-3");
1575 rcode = checkjobs(pi);
1576 /* move the shell to the foreground */
1577 if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY)
1578 bb_perror_msg("tcsetpgrp-4");
1579 } else {
1580 rcode = checkjobs(pi);
1581 }
1582 debug_printf("checkjobs returned %d\n",rcode);
1583 }
1584 last_return_code=rcode;
1585 pi->num_progs = save_num_progs; /* restore number of programs */
1586 if ( rmode == RES_IF || rmode == RES_ELIF )
1587 next_if_code=rcode; /* can be overwritten a number of times */
1588 if (rmode == RES_WHILE)
1589 flag_rep = !last_return_code;
1590 if (rmode == RES_UNTIL)
1591 flag_rep = last_return_code;
1592 if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
1593 (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
1594 skip_more_in_this_rmode=rmode;
1595 checkjobs(NULL);
1596 }
1597 return rcode;
1598}
1599
1600/* return code is the exit status of the pipe */
1601static int free_pipe(struct pipe *pi, int indent)
1602{
1603 char **p;
1604 struct child_prog *child;
1605 struct redir_struct *r, *rnext;
1606 int a, i, ret_code=0;
1607
1608 if (pi->stopped_progs > 0)
1609 return ret_code;
1610 final_printf("%s run pipe: (pid %d)\n",indenter(indent),getpid());
1611 for (i=0; i<pi->num_progs; i++) {
1612 child = &pi->progs[i];
1613 final_printf("%s command %d:\n",indenter(indent),i);
1614 if (child->argv) {
1615 for (a=0,p=child->argv; *p; a++,p++) {
1616 final_printf("%s argv[%d] = %s\n",indenter(indent),a,*p);
1617 }
1618 globfree(&child->glob_result);
1619 child->argv=NULL;
1620 } else if (child->group) {
1621 final_printf("%s begin group (subshell:%d)\n",indenter(indent), child->subshell);
1622 ret_code = free_pipe_list(child->group,indent+3);
1623 final_printf("%s end group\n",indenter(indent));
1624 } else {
1625 final_printf("%s (nil)\n",indenter(indent));
1626 }
1627 for (r=child->redirects; r; r=rnext) {
1628 final_printf("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip);
1629 if (r->dup == -1) {
1630 /* guard against the case >$FOO, where foo is unset or blank */
1631 if (r->word.gl_pathv) {
1632 final_printf(" %s\n", *r->word.gl_pathv);
1633 globfree(&r->word);
1634 }
1635 } else {
1636 final_printf("&%d\n", r->dup);
1637 }
1638 rnext=r->next;
1639 free(r);
1640 }
1641 child->redirects=NULL;
1642 }
1643 free(pi->progs); /* children are an array, they get freed all at once */
1644 pi->progs=NULL;
1645 return ret_code;
1646}
1647
1648static int free_pipe_list(struct pipe *head, int indent)
1649{
1650 int rcode=0; /* if list has no members */
1651 struct pipe *pi, *next;
1652 for (pi=head; pi; pi=next) {
1653 final_printf("%s pipe reserved mode %d\n", indenter(indent), pi->r_mode);
1654 rcode = free_pipe(pi, indent);
1655 final_printf("%s pipe followup code %d\n", indenter(indent), pi->followup);
1656 next=pi->next;
1657 pi->next=NULL;
1658 free(pi);
1659 }
1660 return rcode;
1661}
1662
1663/* Select which version we will use */
1664static int run_list(struct pipe *pi)
1665{
1666 int rcode=0;
1667 if (fake_mode==0) {
1668 rcode = run_list_real(pi);
1669 }
1670 /* free_pipe_list has the side effect of clearing memory
1671 * In the long run that function can be merged with run_list_real,
1672 * but doing that now would hobble the debugging effort. */
1673 free_pipe_list(pi,0);
1674 return rcode;
1675}
1676
1677/* The API for glob is arguably broken. This routine pushes a non-matching
1678 * string into the output structure, removing non-backslashed backslashes.
1679 * If someone can prove me wrong, by performing this function within the
1680 * original glob(3) api, feel free to rewrite this routine into oblivion.
1681 * Return code (0 vs. GLOB_NOSPACE) matches glob(3).
1682 * XXX broken if the last character is '\\', check that before calling.
1683 */
1684static int globhack(const char *src, int flags, glob_t *pglob)
1685{
1686 int cnt=0, pathc;
1687 const char *s;
1688 char *dest;
1689 for (cnt=1, s=src; s && *s; s++) {
1690 if (*s == '\\') s++;
1691 cnt++;
1692 }
1693 dest = malloc(cnt);
1694 if (!dest) return GLOB_NOSPACE;
1695 if (!(flags & GLOB_APPEND)) {
1696 pglob->gl_pathv=NULL;
1697 pglob->gl_pathc=0;
1698 pglob->gl_offs=0;
1699 pglob->gl_offs=0;
1700 }
1701 pathc = ++pglob->gl_pathc;
1702 pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
1703 if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
1704 pglob->gl_pathv[pathc-1]=dest;
1705 pglob->gl_pathv[pathc]=NULL;
1706 for (s=src; s && *s; s++, dest++) {
1707 if (*s == '\\') s++;
1708 *dest = *s;
1709 }
1710 *dest='\0';
1711 return 0;
1712}
1713
1714/* XXX broken if the last character is '\\', check that before calling */
1715static int glob_needed(const char *s)
1716{
1717 for (; *s; s++) {
1718 if (*s == '\\') s++;
1719 if (strchr("*[?",*s)) return 1;
1720 }
1721 return 0;
1722}
1723
1724static int xglob(o_string *dest, int flags, glob_t *pglob)
1725{
1726 int gr;
1727
1728 /* short-circuit for null word */
1729 /* we can code this better when the debug_printf's are gone */
1730 if (dest->length == 0) {
1731 if (dest->nonnull) {
1732 /* bash man page calls this an "explicit" null */
1733 gr = globhack(dest->data, flags, pglob);
1734 debug_printf("globhack returned %d\n",gr);
1735 } else {
1736 return 0;
1737 }
1738 } else if (glob_needed(dest->data)) {
1739 gr = glob(dest->data, flags, NULL, pglob);
1740 debug_printf("glob returned %d\n",gr);
1741 if (gr == GLOB_NOMATCH) {
1742 /* quote removal, or more accurately, backslash removal */
1743 gr = globhack(dest->data, flags, pglob);
1744 debug_printf("globhack returned %d\n",gr);
1745 }
1746 } else {
1747 gr = globhack(dest->data, flags, pglob);
1748 debug_printf("globhack returned %d\n",gr);
1749 }
1750 if (gr == GLOB_NOSPACE)
1751 bb_error_msg_and_die("out of memory during glob");
1752 if (gr != 0) { /* GLOB_ABORTED ? */
1753 bb_error_msg("glob(3) error %d",gr);
1754 }
1755 /* globprint(glob_target); */
1756 return gr;
1757}
1758
1759/* This is used to get/check local shell variables */
1760static char *get_local_var(const char *s)
1761{
1762 struct variables *cur;
1763
1764 if (!s)
1765 return NULL;
1766 for (cur = top_vars; cur; cur=cur->next)
1767 if(strcmp(cur->name, s)==0)
1768 return cur->value;
1769 return NULL;
1770}
1771
1772/* This is used to set local shell variables
1773 flg_export==0 if only local (not exporting) variable
1774 flg_export==1 if "new" exporting environ
1775 flg_export>1 if current startup environ (not call putenv()) */
1776static int set_local_var(const char *s, int flg_export)
1777{
1778 char *name, *value;
1779 int result=0;
1780 struct variables *cur;
1781
1782 name=strdup(s);
1783
1784 /* Assume when we enter this function that we are already in
1785 * NAME=VALUE format. So the first order of business is to
1786 * split 's' on the '=' into 'name' and 'value' */
1787 value = strchr(name, '=');
1788 if (value==0 && ++value==0) {
1789 free(name);
1790 return -1;
1791 }
1792 *value++ = 0;
1793
1794 for(cur = top_vars; cur; cur = cur->next) {
1795 if(strcmp(cur->name, name)==0)
1796 break;
1797 }
1798
1799 if(cur) {
1800 if(strcmp(cur->value, value)==0) {
1801 if(flg_export>0 && cur->flg_export==0)
1802 cur->flg_export=flg_export;
1803 else
1804 result++;
1805 } else {
1806 if(cur->flg_read_only) {
1807 bb_error_msg("%s: readonly variable", name);
1808 result = -1;
1809 } else {
1810 if(flg_export>0 || cur->flg_export>1)
1811 cur->flg_export=1;
1812 free(cur->value);
1813
1814 cur->value = strdup(value);
1815 }
1816 }
1817 } else {
1818 cur = malloc(sizeof(struct variables));
1819 if(!cur) {
1820 result = -1;
1821 } else {
1822 cur->name = strdup(name);
1823 if(cur->name == 0) {
1824 free(cur);
1825 result = -1;
1826 } else {
1827 struct variables *bottom = top_vars;
1828 cur->value = strdup(value);
1829 cur->next = 0;
1830 cur->flg_export = flg_export;
1831 cur->flg_read_only = 0;
1832 while(bottom->next) bottom=bottom->next;
1833 bottom->next = cur;
1834 }
1835 }
1836 }
1837
1838 if(result==0 && cur->flg_export==1) {
1839 *(value-1) = '=';
1840 result = putenv(name);
1841 } else {
1842 free(name);
1843 if(result>0) /* equivalent to previous set */
1844 result = 0;
1845 }
1846 return result;
1847}
1848
1849static void unset_local_var(const char *name)
1850{
1851 struct variables *cur;
1852
1853 if (name) {
1854 for (cur = top_vars; cur; cur=cur->next) {
1855 if(strcmp(cur->name, name)==0)
1856 break;
1857 }
1858 if(cur!=0) {
1859 struct variables *next = top_vars;
1860 if(cur->flg_read_only) {
1861 bb_error_msg("%s: readonly variable", name);
1862 return;
1863 } else {
1864 if(cur->flg_export)
1865 unsetenv(cur->name);
1866 free(cur->name);
1867 free(cur->value);
1868 while (next->next != cur)
1869 next = next->next;
1870 next->next = cur->next;
1871 }
1872 free(cur);
1873 }
1874 }
1875}
1876
1877static int is_assignment(const char *s)
1878{
1879 if (s==NULL || !isalpha(*s)) return 0;
1880 ++s;
1881 while(isalnum(*s) || *s=='_') ++s;
1882 return *s=='=';
1883}
1884
1885/* the src parameter allows us to peek forward to a possible &n syntax
1886 * for file descriptor duplication, e.g., "2>&1".
1887 * Return code is 0 normally, 1 if a syntax error is detected in src.
1888 * Resource errors (in xmalloc) cause the process to exit */
1889static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
1890 struct in_str *input)
1891{
1892 struct child_prog *child=ctx->child;
1893 struct redir_struct *redir = child->redirects;
1894 struct redir_struct *last_redir=NULL;
1895
1896 /* Create a new redir_struct and drop it onto the end of the linked list */
1897 while(redir) {
1898 last_redir=redir;
1899 redir=redir->next;
1900 }
1901 redir = xmalloc(sizeof(struct redir_struct));
1902 redir->next=NULL;
1903 redir->word.gl_pathv=NULL;
1904 if (last_redir) {
1905 last_redir->next=redir;
1906 } else {
1907 child->redirects=redir;
1908 }
1909
1910 redir->type=style;
1911 redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
1912
1913 debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
1914
1915 /* Check for a '2>&1' type redirect */
1916 redir->dup = redirect_dup_num(input);
1917 if (redir->dup == -2) return 1; /* syntax error */
1918 if (redir->dup != -1) {
1919 /* Erik had a check here that the file descriptor in question
1920 * is legit; I postpone that to "run time"
1921 * A "-" representation of "close me" shows up as a -3 here */
1922 debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
1923 } else {
1924 /* We do _not_ try to open the file that src points to,
1925 * since we need to return and let src be expanded first.
1926 * Set ctx->pending_redirect, so we know what to do at the
1927 * end of the next parsed word.
1928 */
1929 ctx->pending_redirect = redir;
1930 }
1931 return 0;
1932}
1933
1934static struct pipe *new_pipe(void) {
1935 struct pipe *pi;
1936 pi = xmalloc(sizeof(struct pipe));
1937 pi->num_progs = 0;
1938 pi->progs = NULL;
1939 pi->next = NULL;
1940 pi->followup = 0; /* invalid */
1941 pi->r_mode = RES_NONE;
1942 return pi;
1943}
1944
1945static void initialize_context(struct p_context *ctx)
1946{
1947 ctx->pipe=NULL;
1948 ctx->pending_redirect=NULL;
1949 ctx->child=NULL;
1950 ctx->list_head=new_pipe();
1951 ctx->pipe=ctx->list_head;
1952 ctx->w=RES_NONE;
1953 ctx->stack=NULL;
1954 ctx->old_flag=0;
1955 done_command(ctx); /* creates the memory for working child */
1956}
1957
1958/* normal return is 0
1959 * if a reserved word is found, and processed, return 1
1960 * should handle if, then, elif, else, fi, for, while, until, do, done.
1961 * case, function, and select are obnoxious, save those for later.
1962 */
1963static int reserved_word(o_string *dest, struct p_context *ctx)
1964{
1965 struct reserved_combo {
1966 char *literal;
1967 int code;
1968 long flag;
1969 };
1970 /* Mostly a list of accepted follow-up reserved words.
1971 * FLAG_END means we are done with the sequence, and are ready
1972 * to turn the compound list into a command.
1973 * FLAG_START means the word must start a new compound list.
1974 */
1975 static struct reserved_combo reserved_list[] = {
1976 { "if", RES_IF, FLAG_THEN | FLAG_START },
1977 { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI },
1978 { "elif", RES_ELIF, FLAG_THEN },
1979 { "else", RES_ELSE, FLAG_FI },
1980 { "fi", RES_FI, FLAG_END },
1981 { "for", RES_FOR, FLAG_IN | FLAG_START },
1982 { "while", RES_WHILE, FLAG_DO | FLAG_START },
1983 { "until", RES_UNTIL, FLAG_DO | FLAG_START },
1984 { "in", RES_IN, FLAG_DO },
1985 { "do", RES_DO, FLAG_DONE },
1986 { "done", RES_DONE, FLAG_END }
1987 };
1988 struct reserved_combo *r;
1989 for (r=reserved_list;
1990#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo)
1991 r<reserved_list+NRES; r++) {
1992 if (strcmp(dest->data, r->literal) == 0) {
1993 debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
1994 if (r->flag & FLAG_START) {
1995 struct p_context *new = xmalloc(sizeof(struct p_context));
1996 debug_printf("push stack\n");
1997 if (ctx->w == RES_IN || ctx->w == RES_FOR) {
1998 syntax();
1999 free(new);
2000 ctx->w = RES_SNTX;
2001 b_reset(dest);
2002 return 1;
2003 }
2004 *new = *ctx; /* physical copy */
2005 initialize_context(ctx);
2006 ctx->stack=new;
2007 } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
2008 syntax();
2009 ctx->w = RES_SNTX;
2010 b_reset(dest);
2011 return 1;
2012 }
2013 ctx->w=r->code;
2014 ctx->old_flag = r->flag;
2015 if (ctx->old_flag & FLAG_END) {
2016 struct p_context *old;
2017 debug_printf("pop stack\n");
2018 done_pipe(ctx,PIPE_SEQ);
2019 old = ctx->stack;
2020 old->child->group = ctx->list_head;
2021 old->child->subshell = 0;
2022 *ctx = *old; /* physical copy */
2023 free(old);
2024 }
2025 b_reset (dest);
2026 return 1;
2027 }
2028 }
2029 return 0;
2030}
2031
2032/* normal return is 0.
2033 * Syntax or xglob errors return 1. */
2034static int done_word(o_string *dest, struct p_context *ctx)
2035{
2036 struct child_prog *child=ctx->child;
2037 glob_t *glob_target;
2038 int gr, flags = 0;
2039
2040 debug_printf("done_word: %s %p\n", dest->data, child);
2041 if (dest->length == 0 && !dest->nonnull) {
2042 debug_printf(" true null, ignored\n");
2043 return 0;
2044 }
2045 if (ctx->pending_redirect) {
2046 glob_target = &ctx->pending_redirect->word;
2047 } else {
2048 if (child->group) {
2049 syntax();
2050 return 1; /* syntax error, groups and arglists don't mix */
2051 }
2052 if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) {
2053 debug_printf("checking %s for reserved-ness\n",dest->data);
2054 if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
2055 }
2056 glob_target = &child->glob_result;
2057 if (child->argv) flags |= GLOB_APPEND;
2058 }
2059 gr = xglob(dest, flags, glob_target);
2060 if (gr != 0) return 1;
2061
2062 b_reset(dest);
2063 if (ctx->pending_redirect) {
2064 ctx->pending_redirect=NULL;
2065 if (glob_target->gl_pathc != 1) {
2066 bb_error_msg("ambiguous redirect");
2067 return 1;
2068 }
2069 } else {
2070 child->argv = glob_target->gl_pathv;
2071 }
2072 if (ctx->w == RES_FOR) {
2073 done_word(dest,ctx);
2074 done_pipe(ctx,PIPE_SEQ);
2075 }
2076 return 0;
2077}
2078
2079/* The only possible error here is out of memory, in which case
2080 * xmalloc exits. */
2081static int done_command(struct p_context *ctx)
2082{
2083 /* The child is really already in the pipe structure, so
2084 * advance the pipe counter and make a new, null child.
2085 * Only real trickiness here is that the uncommitted
2086 * child structure, to which ctx->child points, is not
2087 * counted in pi->num_progs. */
2088 struct pipe *pi=ctx->pipe;
2089 struct child_prog *prog=ctx->child;
2090
2091 if (prog && prog->group == NULL
2092 && prog->argv == NULL
2093 && prog->redirects == NULL) {
2094 debug_printf("done_command: skipping null command\n");
2095 return 0;
2096 } else if (prog) {
2097 pi->num_progs++;
2098 debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
2099 } else {
2100 debug_printf("done_command: initializing\n");
2101 }
2102 pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
2103
2104 prog = pi->progs + pi->num_progs;
2105 prog->redirects = NULL;
2106 prog->argv = NULL;
2107 prog->is_stopped = 0;
2108 prog->group = NULL;
2109 prog->glob_result.gl_pathv = NULL;
2110 prog->family = pi;
2111 prog->sp = 0;
2112 ctx->child = prog;
2113 prog->type = ctx->type;
2114
2115 /* but ctx->pipe and ctx->list_head remain unchanged */
2116 return 0;
2117}
2118
2119static int done_pipe(struct p_context *ctx, pipe_style type)
2120{
2121 struct pipe *new_p;
2122 done_command(ctx); /* implicit closure of previous command */
2123 debug_printf("done_pipe, type %d\n", type);
2124 ctx->pipe->followup = type;
2125 ctx->pipe->r_mode = ctx->w;
2126 new_p=new_pipe();
2127 ctx->pipe->next = new_p;
2128 ctx->pipe = new_p;
2129 ctx->child = NULL;
2130 done_command(ctx); /* set up new pipe to accept commands */
2131 return 0;
2132}
2133
2134/* peek ahead in the in_str to find out if we have a "&n" construct,
2135 * as in "2>&1", that represents duplicating a file descriptor.
2136 * returns either -2 (syntax error), -1 (no &), or the number found.
2137 */
2138static int redirect_dup_num(struct in_str *input)
2139{
2140 int ch, d=0, ok=0;
2141 ch = b_peek(input);
2142 if (ch != '&') return -1;
2143
2144 b_getch(input); /* get the & */
2145 ch=b_peek(input);
2146 if (ch == '-') {
2147 b_getch(input);
2148 return -3; /* "-" represents "close me" */
2149 }
2150 while (isdigit(ch)) {
2151 d = d*10+(ch-'0');
2152 ok=1;
2153 b_getch(input);
2154 ch = b_peek(input);
2155 }
2156 if (ok) return d;
2157
2158 bb_error_msg("ambiguous redirect");
2159 return -2;
2160}
2161
2162/* If a redirect is immediately preceded by a number, that number is
2163 * supposed to tell which file descriptor to redirect. This routine
2164 * looks for such preceding numbers. In an ideal world this routine
2165 * needs to handle all the following classes of redirects...
2166 * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo
2167 * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo
2168 * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo
2169 * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo
2170 * A -1 output from this program means no valid number was found, so the
2171 * caller should use the appropriate default for this redirection.
2172 */
2173static int redirect_opt_num(o_string *o)
2174{
2175 int num;
2176
2177 if (o->length==0) return -1;
2178 for(num=0; num<o->length; num++) {
2179 if (!isdigit(*(o->data+num))) {
2180 return -1;
2181 }
2182 }
2183 /* reuse num (and save an int) */
2184 num=atoi(o->data);
2185 b_reset(o);
2186 return num;
2187}
2188
2189static FILE *generate_stream_from_list(struct pipe *head)
2190{
2191 FILE *pf;
2192 int pid, channel[2];
2193 if (pipe(channel)<0) bb_perror_msg_and_die("pipe");
2194#if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
2195 pid=fork();
2196#else
2197 pid=vfork();
2198#endif
2199 if (pid<0) {
2200 bb_perror_msg_and_die("fork");
2201 } else if (pid==0) {
2202 close(channel[0]);
2203 if (channel[1] != 1) {
2204 dup2(channel[1],1);
2205 close(channel[1]);
2206 }
2207 _exit(run_list_real(head)); /* leaks memory */
2208 }
2209 debug_printf("forked child %d\n",pid);
2210 close(channel[1]);
2211 pf = fdopen(channel[0],"r");
2212 debug_printf("pipe on FILE *%p\n",pf);
2213 return pf;
2214}
2215
2216/* this version hacked for testing purposes */
2217/* return code is exit status of the process that is run. */
2218static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end)
2219{
2220 int retcode;
2221 o_string result=NULL_O_STRING;
2222 struct p_context inner;
2223 FILE *p;
2224 struct in_str pipe_str;
2225 initialize_context(&inner);
2226
2227 /* recursion to generate command */
2228 retcode = parse_stream(&result, &inner, input, subst_end);
2229 if (retcode != 0) return retcode; /* syntax error or EOF */
2230 done_word(&result, &inner);
2231 done_pipe(&inner, PIPE_SEQ);
2232 b_free(&result);
2233
2234 p=generate_stream_from_list(inner.list_head);
2235 if (p==NULL) return 1;
2236 mark_open(fileno(p));
2237 setup_file_in_str(&pipe_str, p);
2238
2239 /* now send results of command back into original context */
2240 retcode = parse_stream(dest, ctx, &pipe_str, '\0');
2241 /* XXX In case of a syntax error, should we try to kill the child?
2242 * That would be tough to do right, so just read until EOF. */
2243 if (retcode == 1) {
2244 while (b_getch(&pipe_str)!=EOF) { /* discard */ };
2245 }
2246
2247 debug_printf("done reading from pipe, pclose()ing\n");
2248 /* This is the step that wait()s for the child. Should be pretty
2249 * safe, since we just read an EOF from its stdout. We could try
2250 * to better, by using wait(), and keeping track of background jobs
2251 * at the same time. That would be a lot of work, and contrary
2252 * to the KISS philosophy of this program. */
2253 mark_closed(fileno(p));
2254 retcode=pclose(p);
2255 free_pipe_list(inner.list_head,0);
2256 debug_printf("pclosed, retcode=%d\n",retcode);
2257 /* XXX this process fails to trim a single trailing newline */
2258 return retcode;
2259}
2260
2261static int parse_group(o_string *dest, struct p_context *ctx,
2262 struct in_str *input, int ch)
2263{
2264 int rcode, endch=0;
2265 struct p_context sub;
2266 struct child_prog *child = ctx->child;
2267 if (child->argv) {
2268 syntax();
2269 return 1; /* syntax error, groups and arglists don't mix */
2270 }
2271 initialize_context(&sub);
2272 switch(ch) {
2273 case '(': endch=')'; child->subshell=1; break;
2274 case '{': endch='}'; break;
2275 default: syntax(); /* really logic error */
2276 }
2277 rcode=parse_stream(dest,&sub,input,endch);
2278 done_word(dest,&sub); /* finish off the final word in the subcontext */
2279 done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */
2280 child->group = sub.list_head;
2281 return rcode;
2282 /* child remains "open", available for possible redirects */
2283}
2284
2285/* basically useful version until someone wants to get fancier,
2286 * see the bash man page under "Parameter Expansion" */
2287static char *lookup_param(char *src)
2288{
2289 char *p=NULL;
2290 if (src) {
2291 p = getenv(src);
2292 if (!p)
2293 p = get_local_var(src);
2294 }
2295 return p;
2296}
2297
2298/* return code: 0 for OK, 1 for syntax error */
2299static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
2300{
2301 int i, advance=0;
2302 char sep[]=" ";
2303 int ch = input->peek(input); /* first character after the $ */
2304 debug_printf("handle_dollar: ch=%c\n",ch);
2305 if (isalpha(ch)) {
2306 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2307 ctx->child->sp++;
2308 while(ch=b_peek(input),isalnum(ch) || ch=='_') {
2309 b_getch(input);
2310 b_addchr(dest,ch);
2311 }
2312 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2313 } else if (isdigit(ch)) {
2314 i = ch-'0'; /* XXX is $0 special? */
2315 if (i<global_argc) {
2316 parse_string(dest, ctx, global_argv[i]); /* recursion */
2317 }
2318 advance = 1;
2319 } else switch (ch) {
2320 case '$':
2321 b_adduint(dest,getpid());
2322 advance = 1;
2323 break;
2324 case '!':
2325 if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
2326 advance = 1;
2327 break;
2328 case '?':
2329 b_adduint(dest,last_return_code);
2330 advance = 1;
2331 break;
2332 case '#':
2333 b_adduint(dest,global_argc ? global_argc-1 : 0);
2334 advance = 1;
2335 break;
2336 case '{':
2337 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2338 ctx->child->sp++;
2339 b_getch(input);
2340 /* XXX maybe someone will try to escape the '}' */
2341 while(ch=b_getch(input),ch!=EOF && ch!='}') {
2342 b_addchr(dest,ch);
2343 }
2344 if (ch != '}') {
2345 syntax();
2346 return 1;
2347 }
2348 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2349 break;
2350 case '(':
2351 b_getch(input);
2352 process_command_subs(dest, ctx, input, ')');
2353 break;
2354 case '*':
2355 sep[0]=ifs[0];
2356 for (i=1; i<global_argc; i++) {
2357 parse_string(dest, ctx, global_argv[i]);
2358 if (i+1 < global_argc) parse_string(dest, ctx, sep);
2359 }
2360 break;
2361 case '@':
2362 case '-':
2363 case '_':
2364 /* still unhandled, but should be eventually */
2365 bb_error_msg("unhandled syntax: $%c",ch);
2366 return 1;
2367 break;
2368 default:
2369 b_addqchr(dest,'$',dest->quote);
2370 }
2371 /* Eat the character if the flag was set. If the compiler
2372 * is smart enough, we could substitute "b_getch(input);"
2373 * for all the "advance = 1;" above, and also end up with
2374 * a nice size-optimized program. Hah! That'll be the day.
2375 */
2376 if (advance) b_getch(input);
2377 return 0;
2378}
2379
2380int parse_string(o_string *dest, struct p_context *ctx, const char *src)
2381{
2382 struct in_str foo;
2383 setup_string_in_str(&foo, src);
2384 return parse_stream(dest, ctx, &foo, '\0');
2385}
2386
2387/* return code is 0 for normal exit, 1 for syntax error */
2388int parse_stream(o_string *dest, struct p_context *ctx,
2389 struct in_str *input, int end_trigger)
2390{
2391 int ch, m;
2392 int redir_fd;
2393 redir_type redir_style;
2394 int next;
2395
2396 /* Only double-quote state is handled in the state variable dest->quote.
2397 * A single-quote triggers a bypass of the main loop until its mate is
2398 * found. When recursing, quote state is passed in via dest->quote. */
2399
2400 debug_printf("parse_stream, end_trigger=%d\n",end_trigger);
2401 while ((ch=b_getch(input))!=EOF) {
2402 m = map[ch];
2403 next = (ch == '\n') ? 0 : b_peek(input);
2404 debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n",
2405 ch,ch,m,dest->quote);
2406 if (m==0 || ((m==1 || m==2) && dest->quote)) {
2407 b_addqchr(dest, ch, dest->quote);
2408 } else {
2409 if (m==2) { /* unquoted IFS */
2410 if (done_word(dest, ctx)) {
2411 return 1;
2412 }
2413 /* If we aren't performing a substitution, treat a newline as a
2414 * command separator. */
2415 if (end_trigger != '\0' && ch=='\n')
2416 done_pipe(ctx,PIPE_SEQ);
2417 }
2418 if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
2419 debug_printf("leaving parse_stream (triggered)\n");
2420 return 0;
2421 }
2422 if (m!=2) switch (ch) {
2423 case '#':
2424 if (dest->length == 0 && !dest->quote) {
2425 while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); }
2426 } else {
2427 b_addqchr(dest, ch, dest->quote);
2428 }
2429 break;
2430 case '\\':
2431 if (next == EOF) {
2432 syntax();
2433 return 1;
2434 }
2435 b_addqchr(dest, '\\', dest->quote);
2436 b_addqchr(dest, b_getch(input), dest->quote);
2437 break;
2438 case '$':
2439 if (handle_dollar(dest, ctx, input)!=0) return 1;
2440 break;
2441 case '\'':
2442 dest->nonnull = 1;
2443 while(ch=b_getch(input),ch!=EOF && ch!='\'') {
2444 b_addchr(dest,ch);
2445 }
2446 if (ch==EOF) {
2447 syntax();
2448 return 1;
2449 }
2450 break;
2451 case '"':
2452 dest->nonnull = 1;
2453 dest->quote = !dest->quote;
2454 break;
2455 case '`':
2456 process_command_subs(dest, ctx, input, '`');
2457 break;
2458 case '>':
2459 redir_fd = redirect_opt_num(dest);
2460 done_word(dest, ctx);
2461 redir_style=REDIRECT_OVERWRITE;
2462 if (next == '>') {
2463 redir_style=REDIRECT_APPEND;
2464 b_getch(input);
2465 } else if (next == '(') {
2466 syntax(); /* until we support >(list) Process Substitution */
2467 return 1;
2468 }
2469 setup_redirect(ctx, redir_fd, redir_style, input);
2470 break;
2471 case '<':
2472 redir_fd = redirect_opt_num(dest);
2473 done_word(dest, ctx);
2474 redir_style=REDIRECT_INPUT;
2475 if (next == '<') {
2476 redir_style=REDIRECT_HEREIS;
2477 b_getch(input);
2478 } else if (next == '>') {
2479 redir_style=REDIRECT_IO;
2480 b_getch(input);
2481 } else if (next == '(') {
2482 syntax(); /* until we support <(list) Process Substitution */
2483 return 1;
2484 }
2485 setup_redirect(ctx, redir_fd, redir_style, input);
2486 break;
2487 case ';':
2488 done_word(dest, ctx);
2489 done_pipe(ctx,PIPE_SEQ);
2490 break;
2491 case '&':
2492 done_word(dest, ctx);
2493 if (next=='&') {
2494 b_getch(input);
2495 done_pipe(ctx,PIPE_AND);
2496 } else {
2497 done_pipe(ctx,PIPE_BG);
2498 }
2499 break;
2500 case '|':
2501 done_word(dest, ctx);
2502 if (next=='|') {
2503 b_getch(input);
2504 done_pipe(ctx,PIPE_OR);
2505 } else {
2506 /* we could pick up a file descriptor choice here
2507 * with redirect_opt_num(), but bash doesn't do it.
2508 * "echo foo 2| cat" yields "foo 2". */
2509 done_command(ctx);
2510 }
2511 break;
2512 case '(':
2513 case '{':
2514 if (parse_group(dest, ctx, input, ch)!=0) return 1;
2515 break;
2516 case ')':
2517 case '}':
2518 syntax(); /* Proper use of this character caught by end_trigger */
2519 return 1;
2520 break;
2521 default:
2522 syntax(); /* this is really an internal logic error */
2523 return 1;
2524 }
2525 }
2526 }
2527 /* complain if quote? No, maybe we just finished a command substitution
2528 * that was quoted. Example:
2529 * $ echo "`cat foo` plus more"
2530 * and we just got the EOF generated by the subshell that ran "cat foo"
2531 * The only real complaint is if we got an EOF when end_trigger != '\0',
2532 * that is, we were really supposed to get end_trigger, and never got
2533 * one before the EOF. Can't use the standard "syntax error" return code,
2534 * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
2535 debug_printf("leaving parse_stream (EOF)\n");
2536 if (end_trigger != '\0') return -1;
2537 return 0;
2538}
2539
2540static void mapset(const char *set, int code)
2541{
2542 const unsigned char *s;
2543 for (s = (const unsigned char *)set; *s; s++) map[(int)*s] = code;
2544}
2545
2546static void update_ifs_map(void)
2547{
2548 /* char *ifs and char map[256] are both globals. */
2549 ifs = getenv("IFS");
2550 if (ifs == NULL) ifs=" \t\n";
2551 /* Precompute a list of 'flow through' behavior so it can be treated
2552 * quickly up front. Computation is necessary because of IFS.
2553 * Special case handling of IFS == " \t\n" is not implemented.
2554 * The map[] array only really needs two bits each, and on most machines
2555 * that would be faster because of the reduced L1 cache footprint.
2556 */
2557 memset(map,0,sizeof(map)); /* most characters flow through always */
2558 mapset("\\$'\"`", 3); /* never flow through */
2559 mapset("<>;&|(){}#", 1); /* flow through if quoted */
2560 mapset(ifs, 2); /* also flow through if quoted */
2561}
2562
2563/* most recursion does not come through here, the exception is
2564 * from builtin_source() */
2565int parse_stream_outer(struct in_str *inp, int flag)
2566{
2567
2568 struct p_context ctx;
2569 o_string temp=NULL_O_STRING;
2570 int rcode;
2571 do {
2572 ctx.type = flag;
2573 initialize_context(&ctx);
2574 update_ifs_map();
2575 if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0);
2576 inp->promptmode=1;
2577 rcode = parse_stream(&temp, &ctx, inp, '\n');
2578 if (rcode != 1 && ctx.old_flag != 0) {
2579 syntax();
2580 }
2581 if (rcode != 1 && ctx.old_flag == 0) {
2582 done_word(&temp, &ctx);
2583 done_pipe(&ctx,PIPE_SEQ);
2584 run_list(ctx.list_head);
2585 } else {
2586 if (ctx.old_flag != 0) {
2587 free(ctx.stack);
2588 b_reset(&temp);
2589 }
2590 temp.nonnull = 0;
2591 temp.quote = 0;
2592 inp->p = NULL;
2593 free_pipe_list(ctx.list_head,0);
2594 }
2595 b_free(&temp);
2596 } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */
2597 return 0;
2598}
2599
2600static int parse_string_outer(const char *s, int flag)
2601{
2602 struct in_str input;
2603 setup_string_in_str(&input, s);
2604 return parse_stream_outer(&input, flag);
2605}
2606
2607static int parse_file_outer(FILE *f)
2608{
2609 int rcode;
2610 struct in_str input;
2611 setup_file_in_str(&input, f);
2612 rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
2613 return rcode;
2614}
2615
2616/* Make sure we have a controlling tty. If we get started under a job
2617 * aware app (like bash for example), make sure we are now in charge so
2618 * we don't fight over who gets the foreground */
2619static void setup_job_control(void)
2620{
2621 static pid_t shell_pgrp;
2622 /* Loop until we are in the foreground. */
2623 while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
2624 kill (- shell_pgrp, SIGTTIN);
2625
2626 /* Ignore interactive and job-control signals. */
2627 signal(SIGINT, SIG_IGN);
2628 signal(SIGQUIT, SIG_IGN);
2629 signal(SIGTERM, SIG_IGN);
2630 signal(SIGTSTP, SIG_IGN);
2631 signal(SIGTTIN, SIG_IGN);
2632 signal(SIGTTOU, SIG_IGN);
2633 signal(SIGCHLD, SIG_IGN);
2634
2635 /* Put ourselves in our own process group. */
2636 setsid();
2637 shell_pgrp = getpid ();
2638 setpgid (shell_pgrp, shell_pgrp);
2639
2640 /* Grab control of the terminal. */
2641 tcsetpgrp(shell_terminal, shell_pgrp);
2642}
2643
2644int hush_main(int argc, char **argv)
2645{
2646 int opt;
2647 FILE *input;
2648 char **e = environ;
2649
2650 /* XXX what should these be while sourcing /etc/profile? */
2651 global_argc = argc;
2652 global_argv = argv;
2653
2654 /* (re?) initialize globals. Sometimes hush_main() ends up calling
2655 * hush_main(), therefore we cannot rely on the BSS to zero out this
2656 * stuff. Reset these to 0 every time. */
2657 ifs = NULL;
2658 /* map[] is taken care of with call to update_ifs_map() */
2659 fake_mode = 0;
2660 interactive = 0;
2661 close_me_head = NULL;
2662 last_bg_pid = 0;
2663 job_list = NULL;
2664 last_jobid = 0;
2665
2666 /* Initialize some more globals to non-zero values */
2667 set_cwd();
2668 if (ENABLE_FEATURE_COMMAND_EDITING) cmdedit_set_initial_prompt();
2669 else PS1 = NULL;
2670 PS2 = "> ";
2671
2672 /* initialize our shell local variables with the values
2673 * currently living in the environment */
2674 if (e) {
2675 for (; *e; e++)
2676 set_local_var(*e, 2); /* without call putenv() */
2677 }
2678
2679 last_return_code=EXIT_SUCCESS;
2680
2681
2682 if (argv[0] && argv[0][0] == '-') {
2683 debug_printf("\nsourcing /etc/profile\n");
2684 if ((input = fopen("/etc/profile", "r")) != NULL) {
2685 mark_open(fileno(input));
2686 parse_file_outer(input);
2687 mark_closed(fileno(input));
2688 fclose(input);
2689 }
2690 }
2691 input=stdin;
2692
2693 while ((opt = getopt(argc, argv, "c:xif")) > 0) {
2694 switch (opt) {
2695 case 'c':
2696 {
2697 global_argv = argv+optind;
2698 global_argc = argc-optind;
2699 opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
2700 goto final_return;
2701 }
2702 break;
2703 case 'i':
2704 interactive++;
2705 break;
2706 case 'f':
2707 fake_mode++;
2708 break;
2709 default:
2710#ifndef BB_VER
2711 fprintf(stderr, "Usage: sh [FILE]...\n"
2712 " or: sh -c command [args]...\n\n");
2713 exit(EXIT_FAILURE);
2714#else
2715 bb_show_usage();
2716#endif
2717 }
2718 }
2719 /* A shell is interactive if the `-i' flag was given, or if all of
2720 * the following conditions are met:
2721 * no -c command
2722 * no arguments remaining or the -s flag given
2723 * standard input is a terminal
2724 * standard output is a terminal
2725 * Refer to Posix.2, the description of the `sh' utility. */
2726 if (argv[optind]==NULL && input==stdin &&
2727 isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
2728 interactive++;
2729 }
2730
2731 debug_printf("\ninteractive=%d\n", interactive);
2732 if (interactive) {
2733 /* Looks like they want an interactive shell */
2734#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
2735 printf( "\n\n%s hush - the humble shell v0.01 (testing)\n",
2736 BB_BANNER);
2737 printf( "Enter 'help' for a list of built-in commands.\n\n");
2738#endif
2739 setup_job_control();
2740 }
2741
2742 if (argv[optind]==NULL) {
2743 opt=parse_file_outer(stdin);
2744 goto final_return;
2745 }
2746
2747 debug_printf("\nrunning script '%s'\n", argv[optind]);
2748 global_argv = argv+optind;
2749 global_argc = argc-optind;
2750 input = xfopen(argv[optind], "r");
2751 opt = parse_file_outer(input);
2752
2753#ifdef CONFIG_FEATURE_CLEAN_UP
2754 fclose(input);
2755 if (cwd && cwd != bb_msg_unknown)
2756 free((char*)cwd);
2757 {
2758 struct variables *cur, *tmp;
2759 for(cur = top_vars; cur; cur = tmp) {
2760 tmp = cur->next;
2761 if (!cur->flg_read_only) {
2762 free(cur->name);
2763 free(cur->value);
2764 free(cur);
2765 }
2766 }
2767 }
2768#endif
2769
2770final_return:
2771 return opt ? opt : last_return_code;
2772}
2773
2774static char *insert_var_value(char *inp)
2775{
2776 int res_str_len = 0;
2777 int len;
2778 int done = 0;
2779 char *p, *p1, *res_str = NULL;
2780
2781 while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
2782 if (p != inp) {
2783 len = p - inp;
2784 res_str = xrealloc(res_str, (res_str_len + len));
2785 strncpy((res_str + res_str_len), inp, len);
2786 res_str_len += len;
2787 }
2788 inp = ++p;
2789 p = strchr(inp, SPECIAL_VAR_SYMBOL);
2790 *p = '\0';
2791 if ((p1 = lookup_param(inp))) {
2792 len = res_str_len + strlen(p1);
2793 res_str = xrealloc(res_str, (1 + len));
2794 strcpy((res_str + res_str_len), p1);
2795 res_str_len = len;
2796 }
2797 *p = SPECIAL_VAR_SYMBOL;
2798 inp = ++p;
2799 done = 1;
2800 }
2801 if (done) {
2802 res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
2803 strcpy((res_str + res_str_len), inp);
2804 while ((p = strchr(res_str, '\n'))) {
2805 *p = ' ';
2806 }
2807 }
2808 return (res_str == NULL) ? inp : res_str;
2809}
2810
2811static char **make_list_in(char **inp, char *name)
2812{
2813 int len, i;
2814 int name_len = strlen(name);
2815 int n = 0;
2816 char **list;
2817 char *p1, *p2, *p3;
2818
2819 /* create list of variable values */
2820 list = xmalloc(sizeof(*list));
2821 for (i = 0; inp[i]; i++) {
2822 p3 = insert_var_value(inp[i]);
2823 p1 = p3;
2824 while (*p1) {
2825 if ((*p1 == ' ')) {
2826 p1++;
2827 continue;
2828 }
2829 if ((p2 = strchr(p1, ' '))) {
2830 len = p2 - p1;
2831 } else {
2832 len = strlen(p1);
2833 p2 = p1 + len;
2834 }
2835 /* we use n + 2 in realloc for list,because we add
2836 * new element and then we will add NULL element */
2837 list = xrealloc(list, sizeof(*list) * (n + 2));
2838 list[n] = xmalloc(2 + name_len + len);
2839 strcpy(list[n], name);
2840 strcat(list[n], "=");
2841 strncat(list[n], p1, len);
2842 list[n++][name_len + len + 1] = '\0';
2843 p1 = p2;
2844 }
2845 if (p3 != inp[i]) free(p3);
2846 }
2847 list[n] = NULL;
2848 return list;
2849}
2850
2851/* Make new string for parser */
2852static char * make_string(char ** inp)
2853{
2854 char *p;
2855 char *str = NULL;
2856 int n;
2857 int len = 2;
2858
2859 for (n = 0; inp[n]; n++) {
2860 p = insert_var_value(inp[n]);
2861 str = xrealloc(str, (len + strlen(p)));
2862 if (n) {
2863 strcat(str, " ");
2864 } else {
2865 *str = '\0';
2866 }
2867 strcat(str, p);
2868 len = strlen(str) + 3;
2869 if (p != inp[n]) free(p);
2870 }
2871 len = strlen(str);
2872 *(str + len) = '\n';
2873 *(str + len + 1) = '\0';
2874 return str;
2875}
diff --git a/shell/lash.c b/shell/lash.c
new file mode 100644
index 000000000..3b51e98a9
--- /dev/null
+++ b/shell/lash.c
@@ -0,0 +1,1573 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * lash -- the BusyBox Lame-Ass SHell
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is
8 * under the following liberal license: "We have placed this source code in the
9 * public domain. Use it in any project, free or commercial."
10 *
11 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
12 */
13
14/* This shell's parsing engine is officially at a dead-end. Future
15 * work shell work should be done using hush, msh, or ash. This is
16 * still a very useful, small shell -- it just don't need any more
17 * features beyond what it already has...
18 */
19
20//For debugging/development on the shell only...
21//#define DEBUG_SHELL
22
23
24#include "busybox.h"
25#include <getopt.h>
26#include "cmdedit.h"
27
28#include <glob.h>
29#define expand_t glob_t
30
31/* Always enable for the moment... */
32#define CONFIG_LASH_PIPE_N_REDIRECTS
33#define CONFIG_LASH_JOB_CONTROL
34
35static const int MAX_READ = 128; /* size of input buffer for `read' builtin */
36#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
37
38
39#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
40enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
41 REDIRECT_APPEND
42};
43#endif
44
45enum {
46 DEFAULT_CONTEXT = 0x1,
47 IF_TRUE_CONTEXT = 0x2,
48 IF_FALSE_CONTEXT = 0x4,
49 THEN_EXP_CONTEXT = 0x8,
50 ELSE_EXP_CONTEXT = 0x10
51};
52
53#define LASH_OPT_DONE (1)
54#define LASH_OPT_SAW_QUOTE (2)
55
56#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
57struct redir_struct {
58 enum redir_type type; /* type of redirection */
59 int fd; /* file descriptor being redirected */
60 char *filename; /* file to redirect fd to */
61};
62#endif
63
64struct child_prog {
65 pid_t pid; /* 0 if exited */
66 char **argv; /* program name and arguments */
67 int num_redirects; /* elements in redirection array */
68 int is_stopped; /* is the program currently running? */
69 struct job *family; /* pointer back to the child's parent job */
70#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
71 struct redir_struct *redirects; /* I/O redirects */
72#endif
73};
74
75struct jobset {
76 struct job *head; /* head of list of running jobs */
77 struct job *fg; /* current foreground job */
78};
79
80struct job {
81 int jobid; /* job number */
82 int num_progs; /* total number of programs in job */
83 int running_progs; /* number of programs running */
84 char *text; /* name of job */
85 char *cmdbuf; /* buffer various argv's point into */
86 pid_t pgrp; /* process group ID for the job */
87 struct child_prog *progs; /* array of programs in job */
88 struct job *next; /* to track background commands */
89 int stopped_progs; /* number of programs alive, but stopped */
90 unsigned int job_context; /* bitmask defining current context */
91 struct jobset *job_list;
92};
93
94struct built_in_command {
95 char *cmd; /* name */
96 char *descr; /* description */
97 int (*function) (struct child_prog *); /* function ptr */
98};
99
100/* function prototypes for builtins */
101static int builtin_cd(struct child_prog *cmd);
102static int builtin_exec(struct child_prog *cmd);
103static int builtin_exit(struct child_prog *cmd);
104static int builtin_fg_bg(struct child_prog *cmd);
105static int builtin_help(struct child_prog *cmd);
106static int builtin_jobs(struct child_prog *dummy);
107static int builtin_pwd(struct child_prog *dummy);
108static int builtin_export(struct child_prog *cmd);
109static int builtin_source(struct child_prog *cmd);
110static int builtin_unset(struct child_prog *cmd);
111static int builtin_read(struct child_prog *cmd);
112
113
114/* function prototypes for shell stuff */
115static void checkjobs(struct jobset *job_list);
116static void remove_job(struct jobset *j_list, struct job *job);
117static int get_command(FILE * source, char *command);
118static int parse_command(char **command_ptr, struct job *job, int *inbg);
119static int run_command(struct job *newjob, int inbg, int outpipe[2]);
120static int pseudo_exec(struct child_prog *cmd) ATTRIBUTE_NORETURN;
121static int busy_loop(FILE * input);
122
123
124/* Table of built-in functions (these are non-forking builtins, meaning they
125 * can change global variables in the parent shell process but they will not
126 * work with pipes and redirects; 'unset foo | whatever' will not work) */
127static struct built_in_command bltins[] = {
128 {"bg", "Resume a job in the background", builtin_fg_bg},
129 {"cd", "Change working directory", builtin_cd},
130 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
131 {"exit", "Exit from shell()", builtin_exit},
132 {"fg", "Bring job into the foreground", builtin_fg_bg},
133 {"jobs", "Lists the active jobs", builtin_jobs},
134 {"export", "Set environment variable", builtin_export},
135 {"unset", "Unset environment variable", builtin_unset},
136 {"read", "Input environment variable", builtin_read},
137 {".", "Source-in and run commands in a file", builtin_source},
138 /* to do: add ulimit */
139 {NULL, NULL, NULL}
140};
141
142/* Table of forking built-in functions (things that fork cannot change global
143 * variables in the parent process, such as the current working directory) */
144static struct built_in_command bltins_forking[] = {
145 {"pwd", "Print current directory", builtin_pwd},
146 {"help", "List shell built-in commands", builtin_help},
147 {NULL, NULL, NULL}
148};
149
150
151static int shell_context; /* Type prompt trigger (PS1 or PS2) */
152
153
154/* Globals that are static to this file */
155static const char *cwd;
156static char *local_pending_command;
157static struct jobset job_list = { NULL, NULL };
158static int argc;
159static char **argv;
160static llist_t *close_me_list;
161static int last_return_code;
162static int last_bg_pid;
163static unsigned int last_jobid;
164static int shell_terminal;
165static char *PS1;
166static char *PS2 = "> ";
167
168
169#ifdef DEBUG_SHELL
170static inline void debug_printf(const char *format, ...)
171{
172 va_list args;
173 va_start(args, format);
174 vfprintf(stderr, format, args);
175 va_end(args);
176}
177#else
178static inline void debug_printf(const char ATTRIBUTE_UNUSED *format, ...) { }
179#endif
180
181/*
182 Most builtins need access to the struct child_prog that has
183 their arguments, previously coded as cmd->progs[0]. That coding
184 can exhibit a bug, if the builtin is not the first command in
185 a pipeline: "echo foo | exec sort" will attempt to exec foo.
186
187builtin previous use notes
188------ ----------------- ---------
189cd cmd->progs[0]
190exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins
191exit cmd->progs[0]
192fg_bg cmd->progs[0], job_list->head, job_list->fg
193help 0
194jobs job_list->head
195pwd 0
196export cmd->progs[0]
197source cmd->progs[0]
198unset cmd->progs[0]
199read cmd->progs[0]
200
201I added "struct job *family;" to struct child_prog,
202and switched API to builtin_foo(struct child_prog *child);
203So cmd->text becomes child->family->text
204 cmd->job_context becomes child->family->job_context
205 cmd->progs[0] becomes *child
206 job_list becomes child->family->job_list
207 */
208
209/* built-in 'cd <path>' handler */
210static int builtin_cd(struct child_prog *child)
211{
212 char *newdir;
213
214 if (child->argv[1] == NULL)
215 newdir = getenv("HOME");
216 else
217 newdir = child->argv[1];
218 if (chdir(newdir)) {
219 bb_perror_msg("cd: %s", newdir);
220 return EXIT_FAILURE;
221 }
222 cwd = xgetcwd((char *)cwd);
223 if (!cwd)
224 cwd = bb_msg_unknown;
225 return EXIT_SUCCESS;
226}
227
228/* built-in 'exec' handler */
229static int builtin_exec(struct child_prog *child)
230{
231 if (child->argv[1] == NULL)
232 return EXIT_SUCCESS; /* Really? */
233 child->argv++;
234 while(close_me_list) close((long)llist_pop(&close_me_list));
235 pseudo_exec(child);
236 /* never returns */
237}
238
239/* built-in 'exit' handler */
240static int builtin_exit(struct child_prog *child)
241{
242 if (child->argv[1] == NULL)
243 exit(EXIT_SUCCESS);
244
245 exit (atoi(child->argv[1]));
246}
247
248/* built-in 'fg' and 'bg' handler */
249static int builtin_fg_bg(struct child_prog *child)
250{
251 int i, jobnum;
252 struct job *job=NULL;
253
254 /* If they gave us no args, assume they want the last backgrounded task */
255 if (!child->argv[1]) {
256 for (job = child->family->job_list->head; job; job = job->next) {
257 if (job->jobid == last_jobid) {
258 break;
259 }
260 }
261 if (!job) {
262 bb_error_msg("%s: no current job", child->argv[0]);
263 return EXIT_FAILURE;
264 }
265 } else {
266 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
267 bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]);
268 return EXIT_FAILURE;
269 }
270 for (job = child->family->job_list->head; job; job = job->next) {
271 if (job->jobid == jobnum) {
272 break;
273 }
274 }
275 if (!job) {
276 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);
277 return EXIT_FAILURE;
278 }
279 }
280
281 if (*child->argv[0] == 'f') {
282 /* Put the job into the foreground. */
283 tcsetpgrp(shell_terminal, job->pgrp);
284
285 child->family->job_list->fg = job;
286 }
287
288 /* Restart the processes in the job */
289 for (i = 0; i < job->num_progs; i++)
290 job->progs[i].is_stopped = 0;
291
292 job->stopped_progs = 0;
293
294 if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
295 if (i == ESRCH) {
296 remove_job(&job_list, job);
297 } else {
298 bb_perror_msg("kill (SIGCONT)");
299 }
300 }
301
302 return EXIT_SUCCESS;
303}
304
305/* built-in 'help' handler */
306static int builtin_help(struct child_prog ATTRIBUTE_UNUSED *dummy)
307{
308 struct built_in_command *x;
309
310 printf("\nBuilt-in commands:\n"
311 "-------------------\n");
312 for (x = bltins; x->cmd; x++) {
313 if (x->descr==NULL)
314 continue;
315 printf("%s\t%s\n", x->cmd, x->descr);
316 }
317 for (x = bltins_forking; x->cmd; x++) {
318 if (x->descr==NULL)
319 continue;
320 printf("%s\t%s\n", x->cmd, x->descr);
321 }
322 putchar('\n');
323 return EXIT_SUCCESS;
324}
325
326/* built-in 'jobs' handler */
327static int builtin_jobs(struct child_prog *child)
328{
329 struct job *job;
330 char *status_string;
331
332 for (job = child->family->job_list->head; job; job = job->next) {
333 if (job->running_progs == job->stopped_progs)
334 status_string = "Stopped";
335 else
336 status_string = "Running";
337
338 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
339 }
340 return EXIT_SUCCESS;
341}
342
343
344/* built-in 'pwd' handler */
345static int builtin_pwd(struct child_prog ATTRIBUTE_UNUSED *dummy)
346{
347 cwd = xgetcwd((char *)cwd);
348 if (!cwd)
349 cwd = bb_msg_unknown;
350 puts(cwd);
351 return EXIT_SUCCESS;
352}
353
354/* built-in 'export VAR=value' handler */
355static int builtin_export(struct child_prog *child)
356{
357 int res;
358 char *v = child->argv[1];
359
360 if (v == NULL) {
361 char **e;
362 for (e = environ; *e; e++) {
363 puts(*e);
364 }
365 return 0;
366 }
367 res = putenv(v);
368 if (res)
369 bb_perror_msg("export");
370#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
371 if (strncmp(v, "PS1=", 4)==0)
372 PS1 = getenv("PS1");
373#endif
374
375#ifdef CONFIG_LOCALE_SUPPORT
376 // TODO: why getenv? "" would be just as good...
377 if(strncmp(v, "LC_ALL=", 7)==0)
378 setlocale(LC_ALL, getenv("LC_ALL"));
379 if(strncmp(v, "LC_CTYPE=", 9)==0)
380 setlocale(LC_CTYPE, getenv("LC_CTYPE"));
381#endif
382
383 return res;
384}
385
386/* built-in 'read VAR' handler */
387static int builtin_read(struct child_prog *child)
388{
389 int res = 0, len;
390 char *s;
391 char string[MAX_READ];
392
393 if (child->argv[1]) {
394 /* argument (VAR) given: put "VAR=" into buffer */
395 safe_strncpy(string, child->argv[1], MAX_READ-1);
396 len = strlen(string);
397 string[len++] = '=';
398 string[len] = '\0';
399 fgets(&string[len], sizeof(string) - len, stdin); /* read string */
400 res = strlen(string);
401 if (res > len)
402 string[--res] = '\0'; /* chomp trailing newline */
403 /*
404 ** string should now contain "VAR=<value>"
405 ** copy it (putenv() won't do that, so we must make sure
406 ** the string resides in a static buffer!)
407 */
408 res = -1;
409 if ((s = strdup(string)))
410 res = putenv(s);
411 if (res)
412 bb_perror_msg("read");
413 }
414 else
415 fgets(string, sizeof(string), stdin);
416
417 return res;
418}
419
420/* Built-in '.' handler (read-in and execute commands from file) */
421static int builtin_source(struct child_prog *child)
422{
423 FILE *input;
424 int status;
425
426 input = fopen_or_warn(child->argv[1], "r");
427 if (!input) {
428 return EXIT_FAILURE;
429 }
430
431 llist_add_to(&close_me_list, (void *)(long)fileno(input));
432 /* Now run the file */
433 status = busy_loop(input);
434 fclose(input);
435 llist_pop(&close_me_list);
436 return status;
437}
438
439/* built-in 'unset VAR' handler */
440static int builtin_unset(struct child_prog *child)
441{
442 if (child->argv[1] == NULL) {
443 printf(bb_msg_requires_arg, "unset");
444 return EXIT_FAILURE;
445 }
446 unsetenv(child->argv[1]);
447 return EXIT_SUCCESS;
448}
449
450#ifdef CONFIG_LASH_JOB_CONTROL
451/* free up all memory from a job */
452static void free_job(struct job *cmd)
453{
454 int i;
455 struct jobset *keep;
456
457 for (i = 0; i < cmd->num_progs; i++) {
458 free(cmd->progs[i].argv);
459#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
460 if (cmd->progs[i].redirects)
461 free(cmd->progs[i].redirects);
462#endif
463 }
464 free(cmd->progs);
465 free(cmd->text);
466 free(cmd->cmdbuf);
467 keep = cmd->job_list;
468 memset(cmd, 0, sizeof(struct job));
469 cmd->job_list = keep;
470}
471
472/* remove a job from a jobset */
473static void remove_job(struct jobset *j_list, struct job *job)
474{
475 struct job *prevjob;
476
477 free_job(job);
478 if (job == j_list->head) {
479 j_list->head = job->next;
480 } else {
481 prevjob = j_list->head;
482 while (prevjob->next != job)
483 prevjob = prevjob->next;
484 prevjob->next = job->next;
485 }
486
487 if (j_list->head)
488 last_jobid = j_list->head->jobid;
489 else
490 last_jobid = 0;
491
492 free(job);
493}
494
495/* Checks to see if any background processes have exited -- if they
496 have, figure out why and see if a job has completed */
497static void checkjobs(struct jobset *j_list)
498{
499 struct job *job;
500 pid_t childpid;
501 int status;
502 int prognum = 0;
503
504 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
505 for (job = j_list->head; job; job = job->next) {
506 prognum = 0;
507 while (prognum < job->num_progs &&
508 job->progs[prognum].pid != childpid) prognum++;
509 if (prognum < job->num_progs)
510 break;
511 }
512
513 /* This happens on backticked commands */
514 if(job==NULL)
515 return;
516
517 if (WIFEXITED(status) || WIFSIGNALED(status)) {
518 /* child exited */
519 job->running_progs--;
520 job->progs[prognum].pid = 0;
521
522 if (!job->running_progs) {
523 printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
524 last_jobid=0;
525 remove_job(j_list, job);
526 }
527 } else {
528 /* child stopped */
529 job->stopped_progs++;
530 job->progs[prognum].is_stopped = 1;
531 }
532 }
533
534 if (childpid == -1 && errno != ECHILD)
535 bb_perror_msg("waitpid");
536}
537#else
538static void checkjobs(struct jobset *j_list)
539{
540}
541static void free_job(struct job *cmd)
542{
543}
544static void remove_job(struct jobset *j_list, struct job *job)
545{
546}
547#endif
548
549#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
550/* squirrel != NULL means we squirrel away copies of stdin, stdout,
551 * and stderr if they are redirected. */
552static int setup_redirects(struct child_prog *prog, int squirrel[])
553{
554 int i;
555 int openfd;
556 int mode = O_RDONLY;
557 struct redir_struct *redir = prog->redirects;
558
559 for (i = 0; i < prog->num_redirects; i++, redir++) {
560 switch (redir->type) {
561 case REDIRECT_INPUT:
562 mode = O_RDONLY;
563 break;
564 case REDIRECT_OVERWRITE:
565 mode = O_WRONLY | O_CREAT | O_TRUNC;
566 break;
567 case REDIRECT_APPEND:
568 mode = O_WRONLY | O_CREAT | O_APPEND;
569 break;
570 }
571
572 openfd = open(redir->filename, mode, 0666);
573 if (openfd < 0) {
574 /* this could get lost if stderr has been redirected, but
575 bash and ash both lose it as well (though zsh doesn't!) */
576 bb_perror_msg("error opening %s", redir->filename);
577 return 1;
578 }
579
580 if (openfd != redir->fd) {
581 if (squirrel && redir->fd < 3) {
582 squirrel[redir->fd] = dup(redir->fd);
583 fcntl (squirrel[redir->fd], F_SETFD, FD_CLOEXEC);
584 }
585 dup2(openfd, redir->fd);
586 close(openfd);
587 }
588 }
589
590 return 0;
591}
592
593static void restore_redirects(int squirrel[])
594{
595 int i, fd;
596 for (i=0; i<3; i++) {
597 fd = squirrel[i];
598 if (fd != -1) {
599 /* No error checking. I sure wouldn't know what
600 * to do with an error if I found one! */
601 dup2(fd, i);
602 close(fd);
603 }
604 }
605}
606#else
607static inline int setup_redirects(struct child_prog *prog, int squirrel[])
608{
609 return 0;
610}
611static inline void restore_redirects(int squirrel[])
612{
613}
614#endif
615
616static inline void cmdedit_set_initial_prompt(void)
617{
618#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
619 PS1 = NULL;
620#else
621 PS1 = getenv("PS1");
622 if(PS1==0)
623 PS1 = "\\w \\$ ";
624#endif
625}
626
627static inline void setup_prompt_string(char **prompt_str)
628{
629#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
630 /* Set up the prompt */
631 if (shell_context == 0) {
632 free(PS1);
633 PS1=xmalloc(strlen(cwd)+4);
634 sprintf(PS1, "%s %c ", cwd, ( geteuid() != 0 ) ? '$': '#');
635 *prompt_str = PS1;
636 } else {
637 *prompt_str = PS2;
638 }
639#else
640 *prompt_str = (shell_context==0)? PS1 : PS2;
641#endif
642}
643
644static int get_command(FILE * source, char *command)
645{
646 char *prompt_str;
647
648 if (source == NULL) {
649 if (local_pending_command) {
650 /* a command specified (-c option): return it & mark it done */
651 strcpy(command, local_pending_command);
652 free(local_pending_command);
653 local_pending_command = NULL;
654 return 0;
655 }
656 return 1;
657 }
658
659 if (source == stdin) {
660 setup_prompt_string(&prompt_str);
661
662#ifdef CONFIG_FEATURE_COMMAND_EDITING
663 /*
664 ** enable command line editing only while a command line
665 ** is actually being read; otherwise, we'll end up bequeathing
666 ** atexit() handlers and other unwanted stuff to our
667 ** child processes (rob@sysgo.de)
668 */
669 cmdedit_read_input(prompt_str, command);
670 return 0;
671#else
672 fputs(prompt_str, stdout);
673#endif
674 }
675
676 if (!fgets(command, BUFSIZ - 2, source)) {
677 if (source == stdin)
678 puts("");
679 return 1;
680 }
681
682 return 0;
683}
684
685static char * strsep_space( char *string, int * ix)
686{
687 /* Short circuit the trivial case */
688 if ( !string || ! string[*ix])
689 return NULL;
690
691 /* Find the end of the token. */
692 while (string[*ix] && !isspace(string[*ix]) ) {
693 (*ix)++;
694 }
695
696 /* Find the end of any whitespace trailing behind
697 * the token and let that be part of the token */
698 while (string[*ix] && (isspace)(string[*ix]) ) {
699 (*ix)++;
700 }
701
702 if (!*ix) {
703 /* Nothing useful was found */
704 return NULL;
705 }
706
707 return xstrndup(string, *ix);
708}
709
710static int expand_arguments(char *command)
711{
712 int total_length=0, length, i, retval, ix = 0;
713 expand_t expand_result;
714 char *tmpcmd, *cmd, *cmd_copy;
715 char *src, *dst, *var;
716 const char * const out_of_space = "out of space during expansion";
717 int flags = GLOB_NOCHECK
718#ifdef GLOB_BRACE
719 | GLOB_BRACE
720#endif
721#ifdef GLOB_TILDE
722 | GLOB_TILDE
723#endif
724 ;
725
726 /* get rid of the terminating \n */
727 chomp(command);
728
729 /* Fix up escape sequences to be the Real Thing(tm) */
730 while( command && command[ix]) {
731 if (command[ix] == '\\') {
732 const char *tmp = command+ix+1;
733 command[ix] = bb_process_escape_sequence( &tmp );
734 memmove(command+ix + 1, tmp, strlen(tmp)+1);
735 }
736 ix++;
737 }
738 /* Use glob and then fixup environment variables and such */
739
740 /* It turns out that glob is very stupid. We have to feed it one word at a
741 * time since it can't cope with a full string. Here we convert command
742 * (char*) into cmd (char**, one word per string) */
743
744 /* We need a clean copy, so strsep can mess up the copy while
745 * we write stuff into the original (in a minute) */
746 cmd = cmd_copy = xstrdup(command);
747 *command = '\0';
748 for (ix = 0, tmpcmd = cmd;
749 (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
750 if (*tmpcmd == '\0')
751 break;
752 /* we need to trim() the result for glob! */
753 trim(tmpcmd);
754 retval = glob(tmpcmd, flags, NULL, &expand_result);
755 free(tmpcmd); /* Free mem allocated by strsep_space */
756 if (retval == GLOB_NOSPACE) {
757 /* Mem may have been allocated... */
758 globfree (&expand_result);
759 bb_error_msg(out_of_space);
760 return FALSE;
761 } else if (retval != 0) {
762 /* Some other error. GLOB_NOMATCH shouldn't
763 * happen because of the GLOB_NOCHECK flag in
764 * the glob call. */
765 bb_error_msg("syntax error");
766 return FALSE;
767 } else {
768 /* Convert from char** (one word per string) to a simple char*,
769 * but don't overflow command which is BUFSIZ in length */
770 for (i=0; i < expand_result.gl_pathc; i++) {
771 length=strlen(expand_result.gl_pathv[i]);
772 if (total_length+length+1 >= BUFSIZ) {
773 bb_error_msg(out_of_space);
774 return FALSE;
775 }
776 strcat(command+total_length, " ");
777 total_length+=1;
778 strcat(command+total_length, expand_result.gl_pathv[i]);
779 total_length+=length;
780 }
781 globfree (&expand_result);
782 }
783 }
784 free(cmd_copy);
785 trim(command);
786
787 /* Now do the shell variable substitutions which
788 * wordexp can't do for us, namely $? and $! */
789 src = command;
790 while((dst = strchr(src,'$')) != NULL){
791 var = NULL;
792 switch(*(dst+1)) {
793 case '?':
794 var = itoa(last_return_code);
795 break;
796 case '!':
797 if (last_bg_pid==-1)
798 *(var)='\0';
799 else
800 var = itoa(last_bg_pid);
801 break;
802 /* Everything else like $$, $#, $[0-9], etc. should all be
803 * expanded by wordexp(), so we can in theory skip that stuff
804 * here, but just to be on the safe side (i.e., since uClibc
805 * wordexp doesn't do this stuff yet), lets leave it in for
806 * now. */
807 case '$':
808 var = itoa(getpid());
809 break;
810 case '#':
811 var = itoa(argc-1);
812 break;
813 case '0':case '1':case '2':case '3':case '4':
814 case '5':case '6':case '7':case '8':case '9':
815 {
816 int ixx=*(dst+1)-48+1;
817 if (ixx >= argc) {
818 var='\0';
819 } else {
820 var = argv[ixx];
821 }
822 }
823 break;
824
825 }
826 if (var) {
827 /* a single character construction was found, and
828 * already handled in the case statement */
829 src=dst+2;
830 } else {
831 /* Looks like an environment variable */
832 char delim_hold;
833 int num_skip_chars=0;
834 int dstlen = strlen(dst);
835 /* Is this a ${foo} type variable? */
836 if (dstlen >=2 && *(dst+1) == '{') {
837 src=strchr(dst+1, '}');
838 num_skip_chars=1;
839 } else {
840 src=dst+1;
841 while((isalnum)(*src) || *src=='_') src++;
842 }
843 if (src == NULL) {
844 src = dst+dstlen;
845 }
846 delim_hold=*src;
847 *src='\0'; /* temporary */
848 var = getenv(dst + 1 + num_skip_chars);
849 *src=delim_hold;
850 src += num_skip_chars;
851 }
852 if (var == NULL) {
853 /* Seems we got an un-expandable variable. So delete it. */
854 var = "";
855 }
856 {
857 int subst_len = strlen(var);
858 int trail_len = strlen(src);
859 if (dst+subst_len+trail_len >= command+BUFSIZ) {
860 bb_error_msg(out_of_space);
861 return FALSE;
862 }
863 /* Move stuff to the end of the string to accommodate
864 * filling the created gap with the new stuff */
865 memmove(dst+subst_len, src, trail_len+1);
866 /* Now copy in the new stuff */
867 memcpy(dst, var, subst_len);
868 src = dst+subst_len;
869 }
870 }
871
872 return TRUE;
873}
874
875/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
876 line). If a valid command is found, command_ptr is set to point to
877 the beginning of the next command (if the original command had more
878 then one job associated with it) or NULL if no more commands are
879 present. */
880static int parse_command(char **command_ptr, struct job *job, int *inbg)
881{
882 char *command;
883 char *return_command = NULL;
884 char *src, *buf;
885 int argc_l;
886 int flag;
887 int argv_alloced;
888 char quote = '\0';
889 struct child_prog *prog;
890#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
891 int i;
892 char *chptr;
893#endif
894
895 /* skip leading white space */
896 *command_ptr = skip_whitespace(*command_ptr);
897
898 /* this handles empty lines or leading '#' characters */
899 if (!**command_ptr || (**command_ptr == '#')) {
900 job->num_progs=0;
901 return 0;
902 }
903
904 *inbg = 0;
905 job->num_progs = 1;
906 job->progs = xmalloc(sizeof(*job->progs));
907
908 /* We set the argv elements to point inside of this string. The
909 memory is freed by free_job(). Allocate twice the original
910 length in case we need to quote every single character.
911
912 Getting clean memory relieves us of the task of NULL
913 terminating things and makes the rest of this look a bit
914 cleaner (though it is, admittedly, a tad less efficient) */
915 job->cmdbuf = command = xzalloc(2*strlen(*command_ptr) + 1);
916 job->text = NULL;
917
918 prog = job->progs;
919 prog->num_redirects = 0;
920 prog->is_stopped = 0;
921 prog->family = job;
922#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
923 prog->redirects = NULL;
924#endif
925
926 argv_alloced = 5;
927 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
928 prog->argv[0] = job->cmdbuf;
929
930 flag = argc_l = 0;
931 buf = command;
932 src = *command_ptr;
933 while (*src && !(flag & LASH_OPT_DONE)) {
934 if (quote == *src) {
935 quote = '\0';
936 } else if (quote) {
937 if (*src == '\\') {
938 src++;
939 if (!*src) {
940 bb_error_msg("character expected after \\");
941 free_job(job);
942 return 1;
943 }
944
945 /* in shell, "\'" should yield \' */
946 if (*src != quote) {
947 *buf++ = '\\';
948 *buf++ = '\\';
949 }
950 } else if (*src == '*' || *src == '?' || *src == '[' ||
951 *src == ']') *buf++ = '\\';
952 *buf++ = *src;
953 } else if (isspace(*src)) {
954 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) {
955 buf++, argc_l++;
956 /* +1 here leaves room for the NULL which ends argv */
957 if ((argc_l + 1) == argv_alloced) {
958 argv_alloced += 5;
959 prog->argv = xrealloc(prog->argv,
960 sizeof(*prog->argv) *
961 argv_alloced);
962 }
963 prog->argv[argc_l] = buf;
964 flag ^= LASH_OPT_SAW_QUOTE;
965 }
966 } else
967 switch (*src) {
968 case '"':
969 case '\'':
970 quote = *src;
971 flag |= LASH_OPT_SAW_QUOTE;
972 break;
973
974 case '#': /* comment */
975 if (*(src-1)== '$')
976 *buf++ = *src;
977 else
978 flag |= LASH_OPT_DONE;
979 break;
980
981#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
982 case '>': /* redirects */
983 case '<':
984 i = prog->num_redirects++;
985 prog->redirects = xrealloc(prog->redirects,
986 sizeof(*prog->redirects) *
987 (i + 1));
988
989 prog->redirects[i].fd = -1;
990 if (buf != prog->argv[argc_l]) {
991 /* the stuff before this character may be the file number
992 being redirected */
993 prog->redirects[i].fd =
994 strtol(prog->argv[argc_l], &chptr, 10);
995
996 if (*chptr && *prog->argv[argc_l]) {
997 buf++, argc_l++;
998 prog->argv[argc_l] = buf;
999 }
1000 }
1001
1002 if (prog->redirects[i].fd == -1) {
1003 if (*src == '>')
1004 prog->redirects[i].fd = 1;
1005 else
1006 prog->redirects[i].fd = 0;
1007 }
1008
1009 if (*src++ == '>') {
1010 if (*src == '>')
1011 prog->redirects[i].type =
1012 REDIRECT_APPEND, src++;
1013 else
1014 prog->redirects[i].type = REDIRECT_OVERWRITE;
1015 } else {
1016 prog->redirects[i].type = REDIRECT_INPUT;
1017 }
1018
1019 /* This isn't POSIX sh compliant. Oh well. */
1020 chptr = src;
1021 chptr = skip_whitespace(chptr);
1022
1023 if (!*chptr) {
1024 bb_error_msg("file name expected after %c", *(src-1));
1025 free_job(job);
1026 job->num_progs=0;
1027 return 1;
1028 }
1029
1030 prog->redirects[i].filename = buf;
1031 while (*chptr && !isspace(*chptr))
1032 *buf++ = *chptr++;
1033
1034 src = chptr - 1; /* we src++ later */
1035 prog->argv[argc_l] = ++buf;
1036 break;
1037
1038 case '|': /* pipe */
1039 /* finish this command */
1040 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE)
1041 argc_l++;
1042 if (!argc_l) {
1043 goto empty_command_in_pipe;
1044 }
1045 prog->argv[argc_l] = NULL;
1046
1047 /* and start the next */
1048 job->num_progs++;
1049 job->progs = xrealloc(job->progs,
1050 sizeof(*job->progs) * job->num_progs);
1051 prog = job->progs + (job->num_progs - 1);
1052 prog->num_redirects = 0;
1053 prog->redirects = NULL;
1054 prog->is_stopped = 0;
1055 prog->family = job;
1056 argc_l = 0;
1057
1058 argv_alloced = 5;
1059 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
1060 prog->argv[0] = ++buf;
1061
1062 src++;
1063 src = skip_whitespace(src);
1064
1065 if (!*src) {
1066empty_command_in_pipe:
1067 bb_error_msg("empty command in pipe");
1068 free_job(job);
1069 job->num_progs=0;
1070 return 1;
1071 }
1072 src--; /* we'll ++ it at the end of the loop */
1073
1074 break;
1075#endif
1076
1077#ifdef CONFIG_LASH_JOB_CONTROL
1078 case '&': /* background */
1079 *inbg = 1;
1080 /* fallthrough */
1081#endif
1082 case ';': /* multiple commands */
1083 flag |= LASH_OPT_DONE;
1084 return_command = *command_ptr + (src - *command_ptr) + 1;
1085 break;
1086
1087 case '\\':
1088 src++;
1089 if (!*src) {
1090 bb_error_msg("character expected after \\");
1091 free_job(job);
1092 return 1;
1093 }
1094 if (*src == '*' || *src == '[' || *src == ']'
1095 || *src == '?') *buf++ = '\\';
1096 /* fallthrough */
1097 default:
1098 *buf++ = *src;
1099 }
1100
1101 src++;
1102 }
1103
1104 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) {
1105 argc_l++;
1106 }
1107 if (!argc_l) {
1108 free_job(job);
1109 return 0;
1110 }
1111 prog->argv[argc_l] = NULL;
1112
1113 if (!return_command) {
1114 job->text = xstrdup(*command_ptr);
1115 } else {
1116 /* This leaves any trailing spaces, which is a bit sloppy */
1117 job->text = xstrndup(*command_ptr, return_command - *command_ptr);
1118 }
1119
1120 *command_ptr = return_command;
1121
1122 return 0;
1123}
1124
1125/* Run the child_prog, no matter what kind of command it uses.
1126 */
1127static int pseudo_exec(struct child_prog *child)
1128{
1129 struct built_in_command *x;
1130
1131 /* Check if the command matches any of the non-forking builtins.
1132 * Depending on context, this might be redundant. But it's
1133 * easier to waste a few CPU cycles than it is to figure out
1134 * if this is one of those cases.
1135 */
1136 for (x = bltins; x->cmd; x++) {
1137 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1138 _exit(x->function(child));
1139 }
1140 }
1141
1142 /* Check if the command matches any of the forking builtins. */
1143 for (x = bltins_forking; x->cmd; x++) {
1144 if (strcmp(child->argv[0], x->cmd) == 0) {
1145 applet_name=x->cmd;
1146 _exit (x->function(child));
1147 }
1148 }
1149
1150 /* Check if the command matches any busybox internal
1151 * commands ("applets") here. Following discussions from
1152 * November 2000 on busybox@busybox.net, don't use
1153 * bb_get_last_path_component(). This way explicit (with
1154 * slashes) filenames will never be interpreted as an
1155 * applet, just like with builtins. This way the user can
1156 * override an applet with an explicit filename reference.
1157 * The only downside to this change is that an explicit
1158 * /bin/foo invocation will fork and exec /bin/foo, even if
1159 * /bin/foo is a symlink to busybox.
1160 */
1161
1162 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
1163 char **argv_l = child->argv;
1164 int argc_l;
1165
1166 for(argc_l=0; *argv_l; argv_l++, argc_l++);
1167 optind = 1;
1168 run_applet_by_name(child->argv[0], argc_l, child->argv);
1169 }
1170
1171 execvp(child->argv[0], child->argv);
1172
1173 /* Do not use bb_perror_msg_and_die() here, since we must not
1174 * call exit() but should call _exit() instead */
1175 bb_perror_msg("%s", child->argv[0]);
1176 _exit(EXIT_FAILURE);
1177}
1178
1179static void insert_job(struct job *newjob, int inbg)
1180{
1181 struct job *thejob;
1182 struct jobset *j_list=newjob->job_list;
1183
1184 /* find the ID for thejob to use */
1185 newjob->jobid = 1;
1186 for (thejob = j_list->head; thejob; thejob = thejob->next)
1187 if (thejob->jobid >= newjob->jobid)
1188 newjob->jobid = thejob->jobid + 1;
1189
1190 /* add thejob to the list of running jobs */
1191 if (!j_list->head) {
1192 thejob = j_list->head = xmalloc(sizeof(*thejob));
1193 } else {
1194 for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */;
1195 thejob->next = xmalloc(sizeof(*thejob));
1196 thejob = thejob->next;
1197 }
1198
1199 *thejob = *newjob; /* physically copy the struct job */
1200 thejob->next = NULL;
1201 thejob->running_progs = thejob->num_progs;
1202 thejob->stopped_progs = 0;
1203
1204#ifdef CONFIG_LASH_JOB_CONTROL
1205 if (inbg) {
1206 /* we don't wait for background thejobs to return -- append it
1207 to the list of backgrounded thejobs and leave it alone */
1208 printf("[%d] %d\n", thejob->jobid,
1209 newjob->progs[newjob->num_progs - 1].pid);
1210 last_jobid = newjob->jobid;
1211 last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
1212 } else {
1213 newjob->job_list->fg = thejob;
1214
1215 /* move the new process group into the foreground */
1216 /* Ignore errors since child could have already exited */
1217 tcsetpgrp(shell_terminal, newjob->pgrp);
1218 }
1219#endif
1220}
1221
1222static int run_command(struct job *newjob, int inbg, int outpipe[2])
1223{
1224 /* struct job *thejob; */
1225 int i;
1226 int nextin, nextout;
1227 int pipefds[2]; /* pipefd[0] is for reading */
1228 struct built_in_command *x;
1229 struct child_prog *child;
1230
1231 nextin = 0, nextout = 1;
1232 for (i = 0; i < newjob->num_progs; i++) {
1233 child = & (newjob->progs[i]);
1234
1235 if ((i + 1) < newjob->num_progs) {
1236 if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");
1237 nextout = pipefds[1];
1238 } else {
1239 if (outpipe[1]!=-1) {
1240 nextout = outpipe[1];
1241 } else {
1242 nextout = 1;
1243 }
1244 }
1245
1246
1247 /* Check if the command matches any non-forking builtins,
1248 * but only if this is a simple command.
1249 * Non-forking builtins within pipes have to fork anyway,
1250 * and are handled in pseudo_exec. "echo foo | read bar"
1251 * is doomed to failure, and doesn't work on bash, either.
1252 */
1253 if (newjob->num_progs == 1) {
1254 /* Check if the command sets an environment variable. */
1255 if (strchr(child->argv[0], '=') != NULL) {
1256 child->argv[1] = child->argv[0];
1257 return builtin_export(child);
1258 }
1259
1260 for (x = bltins; x->cmd; x++) {
1261 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1262 int rcode;
1263 int squirrel[] = {-1, -1, -1};
1264 setup_redirects(child, squirrel);
1265 rcode = x->function(child);
1266 restore_redirects(squirrel);
1267 return rcode;
1268 }
1269 }
1270 }
1271
1272#if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
1273 if (!(child->pid = fork()))
1274#else
1275 if (!(child->pid = vfork()))
1276#endif
1277 {
1278 /* Set the handling for job control signals back to the default. */
1279 signal(SIGINT, SIG_DFL);
1280 signal(SIGQUIT, SIG_DFL);
1281 signal(SIGTSTP, SIG_DFL);
1282 signal(SIGTTIN, SIG_DFL);
1283 signal(SIGTTOU, SIG_DFL);
1284 signal(SIGCHLD, SIG_DFL);
1285
1286 /* Close all open filehandles. */
1287 while(close_me_list) close((long)llist_pop(&close_me_list));
1288
1289 if (outpipe[1]!=-1) {
1290 close(outpipe[0]);
1291 }
1292 if (nextin != 0) {
1293 dup2(nextin, 0);
1294 close(nextin);
1295 }
1296
1297 if (nextout != 1) {
1298 dup2(nextout, 1);
1299 dup2(nextout, 2); /* Really? */
1300 close(nextout);
1301 close(pipefds[0]);
1302 }
1303
1304 /* explicit redirects override pipes */
1305 setup_redirects(child,NULL);
1306
1307 pseudo_exec(child);
1308 }
1309 if (outpipe[1]!=-1) {
1310 close(outpipe[1]);
1311 }
1312
1313 /* put our child in the process group whose leader is the
1314 first process in this pipe */
1315 setpgid(child->pid, newjob->progs[0].pid);
1316 if (nextin != 0)
1317 close(nextin);
1318 if (nextout != 1)
1319 close(nextout);
1320
1321 /* If there isn't another process, nextin is garbage
1322 but it doesn't matter */
1323 nextin = pipefds[0];
1324 }
1325
1326 newjob->pgrp = newjob->progs[0].pid;
1327
1328 insert_job(newjob, inbg);
1329
1330 return 0;
1331}
1332
1333static int busy_loop(FILE * input)
1334{
1335 char *command;
1336 char *next_command = NULL;
1337 struct job newjob;
1338 int i;
1339 int inbg = 0;
1340 int status;
1341#ifdef CONFIG_LASH_JOB_CONTROL
1342 pid_t parent_pgrp;
1343 /* save current owner of TTY so we can restore it on exit */
1344 parent_pgrp = tcgetpgrp(shell_terminal);
1345#endif
1346 newjob.job_list = &job_list;
1347 newjob.job_context = DEFAULT_CONTEXT;
1348
1349 command = xzalloc(BUFSIZ);
1350
1351 while (1) {
1352 if (!job_list.fg) {
1353 /* no job is in the foreground */
1354
1355 /* see if any background processes have exited */
1356 checkjobs(&job_list);
1357
1358 if (!next_command) {
1359 if (get_command(input, command))
1360 break;
1361 next_command = command;
1362 }
1363
1364 if (! expand_arguments(next_command)) {
1365 free(command);
1366 command = xzalloc(BUFSIZ);
1367 next_command = NULL;
1368 continue;
1369 }
1370
1371 if (!parse_command(&next_command, &newjob, &inbg) &&
1372 newjob.num_progs) {
1373 int pipefds[2] = {-1,-1};
1374 debug_printf( "job=%p fed to run_command by busy_loop()'\n",
1375 &newjob);
1376 run_command(&newjob, inbg, pipefds);
1377 }
1378 else {
1379 free(command);
1380 command = (char *) xzalloc(BUFSIZ);
1381 next_command = NULL;
1382 }
1383 } else {
1384 /* a job is running in the foreground; wait for it */
1385 i = 0;
1386 while (!job_list.fg->progs[i].pid ||
1387 job_list.fg->progs[i].is_stopped == 1) i++;
1388
1389 if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) {
1390 if (errno != ECHILD) {
1391 bb_perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
1392 }
1393 }
1394
1395 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1396 /* the child exited */
1397 job_list.fg->running_progs--;
1398 job_list.fg->progs[i].pid = 0;
1399
1400 last_return_code=WEXITSTATUS(status);
1401
1402 if (!job_list.fg->running_progs) {
1403 /* child exited */
1404 remove_job(&job_list, job_list.fg);
1405 job_list.fg = NULL;
1406 }
1407 }
1408#ifdef CONFIG_LASH_JOB_CONTROL
1409 else {
1410 /* the child was stopped */
1411 job_list.fg->stopped_progs++;
1412 job_list.fg->progs[i].is_stopped = 1;
1413
1414 if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
1415 printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
1416 "Stopped", job_list.fg->text);
1417 job_list.fg = NULL;
1418 }
1419 }
1420
1421 if (!job_list.fg) {
1422 /* move the shell to the foreground */
1423 /* suppress messages when run from /linuxrc mag@sysgo.de */
1424 if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY)
1425 bb_perror_msg("tcsetpgrp");
1426 }
1427#endif
1428 }
1429 }
1430 free(command);
1431
1432#ifdef CONFIG_LASH_JOB_CONTROL
1433 /* return controlling TTY back to parent process group before exiting */
1434 if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY)
1435 bb_perror_msg("tcsetpgrp");
1436#endif
1437
1438 /* return exit status if called with "-c" */
1439 if (input == NULL && WIFEXITED(status))
1440 return WEXITSTATUS(status);
1441
1442 return 0;
1443}
1444
1445#ifdef CONFIG_FEATURE_CLEAN_UP
1446static void free_memory(void)
1447{
1448 if (cwd && cwd!=bb_msg_unknown) {
1449 free((char*)cwd);
1450 }
1451 if (local_pending_command)
1452 free(local_pending_command);
1453
1454 if (job_list.fg && !job_list.fg->running_progs) {
1455 remove_job(&job_list, job_list.fg);
1456 }
1457}
1458#else
1459void free_memory(void);
1460#endif
1461
1462#ifdef CONFIG_LASH_JOB_CONTROL
1463/* Make sure we have a controlling tty. If we get started under a job
1464 * aware app (like bash for example), make sure we are now in charge so
1465 * we don't fight over who gets the foreground */
1466static void setup_job_control(void)
1467{
1468 int status;
1469 pid_t shell_pgrp;
1470
1471 /* Loop until we are in the foreground. */
1472 while ((status = tcgetpgrp (shell_terminal)) >= 0) {
1473 if (status == (shell_pgrp = getpgrp ())) {
1474 break;
1475 }
1476 kill (- shell_pgrp, SIGTTIN);
1477 }
1478
1479 /* Ignore interactive and job-control signals. */
1480 signal(SIGINT, SIG_IGN);
1481 signal(SIGQUIT, SIG_IGN);
1482 signal(SIGTSTP, SIG_IGN);
1483 signal(SIGTTIN, SIG_IGN);
1484 signal(SIGTTOU, SIG_IGN);
1485 signal(SIGCHLD, SIG_IGN);
1486
1487 /* Put ourselves in our own process group. */
1488 setsid();
1489 shell_pgrp = getpid ();
1490 setpgid(shell_pgrp, shell_pgrp);
1491
1492 /* Grab control of the terminal. */
1493 tcsetpgrp(shell_terminal, shell_pgrp);
1494}
1495#else
1496static inline void setup_job_control(void)
1497{
1498}
1499#endif
1500
1501int lash_main(int argc_l, char **argv_l)
1502{
1503 unsigned opt;
1504 FILE *input = stdin;
1505 argc = argc_l;
1506 argv = argv_l;
1507
1508 /* These variables need re-initializing when recursing */
1509 last_jobid = 0;
1510 close_me_list = NULL;
1511 job_list.head = NULL;
1512 job_list.fg = NULL;
1513 last_return_code=1;
1514
1515 if (argv[0] && argv[0][0] == '-') {
1516 FILE *prof_input;
1517 prof_input = fopen("/etc/profile", "r");
1518 if (prof_input) {
1519 llist_add_to(&close_me_list, (void *)(long)fileno(prof_input));
1520 /* Now run the file */
1521 busy_loop(prof_input);
1522 fclose_if_not_stdin(prof_input);
1523 llist_pop(&close_me_list);
1524 }
1525 }
1526
1527 opt = getopt32(argc_l, argv_l, "+ic:", &local_pending_command);
1528#define LASH_OPT_i (1<<0)
1529#define LASH_OPT_c (1<<2)
1530 if (opt & LASH_OPT_c) {
1531 input = NULL;
1532 optind++;
1533 argv += optind;
1534 }
1535 /* A shell is interactive if the `-i' flag was given, or if all of
1536 * the following conditions are met:
1537 * no -c command
1538 * no arguments remaining or the -s flag given
1539 * standard input is a terminal
1540 * standard output is a terminal
1541 * Refer to Posix.2, the description of the `sh' utility. */
1542 if (argv[optind]==NULL && input==stdin &&
1543 isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))
1544 {
1545 opt |= LASH_OPT_i;
1546 }
1547 setup_job_control();
1548 if (opt & LASH_OPT_i) {
1549 /* Looks like they want an interactive shell */
1550 if (!ENABLE_FEATURE_SH_EXTRA_QUIET) {
1551 printf("\n\n%s Built-in shell (lash)\n"
1552 "Enter 'help' for a list of built-in commands.\n\n",
1553 BB_BANNER);
1554 }
1555 } else if (!local_pending_command && argv[optind]) {
1556 //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
1557 input = xfopen(argv[optind], "r");
1558 /* be lazy, never mark this closed */
1559 llist_add_to(&close_me_list, (void *)(long)fileno(input));
1560 }
1561
1562 /* initialize the cwd -- this is never freed...*/
1563 cwd = xgetcwd(0);
1564 if (!cwd)
1565 cwd = bb_msg_unknown;
1566
1567 if (ENABLE_FEATURE_CLEAN_UP) atexit(free_memory);
1568
1569 if (ENABLE_FEATURE_COMMAND_EDITING) cmdedit_set_initial_prompt();
1570 else PS1 = NULL;
1571
1572 return (busy_loop(input));
1573}
diff --git a/shell/msh.c b/shell/msh.c
new file mode 100644
index 000000000..492d3cf43
--- /dev/null
+++ b/shell/msh.c
@@ -0,0 +1,5250 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Minix shell port for busybox
4 *
5 * This version of the Minix shell was adapted for use in busybox
6 * by Erik Andersen <andersen@codepoet.org>
7 *
8 * - backtick expansion did not work properly
9 * Jonas Holmberg <jonas.holmberg@axis.com>
10 * Robert Schwebel <r.schwebel@pengutronix.de>
11 * Erik Andersen <andersen@codepoet.org>
12 *
13 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
14 */
15
16#include "busybox.h"
17#include <setjmp.h>
18#include <sys/times.h>
19
20#include "cmdedit.h"
21
22/*#define MSHDEBUG 1*/
23
24#ifdef MSHDEBUG
25int mshdbg = MSHDEBUG;
26
27#define DBGPRINTF(x) if(mshdbg>0)printf x
28#define DBGPRINTF0(x) if(mshdbg>0)printf x
29#define DBGPRINTF1(x) if(mshdbg>1)printf x
30#define DBGPRINTF2(x) if(mshdbg>2)printf x
31#define DBGPRINTF3(x) if(mshdbg>3)printf x
32#define DBGPRINTF4(x) if(mshdbg>4)printf x
33#define DBGPRINTF5(x) if(mshdbg>5)printf x
34#define DBGPRINTF6(x) if(mshdbg>6)printf x
35#define DBGPRINTF7(x) if(mshdbg>7)printf x
36#define DBGPRINTF8(x) if(mshdbg>8)printf x
37#define DBGPRINTF9(x) if(mshdbg>9)printf x
38
39int mshdbg_rc = 0;
40
41#define RCPRINTF(x) if(mshdbg_rc)printf x
42
43#else
44
45#define DBGPRINTF(x)
46#define DBGPRINTF0(x)
47#define DBGPRINTF1(x)
48#define DBGPRINTF2(x)
49#define DBGPRINTF3(x)
50#define DBGPRINTF4(x)
51#define DBGPRINTF5(x)
52#define DBGPRINTF6(x)
53#define DBGPRINTF7(x)
54#define DBGPRINTF8(x)
55#define DBGPRINTF9(x)
56
57#define RCPRINTF(x)
58
59#endif /* MSHDEBUG */
60
61
62#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
63# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
64# define DEFAULT_USER_PROMPT "\\u:\\w$ "
65#else
66# define DEFAULT_ROOT_PROMPT "# "
67# define DEFAULT_USER_PROMPT "$ "
68#endif
69
70
71/* -------- sh.h -------- */
72/*
73 * shell
74 */
75
76#define LINELIM 2100
77#define NPUSH 8 /* limit to input nesting */
78
79#undef NOFILE
80#define NOFILE 20 /* Number of open files */
81#define NUFILE 10 /* Number of user-accessible files */
82#define FDBASE 10 /* First file usable by Shell */
83
84/*
85 * values returned by wait
86 */
87#define WAITSIG(s) ((s)&0177)
88#define WAITVAL(s) (((s)>>8)&0377)
89#define WAITCORE(s) (((s)&0200)!=0)
90
91/*
92 * library and system definitions
93 */
94typedef void xint; /* base type of jmp_buf, for not broken compilers */
95
96/*
97 * shell components
98 */
99
100#define QUOTE 0200
101
102#define NOBLOCK ((struct op *)NULL)
103#define NOWORD ((char *)NULL)
104#define NOWORDS ((char **)NULL)
105#define NOPIPE ((int *)NULL)
106
107/*
108 * Description of a command or an operation on commands.
109 * Might eventually use a union.
110 */
111struct op {
112 int type; /* operation type, see below */
113 char **words; /* arguments to a command */
114 struct ioword **ioact; /* IO actions (eg, < > >>) */
115 struct op *left;
116 struct op *right;
117 char *str; /* identifier for case and for */
118};
119
120#define TCOM 1 /* command */
121#define TPAREN 2 /* (c-list) */
122#define TPIPE 3 /* a | b */
123#define TLIST 4 /* a [&;] b */
124#define TOR 5 /* || */
125#define TAND 6 /* && */
126#define TFOR 7
127#define TDO 8
128#define TCASE 9
129#define TIF 10
130#define TWHILE 11
131#define TUNTIL 12
132#define TELIF 13
133#define TPAT 14 /* pattern in case */
134#define TBRACE 15 /* {c-list} */
135#define TASYNC 16 /* c & */
136/* Added to support "." file expansion */
137#define TDOT 17
138
139/* Strings for names to make debug easier */
140#ifdef MSHDEBUG
141static char *T_CMD_NAMES[] = {
142 "PLACEHOLDER",
143 "TCOM",
144 "TPAREN",
145 "TPIPE",
146 "TLIST",
147 "TOR",
148 "TAND",
149 "TFOR",
150 "TDO",
151 "TCASE",
152 "TIF",
153 "TWHILE",
154 "TUNTIL",
155 "TELIF",
156 "TPAT",
157 "TBRACE",
158 "TASYNC",
159 "TDOT",
160};
161#endif
162
163/*
164 * actions determining the environment of a process
165 */
166#define BIT(i) (1<<(i))
167#define FEXEC BIT(0) /* execute without forking */
168
169#define AREASIZE (90000)
170
171/*
172 * flags to control evaluation of words
173 */
174#define DOSUB 1 /* interpret $, `, and quotes */
175#define DOBLANK 2 /* perform blank interpretation */
176#define DOGLOB 4 /* interpret [?* */
177#define DOKEY 8 /* move words with `=' to 2nd arg. list */
178#define DOTRIM 16 /* trim resulting string */
179
180#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
181
182
183/* PROTOTYPES */
184static int newfile(char *s);
185static char *findeq(char *cp);
186static char *cclass(char *p, int sub);
187static void initarea(void);
188extern int msh_main(int argc, char **argv);
189
190
191struct brkcon {
192 jmp_buf brkpt;
193 struct brkcon *nextlev;
194};
195
196
197/*
198 * redirection
199 */
200struct ioword {
201 short io_unit; /* unit affected */
202 short io_flag; /* action (below) */
203 char *io_name; /* file name */
204};
205
206#define IOREAD 1 /* < */
207#define IOHERE 2 /* << (here file) */
208#define IOWRITE 4 /* > */
209#define IOCAT 8 /* >> */
210#define IOXHERE 16 /* ${}, ` in << */
211#define IODUP 32 /* >&digit */
212#define IOCLOSE 64 /* >&- */
213
214#define IODEFAULT (-1) /* token for default IO unit */
215
216
217
218/*
219 * parsing & execution environment
220 */
221static struct env {
222 char *linep;
223 struct io *iobase;
224 struct io *iop;
225 xint *errpt; /* void * */
226 int iofd;
227 struct env *oenv;
228} e;
229
230/*
231 * flags:
232 * -e: quit on error
233 * -k: look for name=value everywhere on command line
234 * -n: no execution
235 * -t: exit after reading and executing one command
236 * -v: echo as read
237 * -x: trace
238 * -u: unset variables net diagnostic
239 */
240static char flags['z' - 'a' + 1];
241/* this looks weird, but is OK ... we index flag with 'a'...'z' */
242static char *flag = flags - 'a';
243
244static char *null; /* null value for variable */
245static int intr; /* interrupt pending */
246
247static char *trap[_NSIG + 1];
248static char ourtrap[_NSIG + 1];
249static int trapset; /* trap pending */
250
251static int heedint; /* heed interrupt signals */
252
253static int yynerrs; /* yacc */
254
255static char line[LINELIM];
256static char *elinep;
257
258
259/*
260 * other functions
261 */
262static int (*inbuilt(char *s)) (struct op *);
263
264static char *rexecve(char *c, char **v, char **envp);
265static char *space(int n);
266static char *strsave(char *s, int a);
267static char *evalstr(char *cp, int f);
268static char *putn(int n);
269static char *unquote(char *as);
270static struct var *lookup(char *n);
271static int rlookup(char *n);
272static struct wdblock *glob(char *cp, struct wdblock *wb);
273static int my_getc(int ec);
274static int subgetc(char ec, int quoted);
275static char **makenv(int all, struct wdblock *wb);
276static char **eval(char **ap, int f);
277static int setstatus(int s);
278static int waitfor(int lastpid, int canintr);
279
280static void onintr(int s); /* SIGINT handler */
281
282static int newenv(int f);
283static void quitenv(void);
284static void err(char *s);
285static int anys(char *s1, char *s2);
286static int any(int c, char *s);
287static void next(int f);
288static void setdash(void);
289static void onecommand(void);
290static void runtrap(int i);
291static int gmatch(char *s, char *p);
292
293
294/*
295 * error handling
296 */
297static void leave(void); /* abort shell (or fail in subshell) */
298static void fail(void); /* fail but return to process next command */
299static void warn(char *s);
300static void sig(int i); /* default signal handler */
301
302
303
304/* -------- area stuff -------- */
305
306#define REGSIZE sizeof(struct region)
307#define GROWBY (256)
308/* #define SHRINKBY (64) */
309#undef SHRINKBY
310#define FREE (32767)
311#define BUSY (0)
312#define ALIGN (sizeof(int)-1)
313
314
315struct region {
316 struct region *next;
317 int area;
318};
319
320
321
322/* -------- grammar stuff -------- */
323typedef union {
324 char *cp;
325 char **wp;
326 int i;
327 struct op *o;
328} YYSTYPE;
329
330#define WORD 256
331#define LOGAND 257
332#define LOGOR 258
333#define BREAK 259
334#define IF 260
335#define THEN 261
336#define ELSE 262
337#define ELIF 263
338#define FI 264
339#define CASE 265
340#define ESAC 266
341#define FOR 267
342#define WHILE 268
343#define UNTIL 269
344#define DO 270
345#define DONE 271
346#define IN 272
347/* Added for "." file expansion */
348#define DOT 273
349
350#define YYERRCODE 300
351
352/* flags to yylex */
353#define CONTIN 01 /* skip new lines to complete command */
354
355#define SYNTAXERR zzerr()
356
357static struct op *pipeline(int cf);
358static struct op *andor(void);
359static struct op *c_list(void);
360static int synio(int cf);
361static void musthave(int c, int cf);
362static struct op *simple(void);
363static struct op *nested(int type, int mark);
364static struct op *command(int cf);
365static struct op *dogroup(int onlydone);
366static struct op *thenpart(void);
367static struct op *elsepart(void);
368static struct op *caselist(void);
369static struct op *casepart(void);
370static char **pattern(void);
371static char **wordlist(void);
372static struct op *list(struct op *t1, struct op *t2);
373static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
374static struct op *newtp(void);
375static struct op *namelist(struct op *t);
376static char **copyw(void);
377static void word(char *cp);
378static struct ioword **copyio(void);
379static struct ioword *io(int u, int f, char *cp);
380static void zzerr(void);
381static void yyerror(char *s);
382static int yylex(int cf);
383static int collect(int c, int c1);
384static int dual(int c);
385static void diag(int ec);
386static char *tree(unsigned size);
387
388/* -------- var.h -------- */
389
390struct var {
391 char *value;
392 char *name;
393 struct var *next;
394 char status;
395};
396
397#define COPYV 1 /* flag to setval, suggesting copy */
398#define RONLY 01 /* variable is read-only */
399#define EXPORT 02 /* variable is to be exported */
400#define GETCELL 04 /* name & value space was got with getcell */
401
402static int yyparse(void);
403static struct var *lookup(char *n);
404static void setval(struct var *vp, char *val);
405static void nameval(struct var *vp, char *val, char *name);
406static void export(struct var *vp);
407static void ronly(struct var *vp);
408static int isassign(char *s);
409static int checkname(char *cp);
410static int assign(char *s, int cf);
411static void putvlist(int f, int out);
412static int eqname(char *n1, char *n2);
413
414static int execute(struct op *t, int *pin, int *pout, int act);
415
416
417/* -------- io.h -------- */
418/* io buffer */
419struct iobuf {
420 unsigned id; /* buffer id */
421 char buf[512]; /* buffer */
422 char *bufp; /* pointer into buffer */
423 char *ebufp; /* pointer to end of buffer */
424};
425
426/* possible arguments to an IO function */
427struct ioarg {
428 char *aword;
429 char **awordlist;
430 int afile; /* file descriptor */
431 unsigned afid; /* buffer id */
432 long afpos; /* file position */
433 struct iobuf *afbuf; /* buffer for this file */
434};
435
436//static struct ioarg ioargstack[NPUSH];
437#define AFID_NOBUF (~0)
438#define AFID_ID 0
439
440/* an input generator's state */
441struct io {
442 int (*iofn) (struct ioarg *, struct io *);
443 struct ioarg *argp;
444 int peekc;
445 char prev; /* previous character read by readc() */
446 char nlcount; /* for `'s */
447 char xchar; /* for `'s */
448 char task; /* reason for pushed IO */
449};
450
451//static struct io iostack[NPUSH];
452#define XOTHER 0 /* none of the below */
453#define XDOLL 1 /* expanding ${} */
454#define XGRAVE 2 /* expanding `'s */
455#define XIO 3 /* file IO */
456
457/* in substitution */
458#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
459
460
461/*
462 * input generators for IO structure
463 */
464static int nlchar(struct ioarg *ap);
465static int strchar(struct ioarg *ap);
466static int qstrchar(struct ioarg *ap);
467static int filechar(struct ioarg *ap);
468static int herechar(struct ioarg *ap);
469static int linechar(struct ioarg *ap);
470static int gravechar(struct ioarg *ap, struct io *iop);
471static int qgravechar(struct ioarg *ap, struct io *iop);
472static int dolchar(struct ioarg *ap);
473static int wdchar(struct ioarg *ap);
474static void scraphere(void);
475static void freehere(int area);
476static void gethere(void);
477static void markhere(char *s, struct ioword *iop);
478static int herein(char *hname, int xdoll);
479static int run(struct ioarg *argp, int (*f) (struct ioarg *));
480
481
482/*
483 * IO functions
484 */
485static int eofc(void);
486static int readc(void);
487static void unget(int c);
488static void ioecho(char c);
489static void prs(const char *s);
490static void prn(unsigned u);
491static void closef(int i);
492static void closeall(void);
493
494
495/*
496 * IO control
497 */
498static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
499static int remap(int fd);
500static int openpipe(int *pv);
501static void closepipe(int *pv);
502static struct io *setbase(struct io *ip);
503
504#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
505#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
506
507/* -------- word.h -------- */
508
509#define NSTART 16 /* default number of words to allow for initially */
510
511struct wdblock {
512 short w_bsize;
513 short w_nword;
514 /* bounds are arbitrary */
515 char *w_words[1];
516};
517
518static struct wdblock *addword(char *wd, struct wdblock *wb);
519static struct wdblock *newword(int nw);
520static char **getwords(struct wdblock *wb);
521
522/* -------- area.h -------- */
523
524/*
525 * storage allocation
526 */
527static char *getcell(unsigned nbytes);
528static void garbage(void);
529static void setarea(char *cp, int a);
530static int getarea(char *cp);
531static void freearea(int a);
532static void freecell(char *cp);
533static int areanum; /* current allocation area */
534
535#define NEW(type) (type *)getcell(sizeof(type))
536#define DELETE(obj) freecell((char *)obj)
537
538
539/* -------- misc stuff -------- */
540
541static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
542static int iosetup(struct ioword *iop, int pipein, int pipeout);
543static void echo(char **wp);
544static struct op **find1case(struct op *t, char *w);
545static struct op *findcase(struct op *t, char *w);
546static void brkset(struct brkcon *bc);
547static int dolabel(struct op *t);
548static int dohelp(struct op *t);
549static int dochdir(struct op *t);
550static int doshift(struct op *t);
551static int dologin(struct op *t);
552static int doumask(struct op *t);
553static int doexec(struct op *t);
554static int dodot(struct op *t);
555static int dowait(struct op *t);
556static int doread(struct op *t);
557static int doeval(struct op *t);
558static int dotrap(struct op *t);
559static int getsig(char *s);
560static void setsig(int n, sighandler_t f);
561static int getn(char *as);
562static int dobreak(struct op *t);
563static int docontinue(struct op *t);
564static int brkcontin(char *cp, int val);
565static int doexit(struct op *t);
566static int doexport(struct op *t);
567static int doreadonly(struct op *t);
568static void rdexp(char **wp, void (*f) (struct var *), int key);
569static void badid(char *s);
570static int doset(struct op *t);
571static void varput(char *s, int out);
572static int dotimes(struct op *t);
573static int expand(char *cp, struct wdblock **wbp, int f);
574static char *blank(int f);
575static int dollar(int quoted);
576static int grave(int quoted);
577static void globname(char *we, char *pp);
578static char *generate(char *start1, char *end1, char *middle, char *end);
579static int anyspcl(struct wdblock *wb);
580static int xstrcmp(char *p1, char *p2);
581static void glob0(char *a0, unsigned int a1, int a2,
582 int (*a3) (char *, char *));
583static void glob1(char *base, char *lim);
584static void glob2(char *i, char *j);
585static void glob3(char *i, char *j, char *k);
586static void readhere(char **name, char *s, int ec);
587static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
588static int xxchar(struct ioarg *ap);
589
590struct here {
591 char *h_tag;
592 int h_dosub;
593 struct ioword *h_iop;
594 struct here *h_next;
595};
596
597static const char * const signame[] = {
598 "Signal 0",
599 "Hangup",
600 (char *) NULL, /* interrupt */
601 "Quit",
602 "Illegal instruction",
603 "Trace/BPT trap",
604 "Abort",
605 "Bus error",
606 "Floating Point Exception",
607 "Killed",
608 "SIGUSR1",
609 "SIGSEGV",
610 "SIGUSR2",
611 (char *) NULL, /* broken pipe */
612 "Alarm clock",
613 "Terminated",
614};
615
616#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
617
618struct res {
619 const char *r_name;
620 int r_val;
621};
622static const struct res restab[] = {
623 {"for", FOR},
624 {"case", CASE},
625 {"esac", ESAC},
626 {"while", WHILE},
627 {"do", DO},
628 {"done", DONE},
629 {"if", IF},
630 {"in", IN},
631 {"then", THEN},
632 {"else", ELSE},
633 {"elif", ELIF},
634 {"until", UNTIL},
635 {"fi", FI},
636 {";;", BREAK},
637 {"||", LOGOR},
638 {"&&", LOGAND},
639 {"{", '{'},
640 {"}", '}'},
641 {".", DOT},
642 {0, 0},
643};
644
645
646struct builtincmd {
647 const char *name;
648 int (*builtinfunc) (struct op * t);
649};
650static const struct builtincmd builtincmds[] = {
651 {".", dodot},
652 {":", dolabel},
653 {"break", dobreak},
654 {"cd", dochdir},
655 {"continue", docontinue},
656 {"eval", doeval},
657 {"exec", doexec},
658 {"exit", doexit},
659 {"export", doexport},
660 {"help", dohelp},
661 {"login", dologin},
662 {"newgrp", dologin},
663 {"read", doread},
664 {"readonly", doreadonly},
665 {"set", doset},
666 {"shift", doshift},
667 {"times", dotimes},
668 {"trap", dotrap},
669 {"umask", doumask},
670 {"wait", dowait},
671 {0, 0}
672};
673
674static struct op *scantree(struct op *);
675static struct op *dowholefile(int, int);
676
677/* Globals */
678extern char **environ; /* environment pointer */
679
680static char **dolv;
681static int dolc;
682static int exstat;
683static char gflg;
684static int interactive; /* Is this an interactive shell */
685static int execflg;
686static int multiline; /* \n changed to ; */
687static struct op *outtree; /* result from parser */
688static xint *failpt;
689static xint *errpt;
690static struct brkcon *brklist;
691static int isbreak;
692static struct wdblock *wdlist;
693static struct wdblock *iolist;
694static char *trap[_NSIG + 1];
695static char ourtrap[_NSIG + 1];
696static int trapset; /* trap pending */
697static int yynerrs; /* yacc */
698static char line[LINELIM];
699
700#ifdef MSHDEBUG
701static struct var *mshdbg_var;
702#endif
703static struct var *vlist; /* dictionary */
704static struct var *homedir; /* home directory */
705static struct var *prompt; /* main prompt */
706static struct var *cprompt; /* continuation prompt */
707static struct var *path; /* search path for commands */
708static struct var *shell; /* shell to interpret command files */
709static struct var *ifs; /* field separators */
710
711static int areanum; /* current allocation area */
712static int intr;
713static int inparse;
714static char *null = "";
715static int heedint = 1;
716static void (*qflag) (int) = SIG_IGN;
717static int startl;
718static int peeksym;
719static int nlseen;
720static int iounit = IODEFAULT;
721static YYSTYPE yylval;
722static char *elinep = line + sizeof(line) - 5;
723
724static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
725static struct ioarg ioargstack[NPUSH];
726static struct io iostack[NPUSH];
727static struct iobuf sharedbuf = { AFID_NOBUF };
728static struct iobuf mainbuf = { AFID_NOBUF };
729static unsigned bufid = AFID_ID; /* buffer id counter */
730
731static struct here *inhere; /* list of hear docs while parsing */
732static struct here *acthere; /* list of active here documents */
733static struct region *areabot; /* bottom of area */
734static struct region *areatop; /* top of area */
735static struct region *areanxt; /* starting point of scan */
736static void *brktop;
737static void *brkaddr;
738
739static struct env e = {
740 line, /* linep: char ptr */
741 iostack, /* iobase: struct io ptr */
742 iostack - 1, /* iop: struct io ptr */
743 (xint *) NULL, /* errpt: void ptr for errors? */
744 FDBASE, /* iofd: file desc */
745 (struct env *) NULL /* oenv: struct env ptr */
746};
747
748#ifdef MSHDEBUG
749void print_t(struct op *t);
750void print_t(struct op *t)
751{
752 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
753 T_CMD_NAMES[t->type], t->words, t->ioact));
754
755 if (t->words) {
756 DBGPRINTF(("T: W1: %s", t->words[0]));
757 }
758
759 return;
760}
761
762void print_tree(struct op *head);
763void print_tree(struct op *head)
764{
765 if (head == NULL) {
766 DBGPRINTF(("PRINT_TREE: no tree\n"));
767 return;
768 }
769
770 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
771 head->right));
772
773 if (head->left)
774 print_tree(head->left);
775
776 if (head->right)
777 print_tree(head->right);
778
779 return;
780}
781#endif /* MSHDEBUG */
782
783
784#ifdef CONFIG_FEATURE_COMMAND_EDITING
785static char *current_prompt;
786#endif
787
788/* -------- sh.c -------- */
789/*
790 * shell
791 */
792
793
794int msh_main(int argc, char **argv)
795{
796 int f;
797 char *s;
798 int cflag;
799 char *name, **ap;
800 int (*iof) (struct ioarg *);
801
802 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
803
804 initarea();
805 if ((ap = environ) != NULL) {
806 while (*ap)
807 assign(*ap++, !COPYV);
808 for (ap = environ; *ap;)
809 export(lookup(*ap++));
810 }
811 closeall();
812 areanum = 1;
813
814 shell = lookup("SHELL");
815 if (shell->value == null)
816 setval(shell, (char *)DEFAULT_SHELL);
817 export(shell);
818
819 homedir = lookup("HOME");
820 if (homedir->value == null)
821 setval(homedir, "/");
822 export(homedir);
823
824 setval(lookup("$"), putn(getpid()));
825
826 path = lookup("PATH");
827 if (path->value == null) {
828 if (geteuid() == 0)
829 setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
830 else
831 setval(path, "/bin:/usr/bin");
832 }
833 export(path);
834
835 ifs = lookup("IFS");
836 if (ifs->value == null)
837 setval(ifs, " \t\n");
838
839#ifdef MSHDEBUG
840 mshdbg_var = lookup("MSHDEBUG");
841 if (mshdbg_var->value == null)
842 setval(mshdbg_var, "0");
843#endif
844
845 prompt = lookup("PS1");
846#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
847 if (prompt->value == null)
848#endif
849 setval(prompt, DEFAULT_USER_PROMPT);
850 if (geteuid() == 0) {
851 setval(prompt, DEFAULT_ROOT_PROMPT);
852 prompt->status &= ~EXPORT;
853 }
854 cprompt = lookup("PS2");
855#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
856 if (cprompt->value == null)
857#endif
858 setval(cprompt, "> ");
859
860 iof = filechar;
861 cflag = 0;
862 name = *argv++;
863 if (--argc >= 1) {
864 if (argv[0][0] == '-' && argv[0][1] != '\0') {
865 for (s = argv[0] + 1; *s; s++)
866 switch (*s) {
867 case 'c':
868 prompt->status &= ~EXPORT;
869 cprompt->status &= ~EXPORT;
870 setval(prompt, "");
871 setval(cprompt, "");
872 cflag = 1;
873 if (--argc > 0)
874 PUSHIO(aword, *++argv, iof = nlchar);
875 break;
876
877 case 'q':
878 qflag = SIG_DFL;
879 break;
880
881 case 's':
882 /* standard input */
883 break;
884
885 case 't':
886 prompt->status &= ~EXPORT;
887 setval(prompt, "");
888 iof = linechar;
889 break;
890
891 case 'i':
892 interactive++;
893 default:
894 if (*s >= 'a' && *s <= 'z')
895 flag[(int) *s]++;
896 }
897 } else {
898 argv--;
899 argc++;
900 }
901
902 if (iof == filechar && --argc > 0) {
903 setval(prompt, "");
904 setval(cprompt, "");
905 prompt->status &= ~EXPORT;
906 cprompt->status &= ~EXPORT;
907
908/* Shell is non-interactive, activate printf-based debug */
909#ifdef MSHDEBUG
910 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
911 if (mshdbg < 0)
912 mshdbg = 0;
913#endif
914 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
915
916 if (newfile(name = *++argv))
917 exit(1); /* Exit on error */
918 }
919 }
920
921 setdash();
922
923 /* This won't be true if PUSHIO has been called, say from newfile() above */
924 if (e.iop < iostack) {
925 PUSHIO(afile, 0, iof);
926 if (isatty(0) && isatty(1) && !cflag) {
927 interactive++;
928#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
929#ifdef MSHDEBUG
930 printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER);
931#else
932 printf("\n\n%s Built-in shell (msh)\n", BB_BANNER);
933#endif
934 printf("Enter 'help' for a list of built-in commands.\n\n");
935#endif
936 }
937 }
938
939 signal(SIGQUIT, qflag);
940 if (name && name[0] == '-') {
941 interactive++;
942 if ((f = open(".profile", 0)) >= 0)
943 next(remap(f));
944 if ((f = open("/etc/profile", 0)) >= 0)
945 next(remap(f));
946 }
947 if (interactive)
948 signal(SIGTERM, sig);
949
950 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
951 signal(SIGINT, onintr);
952 dolv = argv;
953 dolc = argc;
954 dolv[0] = name;
955 if (dolc > 1) {
956 for (ap = ++argv; --argc > 0;) {
957 if (assign(*ap = *argv++, !COPYV)) {
958 dolc--; /* keyword */
959 } else {
960 ap++;
961 }
962 }
963 }
964 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
965
966 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
967
968 for (;;) {
969 if (interactive && e.iop <= iostack) {
970#ifdef CONFIG_FEATURE_COMMAND_EDITING
971 current_prompt = prompt->value;
972#else
973 prs(prompt->value);
974#endif
975 }
976 onecommand();
977 /* Ensure that getenv("PATH") stays current */
978 setenv("PATH", path->value, 1);
979 }
980
981 DBGPRINTF(("MSH_MAIN: returning.\n"));
982}
983
984static void setdash(void)
985{
986 char *cp;
987 int c;
988 char m['z' - 'a' + 1];
989
990 cp = m;
991 for (c = 'a'; c <= 'z'; c++)
992 if (flag[(int) c])
993 *cp++ = c;
994 *cp = 0;
995 setval(lookup("-"), m);
996}
997
998static int newfile(char *s)
999{
1000 int f;
1001
1002 DBGPRINTF7(("NEWFILE: opening %s\n", s));
1003
1004 if (strcmp(s, "-") != 0) {
1005 DBGPRINTF(("NEWFILE: s is %s\n", s));
1006 f = open(s, 0);
1007 if (f < 0) {
1008 prs(s);
1009 err(": cannot open");
1010 return 1;
1011 }
1012 } else
1013 f = 0;
1014
1015 next(remap(f));
1016 return 0;
1017}
1018
1019
1020struct op *scantree(struct op *head)
1021{
1022 struct op *dotnode;
1023
1024 if (head == NULL)
1025 return NULL;
1026
1027 if (head->left != NULL) {
1028 dotnode = scantree(head->left);
1029 if (dotnode)
1030 return dotnode;
1031 }
1032
1033 if (head->right != NULL) {
1034 dotnode = scantree(head->right);
1035 if (dotnode)
1036 return dotnode;
1037 }
1038
1039 if (head->words == NULL)
1040 return NULL;
1041
1042 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
1043
1044 if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) {
1045 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
1046 return head;
1047 }
1048
1049 return NULL;
1050}
1051
1052
1053static void onecommand(void)
1054{
1055 int i;
1056 jmp_buf m1;
1057
1058 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
1059
1060 while (e.oenv)
1061 quitenv();
1062
1063 areanum = 1;
1064 freehere(areanum);
1065 freearea(areanum);
1066 garbage();
1067 wdlist = 0;
1068 iolist = 0;
1069 e.errpt = 0;
1070 e.linep = line;
1071 yynerrs = 0;
1072 multiline = 0;
1073 inparse = 1;
1074 intr = 0;
1075 execflg = 0;
1076
1077 setjmp(failpt = m1); /* Bruce Evans' fix */
1078 if (setjmp(failpt = m1) || yyparse() || intr) {
1079
1080 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1081
1082 while (e.oenv)
1083 quitenv();
1084 scraphere();
1085 if (!interactive && intr)
1086 leave();
1087 inparse = 0;
1088 intr = 0;
1089 return;
1090 }
1091
1092 inparse = 0;
1093 brklist = 0;
1094 intr = 0;
1095 execflg = 0;
1096
1097 if (!flag['n']) {
1098 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
1099 outtree));
1100 execute(outtree, NOPIPE, NOPIPE, 0);
1101 }
1102
1103 if (!interactive && intr) {
1104 execflg = 0;
1105 leave();
1106 }
1107
1108 if ((i = trapset) != 0) {
1109 trapset = 0;
1110 runtrap(i);
1111 }
1112}
1113
1114static void fail(void)
1115{
1116 longjmp(failpt, 1);
1117 /* NOTREACHED */
1118}
1119
1120static void leave(void)
1121{
1122 DBGPRINTF(("LEAVE: leave called!\n"));
1123
1124 if (execflg)
1125 fail();
1126 scraphere();
1127 freehere(1);
1128 runtrap(0);
1129 _exit(exstat);
1130 /* NOTREACHED */
1131}
1132
1133static void warn(char *s)
1134{
1135 if (*s) {
1136 prs(s);
1137 exstat = -1;
1138 }
1139 prs("\n");
1140 if (flag['e'])
1141 leave();
1142}
1143
1144static void err(char *s)
1145{
1146 warn(s);
1147 if (flag['n'])
1148 return;
1149 if (!interactive)
1150 leave();
1151 if (e.errpt)
1152 longjmp(e.errpt, 1);
1153 closeall();
1154 e.iop = e.iobase = iostack;
1155}
1156
1157static int newenv(int f)
1158{
1159 struct env *ep;
1160
1161 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
1162
1163 if (f) {
1164 quitenv();
1165 return 1;
1166 }
1167
1168 ep = (struct env *) space(sizeof(*ep));
1169 if (ep == NULL) {
1170 while (e.oenv)
1171 quitenv();
1172 fail();
1173 }
1174 *ep = e;
1175 e.oenv = ep;
1176 e.errpt = errpt;
1177
1178 return 0;
1179}
1180
1181static void quitenv(void)
1182{
1183 struct env *ep;
1184 int fd;
1185
1186 DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv));
1187
1188 if ((ep = e.oenv) != NULL) {
1189 fd = e.iofd;
1190 e = *ep;
1191 /* should close `'d files */
1192 DELETE(ep);
1193 while (--fd >= e.iofd)
1194 close(fd);
1195 }
1196}
1197
1198/*
1199 * Is any character from s1 in s2?
1200 */
1201static int anys(char *s1, char *s2)
1202{
1203 while (*s1)
1204 if (any(*s1++, s2))
1205 return 1;
1206 return 0;
1207}
1208
1209/*
1210 * Is character c in s?
1211 */
1212static int any(int c, char *s)
1213{
1214 while (*s)
1215 if (*s++ == c)
1216 return 1;
1217 return 0;
1218}
1219
1220static char *putn(int n)
1221{
1222 return itoa(n);
1223}
1224
1225static void next(int f)
1226{
1227 PUSHIO(afile, f, filechar);
1228}
1229
1230static void onintr(int s) /* ANSI C requires a parameter */
1231{
1232 signal(SIGINT, onintr);
1233 intr = 1;
1234 if (interactive) {
1235 if (inparse) {
1236 prs("\n");
1237 fail();
1238 }
1239 } else if (heedint) {
1240 execflg = 0;
1241 leave();
1242 }
1243}
1244
1245static char *space(int n)
1246{
1247 char *cp;
1248
1249 if ((cp = getcell(n)) == 0)
1250 err("out of string space");
1251 return cp;
1252}
1253
1254static char *strsave(char *s, int a)
1255{
1256 char *cp, *xp;
1257
1258 if ((cp = space(strlen(s) + 1)) != NULL) {
1259 setarea((char *) cp, a);
1260 for (xp = cp; (*xp++ = *s++) != '\0';);
1261 return cp;
1262 }
1263 return "";
1264}
1265
1266/*
1267 * trap handling
1268 */
1269static void sig(int i)
1270{
1271 trapset = i;
1272 signal(i, sig);
1273}
1274
1275static void runtrap(int i)
1276{
1277 char *trapstr;
1278
1279 if ((trapstr = trap[i]) == NULL)
1280 return;
1281
1282 if (i == 0)
1283 trap[i] = 0;
1284
1285 RUN(aword, trapstr, nlchar);
1286}
1287
1288/* -------- var.c -------- */
1289
1290/*
1291 * Find the given name in the dictionary
1292 * and return its value. If the name was
1293 * not previously there, enter it now and
1294 * return a null value.
1295 */
1296static struct var *lookup(char *n)
1297{
1298 struct var *vp;
1299 char *cp;
1300 int c;
1301 static struct var dummy;
1302
1303 if (isdigit(*n)) {
1304 dummy.name = n;
1305 for (c = 0; isdigit(*n) && c < 1000; n++)
1306 c = c * 10 + *n - '0';
1307 dummy.status = RONLY;
1308 dummy.value = c <= dolc ? dolv[c] : null;
1309 return &dummy;
1310 }
1311 for (vp = vlist; vp; vp = vp->next)
1312 if (eqname(vp->name, n))
1313 return vp;
1314 cp = findeq(n);
1315 vp = (struct var *) space(sizeof(*vp));
1316 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
1317 dummy.name = dummy.value = "";
1318 return &dummy;
1319 }
1320 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++);
1321 if (*cp == 0)
1322 *cp = '=';
1323 *++cp = 0;
1324 setarea((char *) vp, 0);
1325 setarea((char *) vp->name, 0);
1326 vp->value = null;
1327 vp->next = vlist;
1328 vp->status = GETCELL;
1329 vlist = vp;
1330 return vp;
1331}
1332
1333/*
1334 * give variable at `vp' the value `val'.
1335 */
1336static void setval(struct var *vp, char *val)
1337{
1338 nameval(vp, val, (char *) NULL);
1339}
1340
1341/*
1342 * if name is not NULL, it must be
1343 * a prefix of the space `val',
1344 * and end with `='.
1345 * this is all so that exporting
1346 * values is reasonably painless.
1347 */
1348static void nameval(struct var *vp, char *val, char *name)
1349{
1350 char *cp, *xp;
1351 char *nv;
1352 int fl;
1353
1354 if (vp->status & RONLY) {
1355 for (xp = vp->name; *xp && *xp != '=';)
1356 putc(*xp++, stderr);
1357 err(" is read-only");
1358 return;
1359 }
1360 fl = 0;
1361 if (name == NULL) {
1362 xp = space(strlen(vp->name) + strlen(val) + 2);
1363 if (xp == 0)
1364 return;
1365 /* make string: name=value */
1366 setarea((char *) xp, 0);
1367 name = xp;
1368 for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++);
1369 if (*xp++ == 0)
1370 xp[-1] = '=';
1371 nv = xp;
1372 for (cp = val; (*xp++ = *cp++) != '\0';);
1373 val = nv;
1374 fl = GETCELL;
1375 }
1376 if (vp->status & GETCELL)
1377 freecell(vp->name); /* form new string `name=value' */
1378 vp->name = name;
1379 vp->value = val;
1380 vp->status |= fl;
1381}
1382
1383static void export(struct var *vp)
1384{
1385 vp->status |= EXPORT;
1386}
1387
1388static void ronly(struct var *vp)
1389{
1390 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1391 vp->status |= RONLY;
1392}
1393
1394static int isassign(char *s)
1395{
1396 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1397
1398 if (!isalpha((int) *s) && *s != '_')
1399 return 0;
1400 for (; *s != '='; s++)
1401 if (*s == 0 || (!isalnum(*s) && *s != '_'))
1402 return 0;
1403
1404 return 1;
1405}
1406
1407static int assign(char *s, int cf)
1408{
1409 char *cp;
1410 struct var *vp;
1411
1412 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1413
1414 if (!isalpha(*s) && *s != '_')
1415 return 0;
1416 for (cp = s; *cp != '='; cp++)
1417 if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
1418 return 0;
1419 vp = lookup(s);
1420 nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s);
1421 if (cf != COPYV)
1422 vp->status &= ~GETCELL;
1423 return 1;
1424}
1425
1426static int checkname(char *cp)
1427{
1428 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1429
1430 if (!isalpha(*cp++) && *(cp - 1) != '_')
1431 return 0;
1432 while (*cp)
1433 if (!isalnum(*cp++) && *(cp - 1) != '_')
1434 return 0;
1435 return 1;
1436}
1437
1438static void putvlist(int f, int out)
1439{
1440 struct var *vp;
1441
1442 for (vp = vlist; vp; vp = vp->next)
1443 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1444 if (vp->status & EXPORT)
1445 write(out, "export ", 7);
1446 if (vp->status & RONLY)
1447 write(out, "readonly ", 9);
1448 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1449 write(out, "\n", 1);
1450 }
1451}
1452
1453static int eqname(char *n1, char *n2)
1454{
1455 for (; *n1 != '=' && *n1 != 0; n1++)
1456 if (*n2++ != *n1)
1457 return 0;
1458 return *n2 == 0 || *n2 == '=';
1459}
1460
1461static char *findeq(char *cp)
1462{
1463 while (*cp != '\0' && *cp != '=')
1464 cp++;
1465 return cp;
1466}
1467
1468/* -------- gmatch.c -------- */
1469/*
1470 * int gmatch(string, pattern)
1471 * char *string, *pattern;
1472 *
1473 * Match a pattern as in sh(1).
1474 */
1475
1476#define CMASK 0377
1477#define QUOTE 0200
1478#define QMASK (CMASK&~QUOTE)
1479#define NOT '!' /* might use ^ */
1480
1481static int gmatch(char *s, char *p)
1482{
1483 int sc, pc;
1484
1485 if (s == NULL || p == NULL)
1486 return 0;
1487 while ((pc = *p++ & CMASK) != '\0') {
1488 sc = *s++ & QMASK;
1489 switch (pc) {
1490 case '[':
1491 if ((p = cclass(p, sc)) == NULL)
1492 return 0;
1493 break;
1494
1495 case '?':
1496 if (sc == 0)
1497 return 0;
1498 break;
1499
1500 case '*':
1501 s--;
1502 do {
1503 if (*p == '\0' || gmatch(s, p))
1504 return 1;
1505 } while (*s++ != '\0');
1506 return 0;
1507
1508 default:
1509 if (sc != (pc & ~QUOTE))
1510 return 0;
1511 }
1512 }
1513 return *s == 0;
1514}
1515
1516static char *cclass(char *p, int sub)
1517{
1518 int c, d, not, found;
1519
1520 if ((not = *p == NOT) != 0)
1521 p++;
1522 found = not;
1523 do {
1524 if (*p == '\0')
1525 return NULL;
1526 c = *p & CMASK;
1527 if (p[1] == '-' && p[2] != ']') {
1528 d = p[2] & CMASK;
1529 p++;
1530 } else
1531 d = c;
1532 if (c == sub || (c <= sub && sub <= d))
1533 found = !not;
1534 } while (*++p != ']');
1535 return found ? p + 1 : NULL;
1536}
1537
1538
1539/* -------- area.c -------- */
1540
1541/*
1542 * All memory between (char *)areabot and (char *)(areatop+1) is
1543 * exclusively administered by the area management routines.
1544 * It is assumed that sbrk() and brk() manipulate the high end.
1545 */
1546
1547#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
1548
1549static void initarea(void)
1550{
1551 brkaddr = xmalloc(AREASIZE);
1552 brktop = brkaddr + AREASIZE;
1553
1554 while ((long) sbrk(0) & ALIGN)
1555 sbrk(1);
1556 areabot = (struct region *) sbrk(REGSIZE);
1557
1558 areabot->next = areabot;
1559 areabot->area = BUSY;
1560 areatop = areabot;
1561 areanxt = areabot;
1562}
1563
1564char *getcell(unsigned nbytes)
1565{
1566 int nregio;
1567 struct region *p, *q;
1568 int i;
1569
1570 if (nbytes == 0) {
1571 puts("getcell(0)");
1572 abort();
1573 }
1574 /* silly and defeats the algorithm */
1575 /*
1576 * round upwards and add administration area
1577 */
1578 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
1579 for (p = areanxt;;) {
1580 if (p->area > areanum) {
1581 /*
1582 * merge free cells
1583 */
1584 while ((q = p->next)->area > areanum && q != areanxt)
1585 p->next = q->next;
1586 /*
1587 * exit loop if cell big enough
1588 */
1589 if (q >= p + nregio)
1590 goto found;
1591 }
1592 p = p->next;
1593 if (p == areanxt)
1594 break;
1595 }
1596 i = nregio >= GROWBY ? nregio : GROWBY;
1597 p = (struct region *) sbrk(i * REGSIZE);
1598 if (p == (struct region *) -1)
1599 return NULL;
1600 p--;
1601 if (p != areatop) {
1602 puts("not contig");
1603 abort(); /* allocated areas are contiguous */
1604 }
1605 q = p + i;
1606 p->next = q;
1607 p->area = FREE;
1608 q->next = areabot;
1609 q->area = BUSY;
1610 areatop = q;
1611 found:
1612 /*
1613 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
1614 */
1615 areanxt = p + nregio;
1616 if (areanxt < q) {
1617 /*
1618 * split into requested area and rest
1619 */
1620 if (areanxt + 1 > q) {
1621 puts("OOM");
1622 abort(); /* insufficient space left for admin */
1623 }
1624 areanxt->next = q;
1625 areanxt->area = FREE;
1626 p->next = areanxt;
1627 }
1628 p->area = areanum;
1629 return (char *) (p + 1);
1630}
1631
1632static void freecell(char *cp)
1633{
1634 struct region *p;
1635
1636 if ((p = (struct region *) cp) != NULL) {
1637 p--;
1638 if (p < areanxt)
1639 areanxt = p;
1640 p->area = FREE;
1641 }
1642}
1643
1644static void freearea(int a)
1645{
1646 struct region *p, *top;
1647
1648 top = areatop;
1649 for (p = areabot; p != top; p = p->next)
1650 if (p->area >= a)
1651 p->area = FREE;
1652}
1653
1654static void setarea(char *cp, int a)
1655{
1656 struct region *p;
1657
1658 if ((p = (struct region *) cp) != NULL)
1659 (p - 1)->area = a;
1660}
1661
1662int getarea(char *cp)
1663{
1664 return ((struct region *) cp - 1)->area;
1665}
1666
1667static void garbage(void)
1668{
1669 struct region *p, *q, *top;
1670
1671 top = areatop;
1672 for (p = areabot; p != top; p = p->next) {
1673 if (p->area > areanum) {
1674 while ((q = p->next)->area > areanum)
1675 p->next = q->next;
1676 areanxt = p;
1677 }
1678 }
1679#ifdef SHRINKBY
1680 if (areatop >= q + SHRINKBY && q->area > areanum) {
1681 brk((char *) (q + 1));
1682 q->next = areabot;
1683 q->area = BUSY;
1684 areatop = q;
1685 }
1686#endif
1687}
1688
1689/* -------- csyn.c -------- */
1690/*
1691 * shell: syntax (C version)
1692 */
1693
1694int yyparse(void)
1695{
1696 DBGPRINTF7(("YYPARSE: enter...\n"));
1697
1698 startl = 1;
1699 peeksym = 0;
1700 yynerrs = 0;
1701 outtree = c_list();
1702 musthave('\n', 0);
1703 return (yynerrs != 0);
1704}
1705
1706static struct op *pipeline(int cf)
1707{
1708 struct op *t, *p;
1709 int c;
1710
1711 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
1712
1713 t = command(cf);
1714
1715 DBGPRINTF9(("PIPELINE: t=%p\n", t));
1716
1717 if (t != NULL) {
1718 while ((c = yylex(0)) == '|') {
1719 if ((p = command(CONTIN)) == NULL) {
1720 DBGPRINTF8(("PIPELINE: error!\n"));
1721 SYNTAXERR;
1722 }
1723
1724 if (t->type != TPAREN && t->type != TCOM) {
1725 /* shell statement */
1726 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1727 }
1728
1729 t = block(TPIPE, t, p, NOWORDS);
1730 }
1731 peeksym = c;
1732 }
1733
1734 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
1735 return t;
1736}
1737
1738static struct op *andor(void)
1739{
1740 struct op *t, *p;
1741 int c;
1742
1743 DBGPRINTF7(("ANDOR: enter...\n"));
1744
1745 t = pipeline(0);
1746
1747 DBGPRINTF9(("ANDOR: t=%p\n", t));
1748
1749 if (t != NULL) {
1750 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
1751 if ((p = pipeline(CONTIN)) == NULL) {
1752 DBGPRINTF8(("ANDOR: error!\n"));
1753 SYNTAXERR;
1754 }
1755
1756 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
1757 } /* WHILE */
1758
1759 peeksym = c;
1760 }
1761
1762 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
1763 return t;
1764}
1765
1766static struct op *c_list(void)
1767{
1768 struct op *t, *p;
1769 int c;
1770
1771 DBGPRINTF7(("C_LIST: enter...\n"));
1772
1773 t = andor();
1774
1775 if (t != NULL) {
1776 if ((peeksym = yylex(0)) == '&')
1777 t = block(TASYNC, t, NOBLOCK, NOWORDS);
1778
1779 while ((c = yylex(0)) == ';' || c == '&'
1780 || (multiline && c == '\n')) {
1781
1782 if ((p = andor()) == NULL)
1783 return t;
1784
1785 if ((peeksym = yylex(0)) == '&')
1786 p = block(TASYNC, p, NOBLOCK, NOWORDS);
1787
1788 t = list(t, p);
1789 } /* WHILE */
1790
1791 peeksym = c;
1792 }
1793 /* IF */
1794 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
1795 return t;
1796}
1797
1798static int synio(int cf)
1799{
1800 struct ioword *iop;
1801 int i;
1802 int c;
1803
1804 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
1805
1806 if ((c = yylex(cf)) != '<' && c != '>') {
1807 peeksym = c;
1808 return 0;
1809 }
1810
1811 i = yylval.i;
1812 musthave(WORD, 0);
1813 iop = io(iounit, i, yylval.cp);
1814 iounit = IODEFAULT;
1815
1816 if (i & IOHERE)
1817 markhere(yylval.cp, iop);
1818
1819 DBGPRINTF7(("SYNIO: returning 1\n"));
1820 return 1;
1821}
1822
1823static void musthave(int c, int cf)
1824{
1825 if ((peeksym = yylex(cf)) != c) {
1826 DBGPRINTF7(("MUSTHAVE: error!\n"));
1827 SYNTAXERR;
1828 }
1829
1830 peeksym = 0;
1831}
1832
1833static struct op *simple(void)
1834{
1835 struct op *t;
1836
1837 t = NULL;
1838 for (;;) {
1839 switch (peeksym = yylex(0)) {
1840 case '<':
1841 case '>':
1842 (void) synio(0);
1843 break;
1844
1845 case WORD:
1846 if (t == NULL) {
1847 t = newtp();
1848 t->type = TCOM;
1849 }
1850 peeksym = 0;
1851 word(yylval.cp);
1852 break;
1853
1854 default:
1855 return t;
1856 }
1857 }
1858}
1859
1860static struct op *nested(int type, int mark)
1861{
1862 struct op *t;
1863
1864 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
1865
1866 multiline++;
1867 t = c_list();
1868 musthave(mark, 0);
1869 multiline--;
1870 return block(type, t, NOBLOCK, NOWORDS);
1871}
1872
1873static struct op *command(int cf)
1874{
1875 struct op *t;
1876 struct wdblock *iosave;
1877 int c;
1878
1879 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
1880
1881 iosave = iolist;
1882 iolist = NULL;
1883
1884 if (multiline)
1885 cf |= CONTIN;
1886
1887 while (synio(cf))
1888 cf = 0;
1889
1890 c = yylex(cf);
1891
1892 switch (c) {
1893 default:
1894 peeksym = c;
1895 if ((t = simple()) == NULL) {
1896 if (iolist == NULL)
1897 return NULL;
1898 t = newtp();
1899 t->type = TCOM;
1900 }
1901 break;
1902
1903 case '(':
1904 t = nested(TPAREN, ')');
1905 break;
1906
1907 case '{':
1908 t = nested(TBRACE, '}');
1909 break;
1910
1911 case FOR:
1912 t = newtp();
1913 t->type = TFOR;
1914 musthave(WORD, 0);
1915 startl = 1;
1916 t->str = yylval.cp;
1917 multiline++;
1918 t->words = wordlist();
1919 if ((c = yylex(0)) != '\n' && c != ';')
1920 peeksym = c;
1921 t->left = dogroup(0);
1922 multiline--;
1923 break;
1924
1925 case WHILE:
1926 case UNTIL:
1927 multiline++;
1928 t = newtp();
1929 t->type = c == WHILE ? TWHILE : TUNTIL;
1930 t->left = c_list();
1931 t->right = dogroup(1);
1932 t->words = NULL;
1933 multiline--;
1934 break;
1935
1936 case CASE:
1937 t = newtp();
1938 t->type = TCASE;
1939 musthave(WORD, 0);
1940 t->str = yylval.cp;
1941 startl++;
1942 multiline++;
1943 musthave(IN, CONTIN);
1944 startl++;
1945
1946 t->left = caselist();
1947
1948 musthave(ESAC, 0);
1949 multiline--;
1950 break;
1951
1952 case IF:
1953 multiline++;
1954 t = newtp();
1955 t->type = TIF;
1956 t->left = c_list();
1957 t->right = thenpart();
1958 musthave(FI, 0);
1959 multiline--;
1960 break;
1961
1962 case DOT:
1963 t = newtp();
1964 t->type = TDOT;
1965
1966 musthave(WORD, 0); /* gets name of file */
1967 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1968
1969 word(yylval.cp); /* add word to wdlist */
1970 word(NOWORD); /* terminate wdlist */
1971 t->words = copyw(); /* dup wdlist */
1972 break;
1973
1974 }
1975
1976 while (synio(0));
1977
1978 t = namelist(t);
1979 iolist = iosave;
1980
1981 DBGPRINTF(("COMMAND: returning %p\n", t));
1982
1983 return t;
1984}
1985
1986static struct op *dowholefile(int type, int mark)
1987{
1988 struct op *t;
1989
1990 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1991
1992 multiline++;
1993 t = c_list();
1994 multiline--;
1995 t = block(type, t, NOBLOCK, NOWORDS);
1996 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
1997 return t;
1998}
1999
2000static struct op *dogroup(int onlydone)
2001{
2002 int c;
2003 struct op *mylist;
2004
2005 c = yylex(CONTIN);
2006 if (c == DONE && onlydone)
2007 return NULL;
2008 if (c != DO)
2009 SYNTAXERR;
2010 mylist = c_list();
2011 musthave(DONE, 0);
2012 return mylist;
2013}
2014
2015static struct op *thenpart(void)
2016{
2017 int c;
2018 struct op *t;
2019
2020 if ((c = yylex(0)) != THEN) {
2021 peeksym = c;
2022 return NULL;
2023 }
2024 t = newtp();
2025 t->type = 0;
2026 t->left = c_list();
2027 if (t->left == NULL)
2028 SYNTAXERR;
2029 t->right = elsepart();
2030 return t;
2031}
2032
2033static struct op *elsepart(void)
2034{
2035 int c;
2036 struct op *t;
2037
2038 switch (c = yylex(0)) {
2039 case ELSE:
2040 if ((t = c_list()) == NULL)
2041 SYNTAXERR;
2042 return t;
2043
2044 case ELIF:
2045 t = newtp();
2046 t->type = TELIF;
2047 t->left = c_list();
2048 t->right = thenpart();
2049 return t;
2050
2051 default:
2052 peeksym = c;
2053 return NULL;
2054 }
2055}
2056
2057static struct op *caselist(void)
2058{
2059 struct op *t;
2060
2061 t = NULL;
2062 while ((peeksym = yylex(CONTIN)) != ESAC) {
2063 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
2064 t = list(t, casepart());
2065 }
2066
2067 DBGPRINTF(("CASELIST, returning t=%p\n", t));
2068 return t;
2069}
2070
2071static struct op *casepart(void)
2072{
2073 struct op *t;
2074
2075 DBGPRINTF7(("CASEPART: enter...\n"));
2076
2077 t = newtp();
2078 t->type = TPAT;
2079 t->words = pattern();
2080 musthave(')', 0);
2081 t->left = c_list();
2082 if ((peeksym = yylex(CONTIN)) != ESAC)
2083 musthave(BREAK, CONTIN);
2084
2085 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
2086
2087 return t;
2088}
2089
2090static char **pattern(void)
2091{
2092 int c, cf;
2093
2094 cf = CONTIN;
2095 do {
2096 musthave(WORD, cf);
2097 word(yylval.cp);
2098 cf = 0;
2099 } while ((c = yylex(0)) == '|');
2100 peeksym = c;
2101 word(NOWORD);
2102
2103 return copyw();
2104}
2105
2106static char **wordlist(void)
2107{
2108 int c;
2109
2110 if ((c = yylex(0)) != IN) {
2111 peeksym = c;
2112 return NULL;
2113 }
2114 startl = 0;
2115 while ((c = yylex(0)) == WORD)
2116 word(yylval.cp);
2117 word(NOWORD);
2118 peeksym = c;
2119 return copyw();
2120}
2121
2122/*
2123 * supporting functions
2124 */
2125static struct op *list(struct op *t1, struct op *t2)
2126{
2127 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
2128
2129 if (t1 == NULL)
2130 return t2;
2131 if (t2 == NULL)
2132 return t1;
2133
2134 return block(TLIST, t1, t2, NOWORDS);
2135}
2136
2137static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
2138{
2139 struct op *t;
2140
2141 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
2142
2143 t = newtp();
2144 t->type = type;
2145 t->left = t1;
2146 t->right = t2;
2147 t->words = wp;
2148
2149 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
2150 t2));
2151
2152 return t;
2153}
2154
2155/* See if given string is a shell multiline (FOR, IF, etc) */
2156static int rlookup(char *n)
2157{
2158 const struct res *rp;
2159
2160 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
2161
2162 for (rp = restab; rp->r_name; rp++)
2163 if (strcmp(rp->r_name, n) == 0) {
2164 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2165 return rp->r_val; /* Return numeric code for shell multiline */
2166 }
2167
2168 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2169 return 0; /* Not a shell multiline */
2170}
2171
2172static struct op *newtp(void)
2173{
2174 struct op *t;
2175
2176 t = (struct op *) tree(sizeof(*t));
2177 t->type = 0;
2178 t->words = NULL;
2179 t->ioact = NULL;
2180 t->left = NULL;
2181 t->right = NULL;
2182 t->str = NULL;
2183
2184 DBGPRINTF3(("NEWTP: allocated %p\n", t));
2185
2186 return t;
2187}
2188
2189static struct op *namelist(struct op *t)
2190{
2191
2192 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
2193 T_CMD_NAMES[t->type], iolist));
2194
2195 if (iolist) {
2196 iolist = addword((char *) NULL, iolist);
2197 t->ioact = copyio();
2198 } else
2199 t->ioact = NULL;
2200
2201 if (t->type != TCOM) {
2202 if (t->type != TPAREN && t->ioact != NULL) {
2203 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2204 t->ioact = t->left->ioact;
2205 t->left->ioact = NULL;
2206 }
2207 return t;
2208 }
2209
2210 word(NOWORD);
2211 t->words = copyw();
2212
2213
2214 return t;
2215}
2216
2217static char **copyw(void)
2218{
2219 char **wd;
2220
2221 wd = getwords(wdlist);
2222 wdlist = 0;
2223 return wd;
2224}
2225
2226static void word(char *cp)
2227{
2228 wdlist = addword(cp, wdlist);
2229}
2230
2231static struct ioword **copyio(void)
2232{
2233 struct ioword **iop;
2234
2235 iop = (struct ioword **) getwords(iolist);
2236 iolist = 0;
2237 return iop;
2238}
2239
2240static struct ioword *io(int u, int f, char *cp)
2241{
2242 struct ioword *iop;
2243
2244 iop = (struct ioword *) tree(sizeof(*iop));
2245 iop->io_unit = u;
2246 iop->io_flag = f;
2247 iop->io_name = cp;
2248 iolist = addword((char *) iop, iolist);
2249 return iop;
2250}
2251
2252static void zzerr(void)
2253{
2254 yyerror("syntax error");
2255}
2256
2257static void yyerror(char *s)
2258{
2259 yynerrs++;
2260 if (interactive && e.iop <= iostack) {
2261 multiline = 0;
2262 while (eofc() == 0 && yylex(0) != '\n');
2263 }
2264 err(s);
2265 fail();
2266}
2267
2268static int yylex(int cf)
2269{
2270 int c, c1;
2271 int atstart;
2272
2273 if ((c = peeksym) > 0) {
2274 peeksym = 0;
2275 if (c == '\n')
2276 startl = 1;
2277 return c;
2278 }
2279
2280
2281 nlseen = 0;
2282 atstart = startl;
2283 startl = 0;
2284 yylval.i = 0;
2285 e.linep = line;
2286
2287/* MALAMO */
2288 line[LINELIM - 1] = '\0';
2289
2290 loop:
2291 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2292 ;
2293
2294 switch (c) {
2295 default:
2296 if (any(c, "0123456789")) {
2297 unget(c1 = my_getc(0));
2298 if (c1 == '<' || c1 == '>') {
2299 iounit = c - '0';
2300 goto loop;
2301 }
2302 *e.linep++ = c;
2303 c = c1;
2304 }
2305 break;
2306
2307 case '#': /* Comment, skip to next newline or End-of-string */
2308 while ((c = my_getc(0)) != 0 && c != '\n');
2309 unget(c);
2310 goto loop;
2311
2312 case 0:
2313 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
2314 return c;
2315
2316 case '$':
2317 DBGPRINTF9(("YYLEX: found $\n"));
2318 *e.linep++ = c;
2319 if ((c = my_getc(0)) == '{') {
2320 if ((c = collect(c, '}')) != '\0')
2321 return c;
2322 goto pack;
2323 }
2324 break;
2325
2326 case '`':
2327 case '\'':
2328 case '"':
2329 if ((c = collect(c, c)) != '\0')
2330 return c;
2331 goto pack;
2332
2333 case '|':
2334 case '&':
2335 case ';':
2336 startl = 1;
2337 /* If more chars process them, else return NULL char */
2338 if ((c1 = dual(c)) != '\0')
2339 return c1;
2340 else
2341 return c;
2342
2343 case '^':
2344 startl = 1;
2345 return '|';
2346 case '>':
2347 case '<':
2348 diag(c);
2349 return c;
2350
2351 case '\n':
2352 nlseen++;
2353 gethere();
2354 startl = 1;
2355 if (multiline || cf & CONTIN) {
2356 if (interactive && e.iop <= iostack) {
2357#ifdef CONFIG_FEATURE_COMMAND_EDITING
2358 current_prompt = cprompt->value;
2359#else
2360 prs(cprompt->value);
2361#endif
2362 }
2363 if (cf & CONTIN)
2364 goto loop;
2365 }
2366 return c;
2367
2368 case '(':
2369 case ')':
2370 startl = 1;
2371 return c;
2372 }
2373
2374 unget(c);
2375
2376 pack:
2377 while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) {
2378 if (e.linep >= elinep)
2379 err("word too long");
2380 else
2381 *e.linep++ = c;
2382 };
2383
2384 unget(c);
2385
2386 if (any(c, "\"'`$"))
2387 goto loop;
2388
2389 *e.linep++ = '\0';
2390
2391 if (atstart && (c = rlookup(line)) != 0) {
2392 startl = 1;
2393 return c;
2394 }
2395
2396 yylval.cp = strsave(line, areanum);
2397 return WORD;
2398}
2399
2400
2401static int collect(int c, int c1)
2402{
2403 char s[2];
2404
2405 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2406
2407 *e.linep++ = c;
2408 while ((c = my_getc(c1)) != c1) {
2409 if (c == 0) {
2410 unget(c);
2411 s[0] = c1;
2412 s[1] = 0;
2413 prs("no closing ");
2414 yyerror(s);
2415 return YYERRCODE;
2416 }
2417 if (interactive && c == '\n' && e.iop <= iostack) {
2418#ifdef CONFIG_FEATURE_COMMAND_EDITING
2419 current_prompt = cprompt->value;
2420#else
2421 prs(cprompt->value);
2422#endif
2423 }
2424 *e.linep++ = c;
2425 }
2426
2427 *e.linep++ = c;
2428
2429 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2430
2431 return 0;
2432}
2433
2434/* "multiline commands" helper func */
2435/* see if next 2 chars form a shell multiline */
2436static int dual(int c)
2437{
2438 char s[3];
2439 char *cp = s;
2440
2441 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2442
2443 *cp++ = c; /* c is the given "peek" char */
2444 *cp++ = my_getc(0); /* get next char of input */
2445 *cp = 0; /* add EOS marker */
2446
2447 c = rlookup(s); /* see if 2 chars form a shell multiline */
2448 if (c == 0)
2449 unget(*--cp); /* String is not a shell multiline, put peek char back */
2450
2451 return c; /* String is multiline, return numeric multiline (restab) code */
2452}
2453
2454static void diag(int ec)
2455{
2456 int c;
2457
2458 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
2459
2460 c = my_getc(0);
2461 if (c == '>' || c == '<') {
2462 if (c != ec)
2463 zzerr();
2464 yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE;
2465 c = my_getc(0);
2466 } else
2467 yylval.i = ec == '>' ? IOWRITE : IOREAD;
2468 if (c != '&' || yylval.i == IOHERE)
2469 unget(c);
2470 else
2471 yylval.i |= IODUP;
2472}
2473
2474static char *tree(unsigned size)
2475{
2476 char *t;
2477
2478 if ((t = getcell(size)) == NULL) {
2479 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
2480 prs("command line too complicated\n");
2481 fail();
2482 /* NOTREACHED */
2483 }
2484 return t;
2485}
2486
2487/* VARARGS1 */
2488/* ARGSUSED */
2489
2490/* -------- exec.c -------- */
2491
2492/*
2493 * execute tree
2494 */
2495
2496
2497static int execute(struct op *t, int *pin, int *pout, int act)
2498{
2499 struct op *t1;
2500 volatile int i, rv, a;
2501 char *cp, **wp, **wp2;
2502 struct var *vp;
2503 struct op *outtree_save;
2504 struct brkcon bc;
2505
2506#if __GNUC__
2507 /* Avoid longjmp clobbering */
2508 (void) &wp;
2509#endif
2510
2511 if (t == NULL) {
2512 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
2513 return 0;
2514 }
2515
2516 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
2517 t->type, T_CMD_NAMES[t->type],
2518 ((t->words == NULL) ? "NULL" : t->words[0])));
2519
2520 rv = 0;
2521 a = areanum++;
2522 wp = (wp2 = t->words) != NULL
2523 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2524 : NULL;
2525
2526 switch (t->type) {
2527 case TDOT:
2528 DBGPRINTF3(("EXECUTE: TDOT\n"));
2529
2530 outtree_save = outtree;
2531
2532 newfile(evalstr(t->words[0], DOALL));
2533
2534 t->left = dowholefile(TLIST, 0);
2535 t->right = NULL;
2536
2537 outtree = outtree_save;
2538
2539 if (t->left)
2540 rv = execute(t->left, pin, pout, 0);
2541 if (t->right)
2542 rv = execute(t->right, pin, pout, 0);
2543 break;
2544
2545 case TPAREN:
2546 rv = execute(t->left, pin, pout, 0);
2547 break;
2548
2549 case TCOM:
2550 {
2551 rv = forkexec(t, pin, pout, act, wp);
2552 }
2553 break;
2554
2555 case TPIPE:
2556 {
2557 int pv[2];
2558
2559 if ((rv = openpipe(pv)) < 0)
2560 break;
2561 pv[0] = remap(pv[0]);
2562 pv[1] = remap(pv[1]);
2563 (void) execute(t->left, pin, pv, 0);
2564 rv = execute(t->right, pv, pout, 0);
2565 }
2566 break;
2567
2568 case TLIST:
2569 (void) execute(t->left, pin, pout, 0);
2570 rv = execute(t->right, pin, pout, 0);
2571 break;
2572
2573 case TASYNC:
2574 {
2575 int hinteractive = interactive;
2576
2577 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2578
2579 i = vfork();
2580 if (i != 0) {
2581 interactive = hinteractive;
2582 if (i != -1) {
2583 setval(lookup("!"), putn(i));
2584 if (pin != NULL)
2585 closepipe(pin);
2586 if (interactive) {
2587 prs(putn(i));
2588 prs("\n");
2589 }
2590 } else
2591 rv = -1;
2592 setstatus(rv);
2593 } else {
2594 signal(SIGINT, SIG_IGN);
2595 signal(SIGQUIT, SIG_IGN);
2596 if (interactive)
2597 signal(SIGTERM, SIG_DFL);
2598 interactive = 0;
2599 if (pin == NULL) {
2600 close(0);
2601 open(bb_dev_null, 0);
2602 }
2603 _exit(execute(t->left, pin, pout, FEXEC));
2604 }
2605 }
2606 break;
2607
2608 case TOR:
2609 case TAND:
2610 rv = execute(t->left, pin, pout, 0);
2611 if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND))
2612 rv = execute(t1, pin, pout, 0);
2613 break;
2614
2615 case TFOR:
2616 if (wp == NULL) {
2617 wp = dolv + 1;
2618 if ((i = dolc) < 0)
2619 i = 0;
2620 } else {
2621 i = -1;
2622 while (*wp++ != NULL);
2623 }
2624 vp = lookup(t->str);
2625 while (setjmp(bc.brkpt))
2626 if (isbreak)
2627 goto broken;
2628 brkset(&bc);
2629 for (t1 = t->left; i-- && *wp != NULL;) {
2630 setval(vp, *wp++);
2631 rv = execute(t1, pin, pout, 0);
2632 }
2633 brklist = brklist->nextlev;
2634 break;
2635
2636 case TWHILE:
2637 case TUNTIL:
2638 while (setjmp(bc.brkpt))
2639 if (isbreak)
2640 goto broken;
2641 brkset(&bc);
2642 t1 = t->left;
2643 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2644 rv = execute(t->right, pin, pout, 0);
2645 brklist = brklist->nextlev;
2646 break;
2647
2648 case TIF:
2649 case TELIF:
2650 if (t->right != NULL) {
2651 rv = !execute(t->left, pin, pout, 0) ?
2652 execute(t->right->left, pin, pout, 0) :
2653 execute(t->right->right, pin, pout, 0);
2654 }
2655 break;
2656
2657 case TCASE:
2658 if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0)
2659 cp = "";
2660
2661 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2662 ((t->str == NULL) ? "NULL" : t->str),
2663 ((cp == NULL) ? "NULL" : cp)));
2664
2665 if ((t1 = findcase(t->left, cp)) != NULL) {
2666 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
2667 rv = execute(t1, pin, pout, 0);
2668 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
2669 }
2670 break;
2671
2672 case TBRACE:
2673/*
2674 if (iopp = t->ioact)
2675 while (*iopp)
2676 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2677 rv = -1;
2678 break;
2679 }
2680*/
2681 if (rv >= 0 && (t1 = t->left))
2682 rv = execute(t1, pin, pout, 0);
2683 break;
2684
2685 };
2686
2687 broken:
2688 t->words = wp2;
2689 isbreak = 0;
2690 freehere(areanum);
2691 freearea(areanum);
2692 areanum = a;
2693 if (interactive && intr) {
2694 closeall();
2695 fail();
2696 }
2697
2698 if ((i = trapset) != 0) {
2699 trapset = 0;
2700 runtrap(i);
2701 }
2702
2703 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
2704 return rv;
2705}
2706
2707static int
2708forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
2709{
2710 pid_t newpid;
2711 int i, rv;
2712 int (*shcom) (struct op *) = NULL;
2713 int f;
2714 char *cp = NULL;
2715 struct ioword **iopp;
2716 int resetsig;
2717 char **owp;
2718 int forked = 0;
2719
2720 int *hpin = pin;
2721 int *hpout = pout;
2722 char *hwp;
2723 int hinteractive;
2724 int hintr;
2725 struct brkcon *hbrklist;
2726 int hexecflg;
2727
2728#if __GNUC__
2729 /* Avoid longjmp clobbering */
2730 (void) &pin;
2731 (void) &pout;
2732 (void) &wp;
2733 (void) &shcom;
2734 (void) &cp;
2735 (void) &resetsig;
2736 (void) &owp;
2737#endif
2738
2739 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
2740 pout, act));
2741 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2742 ((t->words == NULL) ? "NULL" : t->words[0])));
2743
2744 owp = wp;
2745 resetsig = 0;
2746 rv = -1; /* system-detected error */
2747 if (t->type == TCOM) {
2748 while ((cp = *wp++) != NULL);
2749 cp = *wp;
2750
2751 /* strip all initial assignments */
2752 /* not correct wrt PATH=yyy command etc */
2753 if (flag['x']) {
2754 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
2755 cp, wp, owp));
2756 echo(cp ? wp : owp);
2757 }
2758
2759 if (cp == NULL && t->ioact == NULL) {
2760 while ((cp = *owp++) != NULL && assign(cp, COPYV));
2761 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
2762 return setstatus(0);
2763 } else if (cp != NULL) {
2764 shcom = inbuilt(cp);
2765 }
2766 }
2767
2768 t->words = wp;
2769 f = act;
2770
2771 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
2772 f & FEXEC, owp));
2773
2774 if (shcom == NULL && (f & FEXEC) == 0) {
2775 /* Save values in case the child process alters them */
2776 hpin = pin;
2777 hpout = pout;
2778 hwp = *wp;
2779 hinteractive = interactive;
2780 hintr = intr;
2781 hbrklist = brklist;
2782 hexecflg = execflg;
2783
2784 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2785
2786 newpid = vfork();
2787
2788 if (newpid == -1) {
2789 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
2790 return -1;
2791 }
2792
2793
2794 if (newpid > 0) { /* Parent */
2795
2796 /* Restore values */
2797 pin = hpin;
2798 pout = hpout;
2799 *wp = hwp;
2800 interactive = hinteractive;
2801 intr = hintr;
2802 brklist = hbrklist;
2803 execflg = hexecflg;
2804
2805/* moved up
2806 if (i == -1)
2807 return rv;
2808*/
2809
2810 if (pin != NULL)
2811 closepipe(pin);
2812
2813 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
2814 }
2815
2816 /* Must be the child process, pid should be 0 */
2817 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
2818
2819 if (interactive) {
2820 signal(SIGINT, SIG_IGN);
2821 signal(SIGQUIT, SIG_IGN);
2822 resetsig = 1;
2823 }
2824 interactive = 0;
2825 intr = 0;
2826 forked = 1;
2827 brklist = 0;
2828 execflg = 0;
2829 }
2830
2831
2832 if (owp != NULL)
2833 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2834 if (shcom == NULL)
2835 export(lookup(cp));
2836
2837#ifdef COMPIPE
2838 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2839 err("piping to/from shell builtins not yet done");
2840 if (forked)
2841 _exit(-1);
2842 return -1;
2843 }
2844#endif
2845
2846 if (pin != NULL) {
2847 dup2(pin[0], 0);
2848 closepipe(pin);
2849 }
2850 if (pout != NULL) {
2851 dup2(pout[1], 1);
2852 closepipe(pout);
2853 }
2854
2855 if ((iopp = t->ioact) != NULL) {
2856 if (shcom != NULL && shcom != doexec) {
2857 prs(cp);
2858 err(": cannot redirect shell command");
2859 if (forked)
2860 _exit(-1);
2861 return -1;
2862 }
2863 while (*iopp)
2864 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2865 if (forked)
2866 _exit(rv);
2867 return rv;
2868 }
2869 }
2870
2871 if (shcom) {
2872 i = setstatus((*shcom) (t));
2873 if (forked)
2874 _exit(i);
2875 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
2876 return i;
2877 }
2878
2879 /* should use FIOCEXCL */
2880 for (i = FDBASE; i < NOFILE; i++)
2881 close(i);
2882 if (resetsig) {
2883 signal(SIGINT, SIG_DFL);
2884 signal(SIGQUIT, SIG_DFL);
2885 }
2886
2887 if (t->type == TPAREN)
2888 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2889 if (wp[0] == NULL)
2890 _exit(0);
2891
2892 cp = rexecve(wp[0], wp, makenv(0, NULL));
2893 prs(wp[0]);
2894 prs(": ");
2895 err(cp);
2896 if (!execflg)
2897 trap[0] = NULL;
2898
2899 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2900
2901 leave();
2902 /* NOTREACHED */
2903 _exit(1);
2904}
2905
2906/*
2907 * 0< 1> are ignored as required
2908 * within pipelines.
2909 */
2910static int iosetup(struct ioword *iop, int pipein, int pipeout)
2911{
2912 int u = -1;
2913 char *cp = NULL, *msg;
2914
2915 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
2916 pipein, pipeout));
2917
2918 if (iop->io_unit == IODEFAULT) /* take default */
2919 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
2920
2921 if (pipein && iop->io_unit == 0)
2922 return 0;
2923
2924 if (pipeout && iop->io_unit == 1)
2925 return 0;
2926
2927 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
2928 if ((iop->io_flag & IOHERE) == 0) {
2929 cp = iop->io_name;
2930 if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL)
2931 return 1;
2932 }
2933
2934 if (iop->io_flag & IODUP) {
2935 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2936 prs(cp);
2937 err(": illegal >& argument");
2938 return 1;
2939 }
2940 if (*cp == '-')
2941 iop->io_flag = IOCLOSE;
2942 iop->io_flag &= ~(IOREAD | IOWRITE);
2943 }
2944 switch (iop->io_flag) {
2945 case IOREAD:
2946 u = open(cp, 0);
2947 break;
2948
2949 case IOHERE:
2950 case IOHERE | IOXHERE:
2951 u = herein(iop->io_name, iop->io_flag & IOXHERE);
2952 cp = "here file";
2953 break;
2954
2955 case IOWRITE | IOCAT:
2956 if ((u = open(cp, 1)) >= 0) {
2957 lseek(u, (long) 0, SEEK_END);
2958 break;
2959 }
2960 case IOWRITE:
2961 u = creat(cp, 0666);
2962 break;
2963
2964 case IODUP:
2965 u = dup2(*cp - '0', iop->io_unit);
2966 break;
2967
2968 case IOCLOSE:
2969 close(iop->io_unit);
2970 return 0;
2971 }
2972 if (u < 0) {
2973 prs(cp);
2974 prs(": cannot ");
2975 warn(msg);
2976 return 1;
2977 } else {
2978 if (u != iop->io_unit) {
2979 dup2(u, iop->io_unit);
2980 close(u);
2981 }
2982 }
2983 return 0;
2984}
2985
2986static void echo(char **wp)
2987{
2988 int i;
2989
2990 prs("+");
2991 for (i = 0; wp[i]; i++) {
2992 if (i)
2993 prs(" ");
2994 prs(wp[i]);
2995 }
2996 prs("\n");
2997}
2998
2999static struct op **find1case(struct op *t, char *w)
3000{
3001 struct op *t1;
3002 struct op **tp;
3003 char **wp, *cp;
3004
3005
3006 if (t == NULL) {
3007 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
3008 return NULL;
3009 }
3010
3011 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
3012 T_CMD_NAMES[t->type]));
3013
3014 if (t->type == TLIST) {
3015 if ((tp = find1case(t->left, w)) != NULL) {
3016 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
3017 return tp;
3018 }
3019 t1 = t->right; /* TPAT */
3020 } else
3021 t1 = t;
3022
3023 for (wp = t1->words; *wp;)
3024 if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) {
3025 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
3026 &t1->left));
3027 return &t1->left;
3028 }
3029
3030 DBGPRINTF(("FIND1CASE: returning NULL\n"));
3031 return NULL;
3032}
3033
3034static struct op *findcase(struct op *t, char *w)
3035{
3036 struct op **tp;
3037
3038 tp = find1case(t, w);
3039 return tp != NULL ? *tp : NULL;
3040}
3041
3042/*
3043 * Enter a new loop level (marked for break/continue).
3044 */
3045static void brkset(struct brkcon *bc)
3046{
3047 bc->nextlev = brklist;
3048 brklist = bc;
3049}
3050
3051/*
3052 * Wait for the last process created.
3053 * Print a message for each process found
3054 * that was killed by a signal.
3055 * Ignore interrupt signals while waiting
3056 * unless `canintr' is true.
3057 */
3058static int waitfor(int lastpid, int canintr)
3059{
3060 int pid, rv;
3061 int s;
3062 int oheedint = heedint;
3063
3064 heedint = 0;
3065 rv = 0;
3066 do {
3067 pid = wait(&s);
3068 if (pid == -1) {
3069 if (errno != EINTR || canintr)
3070 break;
3071 } else {
3072 if ((rv = WAITSIG(s)) != 0) {
3073 if (rv < NSIGNAL) {
3074 if (signame[rv] != NULL) {
3075 if (pid != lastpid) {
3076 prn(pid);
3077 prs(": ");
3078 }
3079 prs(signame[rv]);
3080 }
3081 } else {
3082 if (pid != lastpid) {
3083 prn(pid);
3084 prs(": ");
3085 }
3086 prs("Signal ");
3087 prn(rv);
3088 prs(" ");
3089 }
3090 if (WAITCORE(s))
3091 prs(" - core dumped");
3092 if (rv >= NSIGNAL || signame[rv])
3093 prs("\n");
3094 rv = -1;
3095 } else
3096 rv = WAITVAL(s);
3097 }
3098 } while (pid != lastpid);
3099 heedint = oheedint;
3100 if (intr) {
3101 if (interactive) {
3102 if (canintr)
3103 intr = 0;
3104 } else {
3105 if (exstat == 0)
3106 exstat = rv;
3107 onintr(0);
3108 }
3109 }
3110 return rv;
3111}
3112
3113static int setstatus(int s)
3114{
3115 exstat = s;
3116 setval(lookup("?"), putn(s));
3117 return s;
3118}
3119
3120/*
3121 * PATH-searching interface to execve.
3122 * If getenv("PATH") were kept up-to-date,
3123 * execvp might be used.
3124 */
3125static char *rexecve(char *c, char **v, char **envp)
3126{
3127 int i;
3128 char *sp, *tp;
3129 int eacces = 0, asis = 0;
3130 char *name = c;
3131
3132 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
3133 optind = 1;
3134 if (find_applet_by_name(name)) {
3135 /* We have to exec here since we vforked. Running
3136 * run_applet_by_name() won't work and bad things
3137 * will happen. */
3138 execve(CONFIG_BUSYBOX_EXEC_PATH, v, envp);
3139 }
3140 }
3141
3142 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
3143
3144 sp = any('/', c) ? "" : path->value;
3145 asis = *sp == '\0';
3146 while (asis || *sp != '\0') {
3147 asis = 0;
3148 tp = e.linep;
3149 for (; *sp != '\0'; tp++)
3150 if ((*tp = *sp++) == ':') {
3151 asis = *sp == '\0';
3152 break;
3153 }
3154 if (tp != e.linep)
3155 *tp++ = '/';
3156 for (i = 0; (*tp++ = c[i++]) != '\0';);
3157
3158 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3159
3160 execve(e.linep, v, envp);
3161
3162 switch (errno) {
3163 case ENOEXEC:
3164 *v = e.linep;
3165 tp = *--v;
3166 *v = e.linep;
3167 execve(DEFAULT_SHELL, v, envp);
3168 *v = tp;
3169 return "no Shell";
3170
3171 case ENOMEM:
3172 return (char *) bb_msg_memory_exhausted;
3173
3174 case E2BIG:
3175 return "argument list too long";
3176
3177 case EACCES:
3178 eacces++;
3179 break;
3180 }
3181 }
3182 return errno == ENOENT ? "not found" : "cannot execute";
3183}
3184
3185/*
3186 * Run the command produced by generator `f'
3187 * applied to stream `arg'.
3188 */
3189static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3190{
3191 struct op *otree;
3192 struct wdblock *swdlist;
3193 struct wdblock *siolist;
3194 jmp_buf ev, rt;
3195 xint *ofail;
3196 int rv;
3197
3198#if __GNUC__
3199 /* Avoid longjmp clobbering */
3200 (void) &rv;
3201#endif
3202
3203 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3204 areanum, outtree, failpt));
3205
3206 areanum++;
3207 swdlist = wdlist;
3208 siolist = iolist;
3209 otree = outtree;
3210 ofail = failpt;
3211 rv = -1;
3212
3213 if (newenv(setjmp(errpt = ev)) == 0) {
3214 wdlist = 0;
3215 iolist = 0;
3216 pushio(argp, f);
3217 e.iobase = e.iop;
3218 yynerrs = 0;
3219 if (setjmp(failpt = rt) == 0 && yyparse() == 0)
3220 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3221 quitenv();
3222 } else {
3223 DBGPRINTF(("RUN: error from newenv()!\n"));
3224 }
3225
3226 wdlist = swdlist;
3227 iolist = siolist;
3228 failpt = ofail;
3229 outtree = otree;
3230 freearea(areanum--);
3231
3232 return rv;
3233}
3234
3235/* -------- do.c -------- */
3236
3237/*
3238 * built-in commands: doX
3239 */
3240
3241static int dohelp(struct op *t)
3242{
3243 int col;
3244 const struct builtincmd *x;
3245
3246 printf("\nBuilt-in commands:\n");
3247 printf("-------------------\n");
3248
3249 for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
3250 if (!x->name)
3251 continue;
3252 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
3253 if (col > 60) {
3254 puts("");
3255 col = 0;
3256 }
3257 }
3258#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3259 {
3260 int i;
3261 const struct BB_applet *applet;
3262 extern const struct BB_applet applets[];
3263 extern const size_t NUM_APPLETS;
3264
3265 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
3266 if (!applet->name)
3267 continue;
3268
3269 col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
3270 if (col > 60) {
3271 puts("");
3272 col = 0;
3273 }
3274 }
3275 }
3276#endif
3277 printf("\n\n");
3278 return EXIT_SUCCESS;
3279}
3280
3281
3282
3283static int dolabel(struct op *t)
3284{
3285 return 0;
3286}
3287
3288static int dochdir(struct op *t)
3289{
3290 char *cp, *er;
3291
3292 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
3293 er = ": no home directory";
3294 else if (chdir(cp) < 0)
3295 er = ": bad directory";
3296 else
3297 return 0;
3298 prs(cp != NULL ? cp : "cd");
3299 err(er);
3300 return 1;
3301}
3302
3303static int doshift(struct op *t)
3304{
3305 int n;
3306
3307 n = t->words[1] ? getn(t->words[1]) : 1;
3308 if (dolc < n) {
3309 err("nothing to shift");
3310 return 1;
3311 }
3312 dolv[n] = dolv[0];
3313 dolv += n;
3314 dolc -= n;
3315 setval(lookup("#"), putn(dolc));
3316 return 0;
3317}
3318
3319/*
3320 * execute login and newgrp directly
3321 */
3322static int dologin(struct op *t)
3323{
3324 char *cp;
3325
3326 if (interactive) {
3327 signal(SIGINT, SIG_DFL);
3328 signal(SIGQUIT, SIG_DFL);
3329 }
3330 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
3331 prs(t->words[0]);
3332 prs(": ");
3333 err(cp);
3334 return 1;
3335}
3336
3337static int doumask(struct op *t)
3338{
3339 int i, n;
3340 char *cp;
3341
3342 if ((cp = t->words[1]) == NULL) {
3343 i = umask(0);
3344 umask(i);
3345 for (n = 3 * 4; (n -= 3) >= 0;)
3346 putc('0' + ((i >> n) & 07), stderr);
3347 putc('\n', stderr);
3348 } else {
3349 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3350 n = n * 8 + (*cp - '0');
3351 umask(n);
3352 }
3353 return 0;
3354}
3355
3356static int doexec(struct op *t)
3357{
3358 int i;
3359 jmp_buf ex;
3360 xint *ofail;
3361
3362 t->ioact = NULL;
3363 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
3364 if (i == 0)
3365 return 1;
3366 execflg = 1;
3367 ofail = failpt;
3368 if (setjmp(failpt = ex) == 0)
3369 execute(t, NOPIPE, NOPIPE, FEXEC);
3370 failpt = ofail;
3371 execflg = 0;
3372 return 1;
3373}
3374
3375static int dodot(struct op *t)
3376{
3377 int i;
3378 char *sp, *tp;
3379 char *cp;
3380 int maltmp;
3381
3382 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
3383
3384 if ((cp = t->words[1]) == NULL) {
3385 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3386 return 0;
3387 } else {
3388 DBGPRINTF(("DODOT: cp is %s\n", cp));
3389 }
3390
3391 sp = any('/', cp) ? ":" : path->value;
3392
3393 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3394 ((sp == NULL) ? "NULL" : sp),
3395 ((e.linep == NULL) ? "NULL" : e.linep)));
3396
3397 while (*sp) {
3398 tp = e.linep;
3399 while (*sp && (*tp = *sp++) != ':')
3400 tp++;
3401 if (tp != e.linep)
3402 *tp++ = '/';
3403
3404 for (i = 0; (*tp++ = cp[i++]) != '\0';);
3405
3406 /* Original code */
3407 if ((i = open(e.linep, 0)) >= 0) {
3408 exstat = 0;
3409 maltmp = remap(i);
3410 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3411
3412 next(maltmp); /* Basically a PUSHIO */
3413
3414 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3415
3416 return exstat;
3417 }
3418
3419 } /* While */
3420
3421 prs(cp);
3422 err(": not found");
3423
3424 return -1;
3425}
3426
3427static int dowait(struct op *t)
3428{
3429 int i;
3430 char *cp;
3431
3432 if ((cp = t->words[1]) != NULL) {
3433 i = getn(cp);
3434 if (i == 0)
3435 return 0;
3436 } else
3437 i = -1;
3438 setstatus(waitfor(i, 1));
3439 return 0;
3440}
3441
3442static int doread(struct op *t)
3443{
3444 char *cp, **wp;
3445 int nb = 0;
3446 int nl = 0;
3447
3448 if (t->words[1] == NULL) {
3449 err("Usage: read name ...");
3450 return 1;
3451 }
3452 for (wp = t->words + 1; *wp; wp++) {
3453 for (cp = e.linep; !nl && cp < elinep - 1; cp++)
3454 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
3455 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
3456 break;
3457 *cp = 0;
3458 if (nb <= 0)
3459 break;
3460 setval(lookup(*wp), e.linep);
3461 }
3462 return nb <= 0;
3463}
3464
3465static int doeval(struct op *t)
3466{
3467 return RUN(awordlist, t->words + 1, wdchar);
3468}
3469
3470static int dotrap(struct op *t)
3471{
3472 int n, i;
3473 int resetsig;
3474
3475 if (t->words[1] == NULL) {
3476 for (i = 0; i <= _NSIG; i++)
3477 if (trap[i]) {
3478 prn(i);
3479 prs(": ");
3480 prs(trap[i]);
3481 prs("\n");
3482 }
3483 return 0;
3484 }
3485 resetsig = isdigit(*t->words[1]);
3486 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3487 n = getsig(t->words[i]);
3488 freecell(trap[n]);
3489 trap[n] = 0;
3490 if (!resetsig) {
3491 if (*t->words[1] != '\0') {
3492 trap[n] = strsave(t->words[1], 0);
3493 setsig(n, sig);
3494 } else
3495 setsig(n, SIG_IGN);
3496 } else {
3497 if (interactive)
3498 if (n == SIGINT)
3499 setsig(n, onintr);
3500 else
3501 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3502 else
3503 setsig(n, SIG_DFL);
3504 }
3505 }
3506 return 0;
3507}
3508
3509static int getsig(char *s)
3510{
3511 int n;
3512
3513 if ((n = getn(s)) < 0 || n > _NSIG) {
3514 err("trap: bad signal number");
3515 n = 0;
3516 }
3517 return n;
3518}
3519
3520static void setsig(int n, sighandler_t f)
3521{
3522 if (n == 0)
3523 return;
3524 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3525 ourtrap[n] = 1;
3526 signal(n, f);
3527 }
3528}
3529
3530static int getn(char *as)
3531{
3532 char *s;
3533 int n, m;
3534
3535 s = as;
3536 m = 1;
3537 if (*s == '-') {
3538 m = -1;
3539 s++;
3540 }
3541 for (n = 0; isdigit(*s); s++)
3542 n = (n * 10) + (*s - '0');
3543 if (*s) {
3544 prs(as);
3545 err(": bad number");
3546 }
3547 return n * m;
3548}
3549
3550static int dobreak(struct op *t)
3551{
3552 return brkcontin(t->words[1], 1);
3553}
3554
3555static int docontinue(struct op *t)
3556{
3557 return brkcontin(t->words[1], 0);
3558}
3559
3560static int brkcontin(char *cp, int val)
3561{
3562 struct brkcon *bc;
3563 int nl;
3564
3565 nl = cp == NULL ? 1 : getn(cp);
3566 if (nl <= 0)
3567 nl = 999;
3568 do {
3569 if ((bc = brklist) == NULL)
3570 break;
3571 brklist = bc->nextlev;
3572 } while (--nl);
3573 if (nl) {
3574 err("bad break/continue level");
3575 return 1;
3576 }
3577 isbreak = val;
3578 longjmp(bc->brkpt, 1);
3579 /* NOTREACHED */
3580}
3581
3582static int doexit(struct op *t)
3583{
3584 char *cp;
3585
3586 execflg = 0;
3587 if ((cp = t->words[1]) != NULL)
3588 setstatus(getn(cp));
3589
3590 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
3591
3592 leave();
3593 /* NOTREACHED */
3594 return 0;
3595}
3596
3597static int doexport(struct op *t)
3598{
3599 rdexp(t->words + 1, export, EXPORT);
3600 return 0;
3601}
3602
3603static int doreadonly(struct op *t)
3604{
3605 rdexp(t->words + 1, ronly, RONLY);
3606 return 0;
3607}
3608
3609static void rdexp(char **wp, void (*f) (struct var *), int key)
3610{
3611 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
3612 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3613
3614 if (*wp != NULL) {
3615 for (; *wp != NULL; wp++) {
3616 if (isassign(*wp)) {
3617 char *cp;
3618
3619 assign(*wp, COPYV);
3620 for (cp = *wp; *cp != '='; cp++);
3621 *cp = '\0';
3622 }
3623 if (checkname(*wp))
3624 (*f) (lookup(*wp));
3625 else
3626 badid(*wp);
3627 }
3628 } else
3629 putvlist(key, 1);
3630}
3631
3632static void badid(char *s)
3633{
3634 prs(s);
3635 err(": bad identifier");
3636}
3637
3638static int doset(struct op *t)
3639{
3640 struct var *vp;
3641 char *cp;
3642 int n;
3643
3644 if ((cp = t->words[1]) == NULL) {
3645 for (vp = vlist; vp; vp = vp->next)
3646 varput(vp->name, 1);
3647 return 0;
3648 }
3649 if (*cp == '-') {
3650 /* bad: t->words++; */
3651 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
3652 if (*++cp == 0)
3653 flag['x'] = flag['v'] = 0;
3654 else
3655 for (; *cp; cp++)
3656 switch (*cp) {
3657 case 'e':
3658 if (!interactive)
3659 flag['e']++;
3660 break;
3661
3662 default:
3663 if (*cp >= 'a' && *cp <= 'z')
3664 flag[(int) *cp]++;
3665 break;
3666 }
3667 setdash();
3668 }
3669 if (t->words[1]) {
3670 t->words[0] = dolv[0];
3671 for (n = 1; t->words[n]; n++)
3672 setarea((char *) t->words[n], 0);
3673 dolc = n - 1;
3674 dolv = t->words;
3675 setval(lookup("#"), putn(dolc));
3676 setarea((char *) (dolv - 1), 0);
3677 }
3678 return 0;
3679}
3680
3681static void varput(char *s, int out)
3682{
3683 if (isalnum(*s) || *s == '_') {
3684 write(out, s, strlen(s));
3685 write(out, "\n", 1);
3686 }
3687}
3688
3689
3690/*
3691 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3692 * This file contains code for the times builtin.
3693 */
3694static int dotimes(struct op *t)
3695{
3696 struct tms buf;
3697 long int clk_tck = sysconf(_SC_CLK_TCK);
3698
3699 times(&buf);
3700 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
3701 (int) (buf.tms_utime / clk_tck / 60),
3702 ((double) buf.tms_utime) / clk_tck,
3703 (int) (buf.tms_stime / clk_tck / 60),
3704 ((double) buf.tms_stime) / clk_tck,
3705 (int) (buf.tms_cutime / clk_tck / 60),
3706 ((double) buf.tms_cutime) / clk_tck,
3707 (int) (buf.tms_cstime / clk_tck / 60),
3708 ((double) buf.tms_cstime) / clk_tck);
3709 return 0;
3710}
3711
3712
3713static int (*inbuilt(char *s)) (struct op *) {
3714 const struct builtincmd *bp;
3715
3716 for (bp = builtincmds; bp->name != NULL; bp++)
3717 if (strcmp(bp->name, s) == 0)
3718 return bp->builtinfunc;
3719
3720 return NULL;
3721}
3722
3723/* -------- eval.c -------- */
3724
3725/*
3726 * ${}
3727 * `command`
3728 * blank interpretation
3729 * quoting
3730 * glob
3731 */
3732
3733static char **eval(char **ap, int f)
3734{
3735 struct wdblock *wb;
3736 char **wp;
3737 char **wf;
3738 jmp_buf ev;
3739
3740#if __GNUC__
3741 /* Avoid longjmp clobbering */
3742 (void) &wp;
3743 (void) &ap;
3744#endif
3745
3746 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3747
3748 wp = NULL;
3749 wb = NULL;
3750 wf = NULL;
3751 if (newenv(setjmp(errpt = ev)) == 0) {
3752 while (*ap && isassign(*ap))
3753 expand(*ap++, &wb, f & ~DOGLOB);
3754 if (flag['k']) {
3755 for (wf = ap; *wf; wf++) {
3756 if (isassign(*wf))
3757 expand(*wf, &wb, f & ~DOGLOB);
3758 }
3759 }
3760 for (wb = addword((char *) 0, wb); *ap; ap++) {
3761 if (!flag['k'] || !isassign(*ap))
3762 expand(*ap, &wb, f & ~DOKEY);
3763 }
3764 wb = addword((char *) 0, wb);
3765 wp = getwords(wb);
3766 quitenv();
3767 } else
3768 gflg = 1;
3769
3770 return gflg ? (char **) NULL : wp;
3771}
3772
3773/*
3774 * Make the exported environment from the exported
3775 * names in the dictionary. Keyword assignments
3776 * will already have been done.
3777 */
3778static char **makenv(int all, struct wdblock *wb)
3779{
3780 struct var *vp;
3781
3782 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3783
3784 for (vp = vlist; vp; vp = vp->next)
3785 if (all || vp->status & EXPORT)
3786 wb = addword(vp->name, wb);
3787 wb = addword((char *) 0, wb);
3788 return getwords(wb);
3789}
3790
3791static char *evalstr(char *cp, int f)
3792{
3793 struct wdblock *wb;
3794
3795 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3796
3797 wb = NULL;
3798 if (expand(cp, &wb, f)) {
3799 if (wb == NULL || wb->w_nword == 0
3800 || (cp = wb->w_words[0]) == NULL)
3801 cp = "";
3802 DELETE(wb);
3803 } else
3804 cp = NULL;
3805 return cp;
3806}
3807
3808static int expand(char *cp, struct wdblock **wbp, int f)
3809{
3810 jmp_buf ev;
3811
3812#if __GNUC__
3813 /* Avoid longjmp clobbering */
3814 (void) &cp;
3815#endif
3816
3817 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3818
3819 gflg = 0;
3820
3821 if (cp == NULL)
3822 return 0;
3823
3824 if (!anys("$`'\"", cp) &&
3825 !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
3826 cp = strsave(cp, areanum);
3827 if (f & DOTRIM)
3828 unquote(cp);
3829 *wbp = addword(cp, *wbp);
3830 return 1;
3831 }
3832 if (newenv(setjmp(errpt = ev)) == 0) {
3833 PUSHIO(aword, cp, strchar);
3834 e.iobase = e.iop;
3835 while ((cp = blank(f)) && gflg == 0) {
3836 e.linep = cp;
3837 cp = strsave(cp, areanum);
3838 if ((f & DOGLOB) == 0) {
3839 if (f & DOTRIM)
3840 unquote(cp);
3841 *wbp = addword(cp, *wbp);
3842 } else
3843 *wbp = glob(cp, *wbp);
3844 }
3845 quitenv();
3846 } else
3847 gflg = 1;
3848 return gflg == 0;
3849}
3850
3851/*
3852 * Blank interpretation and quoting
3853 */
3854static char *blank(int f)
3855{
3856 int c, c1;
3857 char *sp;
3858 int scanequals, foundequals;
3859
3860 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3861
3862 sp = e.linep;
3863 scanequals = f & DOKEY;
3864 foundequals = 0;
3865
3866 loop:
3867 switch (c = subgetc('"', foundequals)) {
3868 case 0:
3869 if (sp == e.linep)
3870 return 0;
3871 *e.linep++ = 0;
3872 return sp;
3873
3874 default:
3875 if (f & DOBLANK && any(c, ifs->value))
3876 goto loop;
3877 break;
3878
3879 case '"':
3880 case '\'':
3881 scanequals = 0;
3882 if (INSUB())
3883 break;
3884 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3885 if (c == 0)
3886 break;
3887 if (c == '\'' || !any(c, "$`\""))
3888 c |= QUOTE;
3889 *e.linep++ = c;
3890 }
3891 c = 0;
3892 }
3893 unget(c);
3894 if (!isalpha(c) && c != '_')
3895 scanequals = 0;
3896 for (;;) {
3897 c = subgetc('"', foundequals);
3898 if (c == 0 ||
3899 f & (DOBLANK && any(c, ifs->value)) ||
3900 (!INSUB() && any(c, "\"'"))) {
3901 scanequals = 0;
3902 unget(c);
3903 if (any(c, "\"'"))
3904 goto loop;
3905 break;
3906 }
3907 if (scanequals) {
3908 if (c == '=') {
3909 foundequals = 1;
3910 scanequals = 0;
3911 } else if (!isalnum(c) && c != '_')
3912 scanequals = 0;
3913 }
3914 *e.linep++ = c;
3915 }
3916 *e.linep++ = 0;
3917 return sp;
3918}
3919
3920/*
3921 * Get characters, substituting for ` and $
3922 */
3923static int subgetc(char ec, int quoted)
3924{
3925 char c;
3926
3927 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
3928
3929 again:
3930 c = my_getc(ec);
3931 if (!INSUB() && ec != '\'') {
3932 if (c == '`') {
3933 if (grave(quoted) == 0)
3934 return 0;
3935 e.iop->task = XGRAVE;
3936 goto again;
3937 }
3938 if (c == '$' && (c = dollar(quoted)) == 0) {
3939 e.iop->task = XDOLL;
3940 goto again;
3941 }
3942 }
3943 return c;
3944}
3945
3946/*
3947 * Prepare to generate the string returned by ${} substitution.
3948 */
3949static int dollar(int quoted)
3950{
3951 int otask;
3952 struct io *oiop;
3953 char *dolp;
3954 char *s, c, *cp = NULL;
3955 struct var *vp;
3956
3957 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3958
3959 c = readc();
3960 s = e.linep;
3961 if (c != '{') {
3962 *e.linep++ = c;
3963 if (isalpha(c) || c == '_') {
3964 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
3965 if (e.linep < elinep)
3966 *e.linep++ = c;
3967 unget(c);
3968 }
3969 c = 0;
3970 } else {
3971 oiop = e.iop;
3972 otask = e.iop->task;
3973
3974 e.iop->task = XOTHER;
3975 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
3976 if (e.linep < elinep)
3977 *e.linep++ = c;
3978 if (oiop == e.iop)
3979 e.iop->task = otask;
3980 if (c != '}') {
3981 err("unclosed ${");
3982 gflg++;
3983 return c;
3984 }
3985 }
3986 if (e.linep >= elinep) {
3987 err("string in ${} too long");
3988 gflg++;
3989 e.linep -= 10;
3990 }
3991 *e.linep = 0;
3992 if (*s)
3993 for (cp = s + 1; *cp; cp++)
3994 if (any(*cp, "=-+?")) {
3995 c = *cp;
3996 *cp++ = 0;
3997 break;
3998 }
3999 if (s[1] == 0 && (*s == '*' || *s == '@')) {
4000 if (dolc > 1) {
4001 /* currently this does not distinguish $* and $@ */
4002 /* should check dollar */
4003 e.linep = s;
4004 PUSHIO(awordlist, dolv + 1, dolchar);
4005 return 0;
4006 } else { /* trap the nasty ${=} */
4007 s[0] = '1';
4008 s[1] = 0;
4009 }
4010 }
4011 vp = lookup(s);
4012 if ((dolp = vp->value) == null) {
4013 switch (c) {
4014 case '=':
4015 if (isdigit(*s)) {
4016 err("cannot use ${...=...} with $n");
4017 gflg++;
4018 break;
4019 }
4020 setval(vp, cp);
4021 dolp = vp->value;
4022 break;
4023
4024 case '-':
4025 dolp = strsave(cp, areanum);
4026 break;
4027
4028 case '?':
4029 if (*cp == 0) {
4030 prs("missing value for ");
4031 err(s);
4032 } else
4033 err(cp);
4034 gflg++;
4035 break;
4036 }
4037 } else if (c == '+')
4038 dolp = strsave(cp, areanum);
4039 if (flag['u'] && dolp == null) {
4040 prs("unset variable: ");
4041 err(s);
4042 gflg++;
4043 }
4044 e.linep = s;
4045 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
4046 return 0;
4047}
4048
4049/*
4050 * Run the command in `...` and read its output.
4051 */
4052
4053static int grave(int quoted)
4054{
4055 char *cp;
4056 int i;
4057 int j;
4058 int pf[2];
4059 static char child_cmd[LINELIM];
4060 char *src;
4061 char *dest;
4062 int count;
4063 int ignore;
4064 int ignore_once;
4065 char *argument_list[4];
4066 struct wdblock *wb = NULL;
4067
4068#if __GNUC__
4069 /* Avoid longjmp clobbering */
4070 (void) &cp;
4071#endif
4072
4073 for (cp = e.iop->argp->aword; *cp != '`'; cp++)
4074 if (*cp == 0) {
4075 err("no closing `");
4076 return 0;
4077 }
4078
4079 /* string copy with dollar expansion */
4080 src = e.iop->argp->aword;
4081 dest = child_cmd;
4082 count = 0;
4083 ignore = 0;
4084 ignore_once = 0;
4085 while ((*src != '`') && (count < LINELIM)) {
4086 if (*src == '\'')
4087 ignore = !ignore;
4088 if (*src == '\\')
4089 ignore_once = 1;
4090 if (*src == '$' && !ignore && !ignore_once) {
4091 struct var *vp;
4092 char var_name[LINELIM];
4093 char alt_value[LINELIM];
4094 int var_index = 0;
4095 int alt_index = 0;
4096 char operator = 0;
4097 int braces = 0;
4098 char *value;
4099
4100 src++;
4101 if (*src == '{') {
4102 braces = 1;
4103 src++;
4104 }
4105
4106 var_name[var_index++] = *src++;
4107 while (isalnum(*src) || *src=='_')
4108 var_name[var_index++] = *src++;
4109 var_name[var_index] = 0;
4110
4111 if (braces) {
4112 switch (*src) {
4113 case '}':
4114 break;
4115 case '-':
4116 case '=':
4117 case '+':
4118 case '?':
4119 operator = * src;
4120 break;
4121 default:
4122 err("unclosed ${\n");
4123 return 0;
4124 }
4125 if (operator) {
4126 src++;
4127 while (*src && (*src != '}')) {
4128 alt_value[alt_index++] = *src++;
4129 }
4130 alt_value[alt_index] = 0;
4131 if (*src != '}') {
4132 err("unclosed ${\n");
4133 return 0;
4134 }
4135 }
4136 src++;
4137 }
4138
4139 if (isalpha(*var_name)) {
4140 /* let subshell handle it instead */
4141
4142 char *namep = var_name;
4143
4144 *dest++ = '$';
4145 if (braces)
4146 *dest++ = '{';
4147 while (*namep)
4148 *dest++ = *namep++;
4149 if (operator) {
4150 char *altp = alt_value;
4151 *dest++ = operator;
4152 while (*altp)
4153 *dest++ = *altp++;
4154 }
4155 if (braces)
4156 *dest++ = '}';
4157
4158 wb = addword(lookup(var_name)->name, wb);
4159 } else {
4160 /* expand */
4161
4162 vp = lookup(var_name);
4163 if (vp->value != null)
4164 value = (operator == '+') ?
4165 alt_value : vp->value;
4166 else if (operator == '?') {
4167 err(alt_value);
4168 return 0;
4169 } else if (alt_index && (operator != '+')) {
4170 value = alt_value;
4171 if (operator == '=')
4172 setval(vp, value);
4173 } else
4174 continue;
4175
4176 while (*value && (count < LINELIM)) {
4177 *dest++ = *value++;
4178 count++;
4179 }
4180 }
4181 } else {
4182 *dest++ = *src++;
4183 count++;
4184 ignore_once = 0;
4185 }
4186 }
4187 *dest = '\0';
4188
4189 if (openpipe(pf) < 0)
4190 return 0;
4191
4192 while ((i = vfork()) == -1 && errno == EAGAIN);
4193
4194 DBGPRINTF3(("GRAVE: i is %p\n", io));
4195
4196 if (i < 0) {
4197 closepipe(pf);
4198 err((char *) bb_msg_memory_exhausted);
4199 return 0;
4200 }
4201 if (i != 0) {
4202 waitpid(i, NULL, 0);
4203 e.iop->argp->aword = ++cp;
4204 close(pf[1]);
4205 PUSHIO(afile, remap(pf[0]),
4206 (int (*)(struct ioarg *)) ((quoted) ? qgravechar :
4207 gravechar));
4208 return 1;
4209 }
4210 /* allow trapped signals */
4211 /* XXX - Maybe this signal stuff should go as well? */
4212 for (j = 0; j <= _NSIG; j++)
4213 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4214 signal(j, SIG_DFL);
4215
4216 dup2(pf[1], 1);
4217 closepipe(pf);
4218
4219 argument_list[0] = (char *) DEFAULT_SHELL;
4220 argument_list[1] = "-c";
4221 argument_list[2] = child_cmd;
4222 argument_list[3] = 0;
4223
4224 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4225 prs(argument_list[0]);
4226 prs(": ");
4227 err(cp);
4228 _exit(1);
4229}
4230
4231
4232static char *unquote(char *as)
4233{
4234 char *s;
4235
4236 if ((s = as) != NULL)
4237 while (*s)
4238 *s++ &= ~QUOTE;
4239 return as;
4240}
4241
4242/* -------- glob.c -------- */
4243
4244/*
4245 * glob
4246 */
4247
4248#define scopy(x) strsave((x), areanum)
4249#define BLKSIZ 512
4250#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4251
4252static struct wdblock *cl, *nl;
4253static char spcl[] = "[?*";
4254
4255static struct wdblock *glob(char *cp, struct wdblock *wb)
4256{
4257 int i;
4258 char *pp;
4259
4260 if (cp == 0)
4261 return wb;
4262 i = 0;
4263 for (pp = cp; *pp; pp++)
4264 if (any(*pp, spcl))
4265 i++;
4266 else if (!any(*pp & ~QUOTE, spcl))
4267 *pp &= ~QUOTE;
4268 if (i != 0) {
4269 for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
4270 cl = nl) {
4271 nl = newword(cl->w_nword * 2);
4272 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
4273 for (pp = cl->w_words[i]; *pp; pp++)
4274 if (any(*pp, spcl)) {
4275 globname(cl->w_words[i], pp);
4276 break;
4277 }
4278 if (*pp == '\0')
4279 nl = addword(scopy(cl->w_words[i]), nl);
4280 }
4281 for (i = 0; i < cl->w_nword; i++)
4282 DELETE(cl->w_words[i]);
4283 DELETE(cl);
4284 }
4285 for (i = 0; i < cl->w_nword; i++)
4286 unquote(cl->w_words[i]);
4287 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
4288 if (cl->w_nword) {
4289 for (i = 0; i < cl->w_nword; i++)
4290 wb = addword(cl->w_words[i], wb);
4291 DELETE(cl);
4292 return wb;
4293 }
4294 }
4295 wb = addword(unquote(cp), wb);
4296 return wb;
4297}
4298
4299static void globname(char *we, char *pp)
4300{
4301 char *np, *cp;
4302 char *name, *gp, *dp;
4303 int k;
4304 DIR *dirp;
4305 struct dirent *de;
4306 char dname[NAME_MAX + 1];
4307 struct stat dbuf;
4308
4309 for (np = we; np != pp; pp--)
4310 if (pp[-1] == '/')
4311 break;
4312 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
4313 *cp++ = *np++;
4314 *cp++ = '.';
4315 *cp = '\0';
4316 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
4317 *cp++ = *np++;
4318 *cp = '\0';
4319 dirp = opendir(dp);
4320 if (dirp == 0) {
4321 DELETE(dp);
4322 DELETE(gp);
4323 return;
4324 }
4325 dname[NAME_MAX] = '\0';
4326 while ((de = readdir(dirp)) != NULL) {
4327 /* XXX Hmmm... What this could be? (abial) */
4328 /*
4329 if (ent[j].d_ino == 0)
4330 continue;
4331 */
4332 strncpy(dname, de->d_name, NAME_MAX);
4333 if (dname[0] == '.')
4334 if (*gp != '.')
4335 continue;
4336 for (k = 0; k < NAME_MAX; k++)
4337 if (any(dname[k], spcl))
4338 dname[k] |= QUOTE;
4339 if (gmatch(dname, gp)) {
4340 name = generate(we, pp, dname, np);
4341 if (*np && !anys(np, spcl)) {
4342 if (stat(name, &dbuf)) {
4343 DELETE(name);
4344 continue;
4345 }
4346 }
4347 nl = addword(name, nl);
4348 }
4349 }
4350 closedir(dirp);
4351 DELETE(dp);
4352 DELETE(gp);
4353}
4354
4355/*
4356 * generate a pathname as below.
4357 * start..end1 / middle end
4358 * the slashes come for free
4359 */
4360static char *generate(char *start1, char *end1, char *middle, char *end)
4361{
4362 char *p;
4363 char *op, *xp;
4364
4365 p = op =
4366 space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
4367 for (xp = start1; xp != end1;)
4368 *op++ = *xp++;
4369 for (xp = middle; (*op++ = *xp++) != '\0';);
4370 op--;
4371 for (xp = end; (*op++ = *xp++) != '\0';);
4372 return p;
4373}
4374
4375static int anyspcl(struct wdblock *wb)
4376{
4377 int i;
4378 char **wd;
4379
4380 wd = wb->w_words;
4381 for (i = 0; i < wb->w_nword; i++)
4382 if (anys(spcl, *wd++))
4383 return 1;
4384 return 0;
4385}
4386
4387static int xstrcmp(char *p1, char *p2)
4388{
4389 return strcmp(*(char **) p1, *(char **) p2);
4390}
4391
4392/* -------- word.c -------- */
4393
4394static struct wdblock *newword(int nw)
4395{
4396 struct wdblock *wb;
4397
4398 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
4399 wb->w_bsize = nw;
4400 wb->w_nword = 0;
4401 return wb;
4402}
4403
4404static struct wdblock *addword(char *wd, struct wdblock *wb)
4405{
4406 struct wdblock *wb2;
4407 int nw;
4408
4409 if (wb == NULL)
4410 wb = newword(NSTART);
4411 if ((nw = wb->w_nword) >= wb->w_bsize) {
4412 wb2 = newword(nw * 2);
4413 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4414 nw * sizeof(char *));
4415 wb2->w_nword = nw;
4416 DELETE(wb);
4417 wb = wb2;
4418 }
4419 wb->w_words[wb->w_nword++] = wd;
4420 return wb;
4421}
4422
4423static
4424char **getwords(struct wdblock *wb)
4425{
4426 char **wd;
4427 int nb;
4428
4429 if (wb == NULL)
4430 return NULL;
4431 if (wb->w_nword == 0) {
4432 DELETE(wb);
4433 return NULL;
4434 }
4435 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
4436 memcpy((char *) wd, (char *) wb->w_words, nb);
4437 DELETE(wb); /* perhaps should done by caller */
4438 return wd;
4439}
4440
4441static int (*func) (char *, char *);
4442static int globv;
4443
4444static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
4445{
4446 func = a3;
4447 globv = a2;
4448 glob1(a0, a0 + a1 * a2);
4449}
4450
4451static void glob1(char *base, char *lim)
4452{
4453 char *i, *j;
4454 int v2;
4455 char *lptr, *hptr;
4456 int c;
4457 unsigned n;
4458
4459
4460 v2 = globv;
4461
4462 top:
4463 if ((n = (int) (lim - base)) <= v2)
4464 return;
4465 n = v2 * (n / (2 * v2));
4466 hptr = lptr = base + n;
4467 i = base;
4468 j = lim - v2;
4469 for (;;) {
4470 if (i < lptr) {
4471 if ((c = (*func) (i, lptr)) == 0) {
4472 glob2(i, lptr -= v2);
4473 continue;
4474 }
4475 if (c < 0) {
4476 i += v2;
4477 continue;
4478 }
4479 }
4480
4481 begin:
4482 if (j > hptr) {
4483 if ((c = (*func) (hptr, j)) == 0) {
4484 glob2(hptr += v2, j);
4485 goto begin;
4486 }
4487 if (c > 0) {
4488 if (i == lptr) {
4489 glob3(i, hptr += v2, j);
4490 i = lptr += v2;
4491 goto begin;
4492 }
4493 glob2(i, j);
4494 j -= v2;
4495 i += v2;
4496 continue;
4497 }
4498 j -= v2;
4499 goto begin;
4500 }
4501
4502
4503 if (i == lptr) {
4504 if (lptr - base >= lim - hptr) {
4505 glob1(hptr + v2, lim);
4506 lim = lptr;
4507 } else {
4508 glob1(base, lptr);
4509 base = hptr + v2;
4510 }
4511 goto top;
4512 }
4513
4514
4515 glob3(j, lptr -= v2, i);
4516 j = hptr -= v2;
4517 }
4518}
4519
4520static void glob2(char *i, char *j)
4521{
4522 char *index1, *index2, c;
4523 int m;
4524
4525 m = globv;
4526 index1 = i;
4527 index2 = j;
4528 do {
4529 c = *index1;
4530 *index1++ = *index2;
4531 *index2++ = c;
4532 } while (--m);
4533}
4534
4535static void glob3(char *i, char *j, char *k)
4536{
4537 char *index1, *index2, *index3;
4538 int c;
4539 int m;
4540
4541 m = globv;
4542 index1 = i;
4543 index2 = j;
4544 index3 = k;
4545 do {
4546 c = *index1;
4547 *index1++ = *index3;
4548 *index3++ = *index2;
4549 *index2++ = c;
4550 } while (--m);
4551}
4552
4553/* -------- io.c -------- */
4554
4555/*
4556 * shell IO
4557 */
4558
4559static int my_getc(int ec)
4560{
4561 int c;
4562
4563 if (e.linep > elinep) {
4564 while ((c = readc()) != '\n' && c);
4565 err("input line too long");
4566 gflg++;
4567 return c;
4568 }
4569 c = readc();
4570 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
4571 if (c == '\\') {
4572 c = readc();
4573 if (c == '\n' && ec != '\"')
4574 return my_getc(ec);
4575 c |= QUOTE;
4576 }
4577 }
4578 return c;
4579}
4580
4581static void unget(int c)
4582{
4583 if (e.iop >= e.iobase)
4584 e.iop->peekc = c;
4585}
4586
4587static int eofc(void)
4588{
4589 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
4590}
4591
4592static int readc(void)
4593{
4594 int c;
4595
4596 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
4597
4598 for (; e.iop >= e.iobase; e.iop--) {
4599 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
4600 if ((c = e.iop->peekc) != '\0') {
4601 e.iop->peekc = 0;
4602 return c;
4603 } else {
4604 if (e.iop->prev != 0) {
4605 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
4606 if (c == -1) {
4607 e.iop++;
4608 continue;
4609 }
4610 if (e.iop == iostack)
4611 ioecho(c);
4612 return (e.iop->prev = c);
4613 } else if (e.iop->task == XIO && e.iop->prev != '\n') {
4614 e.iop->prev = 0;
4615 if (e.iop == iostack)
4616 ioecho('\n');
4617 return '\n';
4618 }
4619 }
4620 if (e.iop->task == XIO) {
4621 if (multiline) {
4622 return e.iop->prev = 0;
4623 }
4624 if (interactive && e.iop == iostack + 1) {
4625#ifdef CONFIG_FEATURE_COMMAND_EDITING
4626 current_prompt = prompt->value;
4627#else
4628 prs(prompt->value);
4629#endif
4630 }
4631 }
4632 }
4633
4634 } /* FOR */
4635
4636 if (e.iop >= iostack) {
4637 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
4638 return 0;
4639 }
4640
4641 DBGPRINTF(("READC: leave()...\n"));
4642 leave();
4643
4644 /* NOTREACHED */
4645 return 0;
4646}
4647
4648static void ioecho(char c)
4649{
4650 if (flag['v'])
4651 write(2, &c, sizeof c);
4652}
4653
4654
4655static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4656{
4657 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
4658 argp->afid, e.iop));
4659
4660 /* Set env ptr for io source to next array spot and check for array overflow */
4661 if (++e.iop >= &iostack[NPUSH]) {
4662 e.iop--;
4663 err("Shell input nested too deeply");
4664 gflg++;
4665 return;
4666 }
4667
4668 /* We did not overflow the NPUSH array spots so setup data structs */
4669
4670 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
4671
4672 if (argp->afid != AFID_NOBUF)
4673 e.iop->argp = argp;
4674 else {
4675
4676 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4677 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4678
4679 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4680
4681 if (e.iop == &iostack[0])
4682 e.iop->argp->afbuf = &mainbuf;
4683 else
4684 e.iop->argp->afbuf = &sharedbuf;
4685
4686 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4687 /* This line appears to be active when running scripts from command line */
4688 if ((isatty(e.iop->argp->afile) == 0)
4689 && (e.iop == &iostack[0]
4690 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
4691 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4692 bufid = AFID_ID; /* AFID_ID = 0 */
4693
4694 e.iop->argp->afid = bufid; /* assign buffer id */
4695 }
4696
4697 DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n",
4698 iostack, e.iop, e.iop->argp->afbuf));
4699 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
4700 &mainbuf, &sharedbuf, bufid, e.iop));
4701
4702 }
4703
4704 e.iop->prev = ~'\n';
4705 e.iop->peekc = 0;
4706 e.iop->xchar = 0;
4707 e.iop->nlcount = 0;
4708
4709 if (fn == filechar || fn == linechar)
4710 e.iop->task = XIO;
4711 else if (fn == (int (*)(struct ioarg *)) gravechar
4712 || fn == (int (*)(struct ioarg *)) qgravechar)
4713 e.iop->task = XGRAVE;
4714 else
4715 e.iop->task = XOTHER;
4716
4717 return;
4718}
4719
4720static struct io *setbase(struct io *ip)
4721{
4722 struct io *xp;
4723
4724 xp = e.iobase;
4725 e.iobase = ip;
4726 return xp;
4727}
4728
4729/*
4730 * Input generating functions
4731 */
4732
4733/*
4734 * Produce the characters of a string, then a newline, then EOF.
4735 */
4736static int nlchar(struct ioarg *ap)
4737{
4738 int c;
4739
4740 if (ap->aword == NULL)
4741 return 0;
4742 if ((c = *ap->aword++) == 0) {
4743 ap->aword = NULL;
4744 return '\n';
4745 }
4746 return c;
4747}
4748
4749/*
4750 * Given a list of words, produce the characters
4751 * in them, with a space after each word.
4752 */
4753static int wdchar(struct ioarg *ap)
4754{
4755 char c;
4756 char **wl;
4757
4758 if ((wl = ap->awordlist) == NULL)
4759 return 0;
4760 if (*wl != NULL) {
4761 if ((c = *(*wl)++) != 0)
4762 return c & 0177;
4763 ap->awordlist++;
4764 return ' ';
4765 }
4766 ap->awordlist = NULL;
4767 return '\n';
4768}
4769
4770/*
4771 * Return the characters of a list of words,
4772 * producing a space between them.
4773 */
4774static int dolchar(struct ioarg *ap)
4775{
4776 char *wp;
4777
4778 if ((wp = *ap->awordlist++) != NULL) {
4779 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4780 return -1;
4781 }
4782 return 0;
4783}
4784
4785static int xxchar(struct ioarg *ap)
4786{
4787 int c;
4788
4789 if (ap->aword == NULL)
4790 return 0;
4791 if ((c = *ap->aword++) == '\0') {
4792 ap->aword = NULL;
4793 return ' ';
4794 }
4795 return c;
4796}
4797
4798/*
4799 * Produce the characters from a single word (string).
4800 */
4801static int strchar(struct ioarg *ap)
4802{
4803 int c;
4804
4805 if (ap->aword == NULL || (c = *ap->aword++) == 0)
4806 return 0;
4807 return c;
4808}
4809
4810/*
4811 * Produce quoted characters from a single word (string).
4812 */
4813static int qstrchar(struct ioarg *ap)
4814{
4815 int c;
4816
4817 if (ap->aword == NULL || (c = *ap->aword++) == 0)
4818 return 0;
4819 return c | QUOTE;
4820}
4821
4822/*
4823 * Return the characters from a file.
4824 */
4825static int filechar(struct ioarg *ap)
4826{
4827 int i;
4828 char c;
4829 struct iobuf *bp = ap->afbuf;
4830
4831 if (ap->afid != AFID_NOBUF) {
4832 if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
4833
4834 if (i)
4835 lseek(ap->afile, ap->afpos, SEEK_SET);
4836
4837 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4838
4839 if (i <= 0) {
4840 closef(ap->afile);
4841 return 0;
4842 }
4843
4844 bp->id = ap->afid;
4845 bp->ebufp = (bp->bufp = bp->buf) + i;
4846 }
4847
4848 ap->afpos++;
4849 return *bp->bufp++ & 0177;
4850 }
4851#ifdef CONFIG_FEATURE_COMMAND_EDITING
4852 if (interactive && isatty(ap->afile)) {
4853 static char mycommand[BUFSIZ];
4854 static int position = 0, size = 0;
4855
4856 while (size == 0 || position >= size) {
4857 cmdedit_read_input(current_prompt, mycommand);
4858 size = strlen(mycommand);
4859 position = 0;
4860 }
4861 c = mycommand[position];
4862 position++;
4863 return c;
4864 } else
4865#endif
4866
4867 {
4868 i = safe_read(ap->afile, &c, sizeof(c));
4869 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
4870 }
4871}
4872
4873/*
4874 * Return the characters from a here temp file.
4875 */
4876static int herechar(struct ioarg *ap)
4877{
4878 char c;
4879
4880
4881 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4882 close(ap->afile);
4883 c = 0;
4884 }
4885 return c;
4886
4887}
4888
4889/*
4890 * Return the characters produced by a process (`...`).
4891 * Quote them if required, and remove any trailing newline characters.
4892 */
4893static int gravechar(struct ioarg *ap, struct io *iop)
4894{
4895 int c;
4896
4897 if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
4898 c = ' ';
4899 return c;
4900}
4901
4902static int qgravechar(struct ioarg *ap, struct io *iop)
4903{
4904 int c;
4905
4906 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
4907
4908 if (iop->xchar) {
4909 if (iop->nlcount) {
4910 iop->nlcount--;
4911 return '\n' | QUOTE;
4912 }
4913 c = iop->xchar;
4914 iop->xchar = 0;
4915 } else if ((c = filechar(ap)) == '\n') {
4916 iop->nlcount = 1;
4917 while ((c = filechar(ap)) == '\n')
4918 iop->nlcount++;
4919 iop->xchar = c;
4920 if (c == 0)
4921 return c;
4922 iop->nlcount--;
4923 c = '\n';
4924 }
4925 return c != 0 ? c | QUOTE : 0;
4926}
4927
4928/*
4929 * Return a single command (usually the first line) from a file.
4930 */
4931static int linechar(struct ioarg *ap)
4932{
4933 int c;
4934
4935 if ((c = filechar(ap)) == '\n') {
4936 if (!multiline) {
4937 closef(ap->afile);
4938 ap->afile = -1; /* illegal value */
4939 }
4940 }
4941 return c;
4942}
4943
4944static void prs(const char *s)
4945{
4946 if (*s)
4947 write(2, s, strlen(s));
4948}
4949
4950static void prn(unsigned u)
4951{
4952 prs(itoa(u));
4953}
4954
4955static void closef(int i)
4956{
4957 if (i > 2)
4958 close(i);
4959}
4960
4961static void closeall(void)
4962{
4963 int u;
4964
4965 for (u = NUFILE; u < NOFILE;)
4966 close(u++);
4967}
4968
4969
4970/*
4971 * remap fd into Shell's fd space
4972 */
4973static int remap(int fd)
4974{
4975 int i;
4976 int map[NOFILE];
4977 int newfd;
4978
4979
4980 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
4981
4982 if (fd < e.iofd) {
4983 for (i = 0; i < NOFILE; i++)
4984 map[i] = 0;
4985
4986 do {
4987 map[fd] = 1;
4988 newfd = dup(fd);
4989 fd = newfd;
4990 } while (fd >= 0 && fd < e.iofd);
4991
4992 for (i = 0; i < NOFILE; i++)
4993 if (map[i])
4994 close(i);
4995
4996 if (fd < 0)
4997 err("too many files open in shell");
4998 }
4999
5000 return fd;
5001}
5002
5003static int openpipe(int *pv)
5004{
5005 int i;
5006
5007 if ((i = pipe(pv)) < 0)
5008 err("can't create pipe - try again");
5009 return i;
5010}
5011
5012static void closepipe(int *pv)
5013{
5014 if (pv != NULL) {
5015 close(*pv++);
5016 close(*pv);
5017 }
5018}
5019
5020/* -------- here.c -------- */
5021
5022/*
5023 * here documents
5024 */
5025
5026static void markhere(char *s, struct ioword *iop)
5027{
5028 struct here *h, *lh;
5029
5030 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
5031
5032 h = (struct here *) space(sizeof(struct here));
5033 if (h == 0)
5034 return;
5035
5036 h->h_tag = evalstr(s, DOSUB);
5037 if (h->h_tag == 0)
5038 return;
5039
5040 h->h_iop = iop;
5041 iop->io_name = 0;
5042 h->h_next = NULL;
5043 if (inhere == 0)
5044 inhere = h;
5045 else
5046 for (lh = inhere; lh != NULL; lh = lh->h_next)
5047 if (lh->h_next == 0) {
5048 lh->h_next = h;
5049 break;
5050 }
5051 iop->io_flag |= IOHERE | IOXHERE;
5052 for (s = h->h_tag; *s; s++)
5053 if (*s & QUOTE) {
5054 iop->io_flag &= ~IOXHERE;
5055 *s &= ~QUOTE;
5056 }
5057 h->h_dosub = iop->io_flag & IOXHERE;
5058}
5059
5060static void gethere(void)
5061{
5062 struct here *h, *hp;
5063
5064 DBGPRINTF7(("GETHERE: enter...\n"));
5065
5066 /* Scan here files first leaving inhere list in place */
5067 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
5068 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
5069
5070 /* Make inhere list active - keep list intact for scraphere */
5071 if (hp != NULL) {
5072 hp->h_next = acthere;
5073 acthere = inhere;
5074 inhere = NULL;
5075 }
5076}
5077
5078static void readhere(char **name, char *s, int ec)
5079{
5080 int tf;
5081 char tname[30] = ".msh_XXXXXX";
5082 int c;
5083 jmp_buf ev;
5084 char myline[LINELIM + 1];
5085 char *thenext;
5086
5087 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
5088
5089 tf = mkstemp(tname);
5090 if (tf < 0)
5091 return;
5092
5093 *name = strsave(tname, areanum);
5094 if (newenv(setjmp(errpt = ev)) != 0)
5095 unlink(tname);
5096 else {
5097 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
5098 e.iobase = e.iop;
5099 for (;;) {
5100 if (interactive && e.iop <= iostack) {
5101#ifdef CONFIG_FEATURE_COMMAND_EDITING
5102 current_prompt = cprompt->value;
5103#else
5104 prs(cprompt->value);
5105#endif
5106 }
5107 thenext = myline;
5108 while ((c = my_getc(ec)) != '\n' && c) {
5109 if (ec == '\'')
5110 c &= ~QUOTE;
5111 if (thenext >= &myline[LINELIM]) {
5112 c = 0;
5113 break;
5114 }
5115 *thenext++ = c;
5116 }
5117 *thenext = 0;
5118 if (strcmp(s, myline) == 0 || c == 0)
5119 break;
5120 *thenext++ = '\n';
5121 write(tf, myline, (int) (thenext - myline));
5122 }
5123 if (c == 0) {
5124 prs("here document `");
5125 prs(s);
5126 err("' unclosed");
5127 }
5128 quitenv();
5129 }
5130 close(tf);
5131}
5132
5133/*
5134 * open here temp file.
5135 * if unquoted here, expand here temp file into second temp file.
5136 */
5137static int herein(char *hname, int xdoll)
5138{
5139 int hf;
5140 int tf;
5141
5142#if __GNUC__
5143 /* Avoid longjmp clobbering */
5144 (void) &tf;
5145#endif
5146 if (hname == NULL)
5147 return -1;
5148
5149 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5150
5151 hf = open(hname, 0);
5152 if (hf < 0)
5153 return -1;
5154
5155 if (xdoll) {
5156 char c;
5157 char tname[30] = ".msh_XXXXXX";
5158 jmp_buf ev;
5159
5160 tf = mkstemp(tname);
5161 if (tf < 0)
5162 return -1;
5163 if (newenv(setjmp(errpt = ev)) == 0) {
5164 PUSHIO(afile, hf, herechar);
5165 setbase(e.iop);
5166 while ((c = subgetc(0, 0)) != 0) {
5167 c &= ~QUOTE;
5168 write(tf, &c, sizeof c);
5169 }
5170 quitenv();
5171 } else
5172 unlink(tname);
5173 close(tf);
5174 tf = open(tname, 0);
5175 unlink(tname);
5176 return tf;
5177 } else
5178 return hf;
5179}
5180
5181static void scraphere(void)
5182{
5183 struct here *h;
5184
5185 DBGPRINTF7(("SCRAPHERE: enter...\n"));
5186
5187 for (h = inhere; h != NULL; h = h->h_next) {
5188 if (h->h_iop && h->h_iop->io_name)
5189 unlink(h->h_iop->io_name);
5190 }
5191 inhere = NULL;
5192}
5193
5194/* unlink here temp files before a freearea(area) */
5195static void freehere(int area)
5196{
5197 struct here *h, *hl;
5198
5199 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5200
5201 hl = NULL;
5202 for (h = acthere; h != NULL; h = h->h_next)
5203 if (getarea((char *) h) >= area) {
5204 if (h->h_iop->io_name != NULL)
5205 unlink(h->h_iop->io_name);
5206 if (hl == NULL)
5207 acthere = h->h_next;
5208 else
5209 hl->h_next = h->h_next;
5210 } else
5211 hl = h;
5212}
5213
5214
5215
5216/*
5217 * Copyright (c) 1987,1997, Prentice Hall
5218 * All rights reserved.
5219 *
5220 * Redistribution and use of the MINIX operating system in source and
5221 * binary forms, with or without modification, are permitted provided
5222 * that the following conditions are met:
5223 *
5224 * Redistributions of source code must retain the above copyright
5225 * notice, this list of conditions and the following disclaimer.
5226 *
5227 * Redistributions in binary form must reproduce the above
5228 * copyright notice, this list of conditions and the following
5229 * disclaimer in the documentation and/or other materials provided
5230 * with the distribution.
5231 *
5232 * Neither the name of Prentice Hall nor the names of the software
5233 * authors or contributors may be used to endorse or promote
5234 * products derived from this software without specific prior
5235 * written permission.
5236 *
5237 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5238 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5239 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5240 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5241 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5242 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5243 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5244 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5245 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5246 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5247 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5248 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5249 *
5250 */