summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2003-07-28 09:56:35 +0000
committerEric Andersen <andersen@codepoet.org>2003-07-28 09:56:35 +0000
commitc470f4477ad7f548ee3ccd3662c83899a5648297 (patch)
treef561378ba4d38e7ed9c6d318c97166a993252582 /shell
parent9b4766116579e1b614b537d72730b7e7f5d7e66c (diff)
downloadbusybox-w32-c470f4477ad7f548ee3ccd3662c83899a5648297.tar.gz
busybox-w32-c470f4477ad7f548ee3ccd3662c83899a5648297.tar.bz2
busybox-w32-c470f4477ad7f548ee3ccd3662c83899a5648297.zip
This is synced from dash-0.4.17 and full ready for insert to new busybox
version: ftp://ftp.simtreas.ru/pub/my/bb/new News: - code is smalest! - support ${var...} expr - used new very strongly steal controlling terminal
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c13785
-rw-r--r--shell/cmdedit.c223
2 files changed, 7203 insertions, 6805 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 1a91f40cd..334dc2235 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -24,27 +24,52 @@
24 * 24 *
25 * This version of ash is adapted from the source in Debian's ash 0.3.8-5 25 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package. 26 * package.
27 * Maintainer Herbert Xu <herbert@debian.org> (C) 1997-2002
27 * 28 *
28 * Modified by Erik Andersen <andersen@codepoet.org> and 29 * Modified by Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
29 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
30 * 30 *
31 * 31 *
32 * Original copyright notice is retained at the end of this file. 32 * Original copyright notice is retained at the end of this file.
33 */ 33 */
34 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
35 46
36/* Enable this to compile in extra debugging noise. When debugging is
37 * on, debugging info will be written to $HOME/trace and a quit signal
38 * will generate a core dump. */
39#undef DEBUG
40 47
41/* These are here to work with glibc -- Don't change these... */
42#undef FNMATCH_BROKEN
43#undef GLOB_BROKEN
44#define IFS_BROKEN 48#define IFS_BROKEN
45 49
46#include <assert.h> 50#define PROFILE 0
51
52#ifdef DEBUG
53#define _GNU_SOURCE
54#endif
55
56#include <sys/types.h>
57#include <sys/cdefs.h>
58#include <sys/ioctl.h>
59#include <sys/param.h>
60#include <sys/resource.h>
61#include <sys/stat.h>
62#include <sys/time.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>
47#include <stddef.h> 71#include <stddef.h>
72#include <assert.h>
48#include <ctype.h> 73#include <ctype.h>
49#include <dirent.h> 74#include <dirent.h>
50#include <errno.h> 75#include <errno.h>
@@ -53,185 +78,122 @@
53#include <paths.h> 78#include <paths.h>
54#include <setjmp.h> 79#include <setjmp.h>
55#include <signal.h> 80#include <signal.h>
56#include <stdarg.h> 81#include <stdint.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <sysexits.h> 82#include <sysexits.h>
61#include <unistd.h>
62#include <sys/stat.h>
63#include <sys/cdefs.h>
64#include <sys/ioctl.h>
65#include <sys/param.h>
66#include <sys/resource.h>
67#include <sys/time.h>
68#include <sys/times.h>
69#include <sys/types.h>
70#include <sys/wait.h>
71#include "busybox.h"
72#include "pwd_.h"
73
74 83
75#if !defined(FNMATCH_BROKEN)
76#include <fnmatch.h> 84#include <fnmatch.h>
77#endif
78#if !defined(GLOB_BROKEN)
79#include <glob.h> 85#include <glob.h>
80#endif 86
87
88
89#include "busybox.h"
90#include "pwd_.h"
81 91
82#ifdef CONFIG_ASH_JOB_CONTROL 92#ifdef CONFIG_ASH_JOB_CONTROL
93#define JOBS 1
94#else
95#undif JOBS
96#endif
97
98#if JOBS
83#include <termios.h> 99#include <termios.h>
84#endif 100#endif
85 101
86#include "cmdedit.h" 102#include "cmdedit.h"
87 103
104#ifdef __GLIBC__
105/* glibc sucks */
106static int *dash_errno;
107#undef errno
108#define errno (*dash_errno)
109#endif
110
88#if defined(__uClinux__) 111#if defined(__uClinux__)
89#error "Do not even bother, ash will not run on uClinux" 112#error "Do not even bother, ash will not run on uClinux"
90#endif 113#endif
91 114
92/* 115#ifdef DEBUG
93 * This file was generated by the mksyntax program. 116#define _DIAGASSERT(assert_expr) assert(assert_expr)
94 */ 117#else
118#define _DIAGASSERT(assert_expr)
119#endif
95 120
96/* Syntax classes */
97#define CWORD 0 /* character is nothing special */
98#define CNL 1 /* newline character */
99#define CBACK 2 /* a backslash character */
100#define CSQUOTE 3 /* single quote */
101#define CDQUOTE 4 /* double quote */
102#define CENDQUOTE 5 /* a terminating quote */
103#define CBQUOTE 6 /* backwards single quote */
104#define CVAR 7 /* a dollar sign */
105#define CENDVAR 8 /* a '}' character */
106#define CLP 9 /* a left paren in arithmetic */
107#define CRP 10 /* a right paren in arithmetic */
108#define CENDFILE 11 /* end of file */
109#define CCTL 12 /* like CWORD, except it must be escaped */
110#define CSPCL 13 /* these terminate a word */
111#define CIGN 14 /* character should be ignored */
112 121
113#define SYNBASE 130 122#ifdef CONFIG_ASH_ALIAS
114#define PEOF -130 123/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
115 124
116#define PEOA -129 125#define ALIASINUSE 1
126#define ALIASDEAD 2
117 127
118#define TEOF 0 128struct alias {
119#define TNL 1 129 struct alias *next;
120#define TREDIR 2 130 char *name;
121#define TWORD 3 131 char *val;
122#define TASSIGN 4 132 int flag;
123#define TSEMI 5 133};
124#define TBACKGND 6
125#define TAND 7
126#define TOR 8
127#define TPIPE 9
128#define TLP 10
129#define TRP 11
130#define TENDCASE 12
131#define TENDBQUOTE 13
132#define TNOT 14
133#define TCASE 15
134#define TDO 16
135#define TDONE 17
136#define TELIF 18
137#define TELSE 19
138#define TESAC 20
139#define TFI 21
140#define TFOR 22
141#define TIF 23
142#define TIN 24
143#define TTHEN 25
144#define TUNTIL 26
145#define TWHILE 27
146#define TBEGIN 28
147#define TEND 29
148 134
135static struct alias *lookupalias(const char *, int);
136static int aliascmd(int, char **);
137static int unaliascmd(int, char **);
138static void rmaliases(void);
139static int unalias(const char *);
140static void printalias(const struct alias *);
141#endif
149 142
143/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
150 144
151/* control characters in argument strings */
152#define CTLESC '\201'
153#define CTLVAR '\202'
154#define CTLENDVAR '\203'
155#define CTLBACKQ '\204'
156#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
157/* CTLBACKQ | CTLQUOTE == '\205' */
158#define CTLARI '\206'
159#define CTLENDARI '\207'
160#define CTLQUOTEMARK '\210'
161 145
146static void setpwd(const char *, int);
147
148/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
162 149
163#define is_digit(c) ((c)>='0' && (c)<='9')
164#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
165#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
166 150
167/* 151/*
168 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise 152 * Types of operations (passed to the errmsg routine).
169 * (assuming ascii char codes, as the original implementation did)
170 */ 153 */
171#define is_special(c) \
172 ( (((unsigned int)c) - 33 < 32) \
173 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
174
175#define digit_val(c) ((c) - '0')
176
177 154
178#define S_DFL 1 /* default signal handling (SIG_DFL) */
179#define S_CATCH 2 /* signal is caught */
180#define S_IGN 3 /* signal is ignored (SIG_IGN) */
181#define S_HARD_IGN 4 /* signal is ignored permenantly */
182#define S_RESET 5 /* temporary - to reset a hard ignored sig */
183 155
156static const char not_found_msg[] = "%s: not found";
184 157
185/* variable substitution byte (follows CTLVAR) */
186#define VSTYPE 0x0f /* type of variable substitution */
187#define VSNUL 0x10 /* colon--treat the empty string as unset */
188#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
189
190/* values of VSTYPE field */
191#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
192#define VSMINUS 0x2 /* ${var-text} */
193#define VSPLUS 0x3 /* ${var+text} */
194#define VSQUESTION 0x4 /* ${var?message} */
195#define VSASSIGN 0x5 /* ${var=text} */
196#define VSTRIMLEFT 0x6 /* ${var#pattern} */
197#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
198#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
199#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
200#define VSLENGTH 0xa /* ${#var} */
201 158
202/* flags passed to redirect */ 159#define E_OPEN "No such file" /* opening a file */
203#define REDIR_PUSH 01 /* save previous values of file descriptors */ 160#define E_CREAT "Directory nonexistent" /* creating a file */
204#define REDIR_BACKQ 02 /* save the command output to pipe */ 161#define E_EXEC not_found_msg+4 /* executing a program */
205 162
206/* 163/*
207 * BSD setjmp saves the signal mask, which violates ANSI C and takes time, 164 * We enclose jmp_buf in a structure so that we can declare pointers to
208 * so we use _setjmp instead. 165 * jump locations. The global variable handler contains the location to
166 * jump to when an exception occurs, and the global variable exception
167 * contains a code identifying the exeception. To implement nested
168 * exception handlers, the user should save the value of handler on entry
169 * to an inner scope, set handler to point to a jmploc structure for the
170 * inner scope, and restore handler on exit from the scope.
209 */ 171 */
210 172
211#if defined(BSD) 173struct jmploc {
212#define setjmp(jmploc) _setjmp(jmploc) 174 jmp_buf loc;
213#define longjmp(jmploc, val) _longjmp(jmploc, val) 175};
214#endif
215 176
216/* 177static struct jmploc *handler;
217 * Most machines require the value returned from malloc to be aligned 178static int exception;
218 * in some way. The following macro will get this right on many machines. 179static volatile int suppressint;
219 */ 180static volatile sig_atomic_t intpending;
220 181
221#ifndef ALIGN 182static int exerrno; /* Last exec error, error for EXEXEC */
222union align {
223 int i;
224 char *cp;
225};
226 183
227#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1)) 184/* exceptions */
228#endif 185#define EXINT 0 /* SIGINT received */
186#define EXERROR 1 /* a generic error */
187#define EXSHELLPROC 2 /* execute a shell procedure */
188#define EXEXEC 3 /* command execution failed */
189#define EXEXIT 4 /* exit the shell */
190#define EXSIG 5 /* trapped signal in wait(1) */
229 191
230#ifdef CONFIG_LOCALE_SUPPORT 192
231#include <locale.h> 193/* do we generate EXSIG events */
232static void change_lc_all(const char *value); 194static int exsig;
233static void change_lc_ctype(const char *value); 195/* last pending signal */
234#endif 196static volatile sig_atomic_t pendingsigs;
235 197
236/* 198/*
237 * These macros allow the user to suspend the handling of interrupt signals 199 * These macros allow the user to suspend the handling of interrupt signals
@@ -240,101 +202,144 @@ static void change_lc_ctype(const char *value);
240 * more fun than worrying about efficiency and portability. :-)) 202 * more fun than worrying about efficiency and portability. :-))
241 */ 203 */
242 204
243static void onint(void); 205#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
244static volatile int suppressint; 206#define INTOFF \
245static volatile int intpending; 207 ({ \
208 suppressint++; \
209 barrier(); \
210 0; \
211 })
212#define SAVEINT(v) ((v) = suppressint)
213#define RESTOREINT(v) \
214 ({ \
215 barrier(); \
216 if ((suppressint = (v)) == 0 && intpending) onint(); \
217 0; \
218 })
219#define EXSIGON() \
220 ({ \
221 exsig++; \
222 barrier(); \
223 if (pendingsigs) \
224 exraise(EXSIG); \
225 0; \
226 })
227/* EXSIG is turned off by evalbltin(). */
228
229
230static void exraise(int) __attribute__((__noreturn__));
231static void onint(void) __attribute__((__noreturn__));
232
233static void error(const char *, ...) __attribute__((__noreturn__));
234static void exerror(int, const char *, ...) __attribute__((__noreturn__));
235
236static void sh_warnx(const char *, ...);
246 237
247#define INTOFF suppressint++ 238#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
248#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE 239static void
249#define INTON { if (--suppressint == 0 && intpending) onint(); } 240inton(void) {
250#define FORCEINTON {suppressint = 0; if (intpending) onint();} 241 if (--suppressint == 0 && intpending) {
251#else 242 onint();
252static void __inton(void); 243 }
253static void forceinton(void); 244}
254 245#define INTON inton()
255#define INTON __inton() 246static void forceinton(void)
247{
248 suppressint = 0;
249 if (intpending)
250 onint();
251}
256#define FORCEINTON forceinton() 252#define FORCEINTON forceinton()
257#endif 253#else
258 254#define INTON \
259#define CLEAR_PENDING_INT intpending = 0 255 ({ \
260#define int_pending() intpending 256 barrier(); \
261 257 if (--suppressint == 0 && intpending) onint(); \
258 0; \
259 })
260#define FORCEINTON \
261 ({ \
262 barrier(); \
263 suppressint = 0; \
264 if (intpending) onint(); \
265 0; \
266 })
267#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
262 268
263typedef void *pointer; 269/*
270 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
271 * so we use _setjmp instead.
272 */
264 273
265#ifndef NULL 274#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
266#define NULL (void *)0 275#define setjmp(jmploc) _setjmp(jmploc)
276#define longjmp(jmploc, val) _longjmp(jmploc, val)
267#endif 277#endif
268 278
269static pointer stalloc(int); 279/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
270static void stunalloc(pointer);
271static void ungrabstackstr(char *, char *);
272static char *growstackstr(void);
273static char *makestrspace(size_t newlen);
274 280
275/* 281struct strlist {
276 * Parse trees for commands are allocated in lifo order, so we use a stack 282 struct strlist *next;
277 * to make this more efficient, and also to avoid all sorts of exception 283 char *text;
278 * handling code to handle interrupts in the middle of a parse. 284};
279 *
280 * The size 504 was chosen because the Ultrix malloc handles that size
281 * well.
282 */
283
284#define MINSIZE 504 /* minimum size of a block */
285 285
286 286
287struct stack_block { 287struct arglist {
288 struct stack_block *prev; 288 struct strlist *list;
289 char space[MINSIZE]; 289 struct strlist **lastp;
290}; 290};
291 291
292static struct stack_block stackbase; 292/*
293static struct stack_block *stackp = &stackbase; 293 * expandarg() flags
294static struct stackmark *markp; 294 */
295static char *stacknxt = stackbase.space; 295#define EXP_FULL 0x1 /* perform word splitting & file globbing */
296static int stacknleft = MINSIZE; 296#define EXP_TILDE 0x2 /* do normal tilde expansion */
297#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
298#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
299#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
300#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
301#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
302#define EXP_WORD 0x80 /* expand word in parameter expansion */
303#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
297 304
298 305
299#define equal(s1, s2) (strcmp(s1, s2) == 0) 306union node;
307static void expandarg(union node *, struct arglist *, int);
308#define rmescapes(p) _rmescapes((p), 0)
309static char *_rmescapes(char *, int);
310static int casematch(union node *, char *);
300 311
301#define stackblock() stacknxt 312#ifdef CONFIG_ASH_MATH_SUPPORT
302#define stackblocksize() stacknleft 313static void expari(int);
303#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() 314#endif
304 315
305#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) 316/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
306#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
307#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
308 317
318static char *commandname; /* currently executing command */
319static struct strlist *cmdenviron; /* environment for builtin command */
320static int exitstatus; /* exit status of last command */
321static int back_exitstatus; /* exit status of backquoted command */
309 322
310#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
311#define STUNPUTC(p) (++sstrnleft, --p)
312#define STTOPC(p) p[-1]
313#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
314#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
315 323
324struct backcmd { /* result of evalbackcmd */
325 int fd; /* file descriptor to read from */
326 char *buf; /* buffer */
327 int nleft; /* number of chars in buffer */
328 struct job *jp; /* job structure for command */
329};
316 330
317#ifdef DEBUG 331/*
318#define TRACE(param) trace param 332 * This file was generated by the mknodes program.
319typedef union node unode; 333 */
320static void trace(const char *, ...);
321static void trargs(char **);
322static void showtree(unode *);
323static void trputc(int);
324static void trputs(const char *);
325static void opentrace(void);
326#else
327#define TRACE(param)
328#endif
329 334
330#define NSEMI 0 335#define NCMD 0
331#define NCMD 1 336#define NPIPE 1
332#define NPIPE 2 337#define NREDIR 2
333#define NREDIR 3 338#define NBACKGND 3
334#define NBACKGND 4 339#define NSUBSHELL 4
335#define NSUBSHELL 5 340#define NAND 5
336#define NAND 6 341#define NOR 6
337#define NOR 7 342#define NSEMI 7
338#define NIF 8 343#define NIF 8
339#define NWHILE 9 344#define NWHILE 9
340#define NUNTIL 10 345#define NUNTIL 10
@@ -344,194 +349,133 @@ static void opentrace(void);
344#define NDEFUN 14 349#define NDEFUN 14
345#define NARG 15 350#define NARG 15
346#define NTO 16 351#define NTO 16
347#define NFROM 17 352#define NCLOBBER 17
348#define NFROMTO 18 353#define NFROM 18
349#define NAPPEND 19 354#define NFROMTO 19
350#define NTOOV 20 355#define NAPPEND 20
351#define NTOFD 21 356#define NTOFD 21
352#define NFROMFD 22 357#define NFROMFD 22
353#define NHERE 23 358#define NHERE 23
354#define NXHERE 24 359#define NXHERE 24
355#define NNOT 25 360#define NNOT 25
356 361
357/*
358 * expandarg() flags
359 */
360#define EXP_FULL 0x1 /* perform word splitting & file globbing */
361#define EXP_TILDE 0x2 /* do normal tilde expansion */
362#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
363#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
364#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
365#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
366
367
368#define NOPTS 16
369
370static char optet_vals[NOPTS];
371
372static const char *const optlist[NOPTS] = {
373 "e" "errexit",
374 "f" "noglob",
375 "I" "ignoreeof",
376 "i" "interactive",
377 "m" "monitor",
378 "n" "noexec",
379 "s" "stdin",
380 "x" "xtrace",
381 "v" "verbose",
382 "V" "vi",
383 "E" "emacs",
384 "C" "noclobber",
385 "a" "allexport",
386 "b" "notify",
387 "u" "nounset",
388 "q" "quietprofile"
389};
390
391#define optent_name(optent) (optent+1)
392#define optent_letter(optent) optent[0]
393#define optent_val(optent) optet_vals[optent]
394
395#define eflag optent_val(0)
396#define fflag optent_val(1)
397#define Iflag optent_val(2)
398#define iflag optent_val(3)
399#define mflag optent_val(4)
400#define nflag optent_val(5)
401#define sflag optent_val(6)
402#define xflag optent_val(7)
403#define vflag optent_val(8)
404#define Vflag optent_val(9)
405#define Eflag optent_val(10)
406#define Cflag optent_val(11)
407#define aflag optent_val(12)
408#define bflag optent_val(13)
409#define uflag optent_val(14)
410#define qflag optent_val(15)
411
412
413/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
414#define FORK_FG 0
415#define FORK_BG 1
416#define FORK_NOJOB 2
417
418
419struct nbinary {
420 int type;
421 union node *ch1;
422 union node *ch2;
423};
424 362
425 363
426struct ncmd { 364struct ncmd {
427 int type; 365 int type;
428 int backgnd; 366 union node *assign;
429 union node *assign; 367 union node *args;
430 union node *args; 368 union node *redirect;
431 union node *redirect;
432}; 369};
433 370
434 371
435struct npipe { 372struct npipe {
436 int type; 373 int type;
437 int backgnd; 374 int backgnd;
438 struct nodelist *cmdlist; 375 struct nodelist *cmdlist;
439}; 376};
440 377
441 378
442struct nredir { 379struct nredir {
443 int type; 380 int type;
444 union node *n; 381 union node *n;
445 union node *redirect; 382 union node *redirect;
383};
384
385
386struct nbinary {
387 int type;
388 union node *ch1;
389 union node *ch2;
446}; 390};
447 391
448 392
449struct nif { 393struct nif {
450 int type; 394 int type;
451 union node *test; 395 union node *test;
452 union node *ifpart; 396 union node *ifpart;
453 union node *elsepart; 397 union node *elsepart;
454}; 398};
455 399
456 400
457struct nfor { 401struct nfor {
458 int type; 402 int type;
459 union node *args; 403 union node *args;
460 union node *body; 404 union node *body;
461 char *var; 405 char *var;
462}; 406};
463 407
464 408
465struct ncase { 409struct ncase {
466 int type; 410 int type;
467 union node *expr; 411 union node *expr;
468 union node *cases; 412 union node *cases;
469}; 413};
470 414
471 415
472struct nclist { 416struct nclist {
473 int type; 417 int type;
474 union node *next; 418 union node *next;
475 union node *pattern; 419 union node *pattern;
476 union node *body; 420 union node *body;
477}; 421};
478 422
479 423
480struct narg { 424struct narg {
481 int type; 425 int type;
482 union node *next; 426 union node *next;
483 char *text; 427 char *text;
484 struct nodelist *backquote; 428 struct nodelist *backquote;
485}; 429};
486 430
487 431
488struct nfile { 432struct nfile {
489 int type; 433 int type;
490 union node *next; 434 union node *next;
491 int fd; 435 int fd;
492 union node *fname; 436 union node *fname;
493 char *expfname; 437 char *expfname;
494}; 438};
495 439
496 440
497struct ndup { 441struct ndup {
498 int type; 442 int type;
499 union node *next; 443 union node *next;
500 int fd; 444 int fd;
501 int dupfd; 445 int dupfd;
502 union node *vname; 446 union node *vname;
503}; 447};
504 448
505 449
506struct nhere { 450struct nhere {
507 int type; 451 int type;
508 union node *next; 452 union node *next;
509 int fd; 453 int fd;
510 union node *doc; 454 union node *doc;
511}; 455};
512 456
513 457
514struct nnot { 458struct nnot {
515 int type; 459 int type;
516 union node *com; 460 union node *com;
517}; 461};
518 462
519 463
520union node { 464union node {
521 int type; 465 int type;
522 struct nbinary nbinary; 466 struct ncmd ncmd;
523 struct ncmd ncmd; 467 struct npipe npipe;
524 struct npipe npipe; 468 struct nredir nredir;
525 struct nredir nredir; 469 struct nbinary nbinary;
526 struct nif nif; 470 struct nif nif;
527 struct nfor nfor; 471 struct nfor nfor;
528 struct ncase ncase; 472 struct ncase ncase;
529 struct nclist nclist; 473 struct nclist nclist;
530 struct narg narg; 474 struct narg narg;
531 struct nfile nfile; 475 struct nfile nfile;
532 struct ndup ndup; 476 struct ndup ndup;
533 struct nhere nhere; 477 struct nhere nhere;
534 struct nnot nnot; 478 struct nnot nnot;
535}; 479};
536 480
537 481
@@ -540,162 +484,316 @@ struct nodelist {
540 union node *n; 484 union node *n;
541}; 485};
542 486
543struct backcmd { /* result of evalbackcmd */
544 int fd; /* file descriptor to read from */
545 char *buf; /* buffer */
546 int nleft; /* number of chars in buffer */
547 struct job *jp; /* job structure for command */
548};
549 487
550struct cmdentry { 488struct funcnode {
551 int cmdtype; 489 int count;
552 union param { 490 union node n;
553 int index;
554 union node *func;
555 const struct builtincmd *cmd;
556 } u;
557}; 491};
558 492
559struct strlist {
560 struct strlist *next;
561 char *text;
562};
563 493
494static void freefunc(struct funcnode *);
495/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
564 496
565struct arglist { 497/* control characters in argument strings */
566 struct strlist *list; 498#define CTL_FIRST '\201' /* first 'special' character */
567 struct strlist **lastp; 499#define CTLESC '\201' /* escape next character */
568}; 500#define CTLVAR '\202' /* variable defn */
501#define CTLENDVAR '\203'
502#define CTLBACKQ '\204'
503#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
504/* CTLBACKQ | CTLQUOTE == '\205' */
505#define CTLARI '\206' /* arithmetic expression */
506#define CTLENDARI '\207'
507#define CTLQUOTEMARK '\210'
508#define CTL_LAST '\210' /* last 'special' character */
569 509
570struct strpush { 510/* variable substitution byte (follows CTLVAR) */
571 struct strpush *prev; /* preceding string on stack */ 511#define VSTYPE 0x0f /* type of variable substitution */
572 char *prevstring; 512#define VSNUL 0x10 /* colon--treat the empty string as unset */
573 int prevnleft; 513#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
574#ifdef CONFIG_ASH_ALIAS
575 struct alias *ap; /* if push was associated with an alias */
576#endif
577 char *string; /* remember the string since it may change */
578};
579 514
580struct parsefile { 515/* values of VSTYPE field */
581 struct parsefile *prev; /* preceding file on stack */ 516#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
582 int linno; /* current line */ 517#define VSMINUS 0x2 /* ${var-text} */
583 int fd; /* file descriptor (or -1 if string) */ 518#define VSPLUS 0x3 /* ${var+text} */
584 int nleft; /* number of chars left in this line */ 519#define VSQUESTION 0x4 /* ${var?message} */
585 int lleft; /* number of chars left in this buffer */ 520#define VSASSIGN 0x5 /* ${var=text} */
586 char *nextc; /* next char in buffer */ 521#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
587 char *buf; /* input buffer */ 522#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
588 struct strpush *strpush; /* for pushing strings at this level */ 523#define VSTRIMLEFT 0x8 /* ${var#pattern} */
589 struct strpush basestrpush; /* so pushing one is fast */ 524#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
590}; 525#define VSLENGTH 0xa /* ${#var} */
591 526
592struct stackmark { 527/* values of checkkwd variable */
593 struct stack_block *stackp; 528#define CHKALIAS 0x1
594 char *stacknxt; 529#define CHKKWD 0x2
595 int stacknleft; 530#define CHKNL 0x4
596 struct stackmark *marknext;
597};
598 531
599struct shparam { 532#define IBUFSIZ (BUFSIZ + 1)
600 int nparam; /* # of positional parameters (without $0) */
601 unsigned char malloc; /* if parameter list dynamically allocated */
602 char **p; /* parameter list */
603 int optind; /* next parameter to be processed by getopts */
604 int optoff; /* used by getopts */
605};
606 533
607/* 534/*
608 * When commands are first encountered, they are entered in a hash table. 535 * NEOF is returned by parsecmd when it encounters an end of file. It
609 * This ensures that a full path search will not have to be done for them 536 * must be distinct from NULL, so we use the address of a variable that
610 * on each invocation. 537 * happens to be handy.
611 *
612 * We should investigate converting to a linear search, even though that
613 * would make the command name "hash" a misnomer.
614 */ 538 */
615#define CMDTABLESIZE 31 /* should be prime */ 539static int plinno = 1; /* input line number */
616#define ARB 1 /* actual size determined at run time */
617 540
541/* number of characters left in input buffer */
542static int parsenleft; /* copy of parsefile->nleft */
543static int parselleft; /* copy of parsefile->lleft */
618 544
545/* next character in input buffer */
546static char *parsenextc; /* copy of parsefile->nextc */
547static struct parsefile basepf; /* top level input file */
548static char basebuf[IBUFSIZ]; /* buffer for top level input file */
549static struct parsefile *parsefile = &basepf; /* current input file */
619 550
620struct tblentry {
621 struct tblentry *next; /* next entry in hash chain */
622 union param param; /* definition of builtin function */
623 short cmdtype; /* index identifying command */
624 char rehash; /* if set, cd done since entry created */
625 char cmdname[ARB]; /* name of command */
626};
627 551
552static int tokpushback; /* last token pushed back */
553#define NEOF ((union node *)&tokpushback)
554static int parsebackquote; /* nonzero if we are inside backquotes */
555static int doprompt; /* if set, prompt the user */
556static int needprompt; /* true if interactive and at start of line */
557static int lasttoken; /* last token read */
558static char *wordtext; /* text of last word returned by readtoken */
559static int checkkwd;
560static struct nodelist *backquotelist;
561static union node *redirnode;
562static struct heredoc *heredoc;
563static int quoteflag; /* set if (part of) last token was quoted */
564static int startlinno; /* line # where last token started */
628 565
629static struct tblentry *cmdtable[CMDTABLESIZE]; 566static union node *parsecmd(int);
630static int builtinloc = -1; /* index in path of %builtin, or -1 */ 567static void fixredir(union node *, const char *, int);
631static int exerrno = 0; /* Last exec error */ 568static const char *const *findkwd(const char *);
569static char *endofname(const char *);
632 570
571/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
633 572
634static void tryexec(char *, char **, char **); 573typedef void *pointer;
635static void printentry(struct tblentry *, int);
636static void clearcmdentry(int);
637static struct tblentry *cmdlookup(const char *, int);
638static void delete_cmd_entry(void);
639static int path_change(const char *, int *);
640 574
575static char nullstr[1]; /* zero length string */
576static const char spcstr[] = " ";
577static const char snlfmt[] = "%s\n";
578static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
579static const char illnum[] = "Illegal number: %s";
580static const char homestr[] = "HOME";
641 581
642static void flushall(void); 582#ifdef DEBUG
643static void out2fmt(const char *, ...) 583#define TRACE(param) trace param
644 __attribute__ ((__format__(__printf__, 1, 2))); 584#define TRACEV(param) tracev param
645static int xwrite(int, const char *, int); 585#else
586#define TRACE(param)
587#define TRACEV(param)
588#endif
646 589
647static inline void outstr(const char *p, FILE * file) 590#if defined(__GNUC__) && __GNUC__ < 3
648{ 591#define va_copy __va_copy
649 fputs(p, file); 592#endif
650} 593
651static void out1str(const char *p) 594#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
652{ 595#define __builtin_expect(x, expected_value) (x)
653 outstr(p, stdout); 596#endif
654} 597
655static void out2str(const char *p) 598#define likely(x) __builtin_expect((x),1)
599#define unlikely(x) __builtin_expect((x),0)
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)
656{ 667{
657 outstr(p, stderr); 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;
658} 675}
659 676
660#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE 677/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
661#define out2c(c) putc((c), stderr) 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
662#else 718#else
663static void out2c(int c) 719#define SYNBASE 129
664{ 720#define PEOF -129
665 putc(c, stderr); 721#define PEOA_OR_PEOF PEOF
666}
667#endif 722#endif
668 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/*
729 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
730 * (assuming ascii char codes, as the original implementation did)
731 */
732#define is_special(c) \
733 ( (((unsigned int)c) - 33 < 32) \
734 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
735
736#define digit_val(c) ((c) - '0')
737
738/*
739 * This file was generated by the mksyntax program.
740 */
669 741
670#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE 742#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
671#define USE_SIT_FUNCTION 743#define USE_SIT_FUNCTION
672#endif 744#endif
673 745
674/* number syntax index */ 746/* number syntax index */
675#define BASESYNTAX 0 /* not in quotes */ 747#define BASESYNTAX 0 /* not in quotes */
676#define DQSYNTAX 1 /* in double quotes */ 748#define DQSYNTAX 1 /* in double quotes */
677#define SQSYNTAX 2 /* in single quotes */ 749#define SQSYNTAX 2 /* in single quotes */
678#define ARISYNTAX 3 /* in arithmetic */ 750#define ARISYNTAX 3 /* in arithmetic */
679 751
752#ifdef CONFIG_ASH_MATH_SUPPORT
680static const char S_I_T[][4] = { 753static const char S_I_T[][4] = {
681 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */ 754#ifdef CONFIG_ASH_ALIAS
682 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */ 755 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
683 {CNL, CNL, CNL, CNL}, /* 2, \n */ 756#endif
684 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */ 757 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
685 {CDQUOTE, CENDQUOTE, CWORD, CDQUOTE}, /* 4, '"' */ 758 {CNL, CNL, CNL, CNL}, /* 2, \n */
686 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */ 759 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
687 {CSQUOTE, CWORD, CENDQUOTE, CSQUOTE}, /* 6, "'" */ 760 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
688 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */ 761 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
689 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */ 762 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
690 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */ 763 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
691 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */ 764 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
692 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */ 765 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
766 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
767 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
693#ifndef USE_SIT_FUNCTION 768#ifndef USE_SIT_FUNCTION
694 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */ 769 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
695 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */ 770 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
696 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */ 771 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
697#endif 772#endif
698}; 773};
774#else
775static const char S_I_T[][3] = {
776#ifdef CONFIG_ASH_ALIAS
777 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
778#endif
779 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
780 {CNL, CNL, CNL}, /* 2, \n */
781 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
782 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
783 {CVAR, CVAR, CWORD}, /* 5, $ */
784 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
785 {CSPCL, CWORD, CWORD}, /* 7, ( */
786 {CSPCL, CWORD, CWORD}, /* 8, ) */
787 {CBACK, CBACK, CCTL}, /* 9, \ */
788 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
789 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
790#ifndef USE_SIT_FUNCTION
791 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
792 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
793 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
794#endif
795};
796#endif /* CONFIG_ASH_MATH_SUPPORT */
699 797
700#ifdef USE_SIT_FUNCTION 798#ifdef USE_SIT_FUNCTION
701 799
@@ -704,41 +802,54 @@ static const char S_I_T[][4] = {
704static int SIT(int c, int syntax) 802static int SIT(int c, int syntax)
705{ 803{
706 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; 804 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
805#ifdef CONFIG_ASH_ALIAS
707 static const char syntax_index_table[] = { 806 static const char syntax_index_table[] = {
708 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ 807 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
709 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ 808 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
710 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */ 809 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
711 11, 3 810 11, 3 /* "}~" */
712 }; /* "}~" */ 811 };
812#else
813 static const char syntax_index_table[] = {
814 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
815 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
816 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
817 10, 2 /* "}~" */
818 };
819#endif
713 const char *s; 820 const char *s;
714 int indx; 821 int indx;
715 822
716 if (c == PEOF) /* 2^8+2 */ 823 if (c == PEOF) /* 2^8+2 */
717 return CENDFILE; 824 return CENDFILE;
718 if (c == PEOA) /* 2^8+1 */ 825#ifdef CONFIG_ASH_ALIAS
826 if (c == PEOA) /* 2^8+1 */
719 indx = 0; 827 indx = 0;
720 else if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK)) 828 else
721 return CCTL; 829#endif
830 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
831 return CCTL;
722 else { 832 else {
723 s = strchr(spec_symbls, c); 833 s = strchr(spec_symbls, c);
724 if (s == 0) 834 if (s == 0 || *s == 0)
725 return CWORD; 835 return CWORD;
726 indx = syntax_index_table[(s - spec_symbls)]; 836 indx = syntax_index_table[(s - spec_symbls)];
727 } 837 }
728 return S_I_T[indx][syntax]; 838 return S_I_T[indx][syntax];
729} 839}
730 840
731#else /* USE_SIT_FUNCTION */ 841#else /* USE_SIT_FUNCTION */
732 842
733#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax] 843#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
734 844
845#ifdef CONFIG_ASH_ALIAS
735#define CSPCL_CIGN_CIGN_CIGN 0 846#define CSPCL_CIGN_CIGN_CIGN 0
736#define CSPCL_CWORD_CWORD_CWORD 1 847#define CSPCL_CWORD_CWORD_CWORD 1
737#define CNL_CNL_CNL_CNL 2 848#define CNL_CNL_CNL_CNL 2
738#define CWORD_CCTL_CCTL_CWORD 3 849#define CWORD_CCTL_CCTL_CWORD 3
739#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4 850#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
740#define CVAR_CVAR_CWORD_CVAR 5 851#define CVAR_CVAR_CWORD_CVAR 5
741#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6 852#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
742#define CSPCL_CWORD_CWORD_CLP 7 853#define CSPCL_CWORD_CWORD_CLP 7
743#define CSPCL_CWORD_CWORD_CRP 8 854#define CSPCL_CWORD_CWORD_CRP 8
744#define CBACK_CBACK_CCTL_CBACK 9 855#define CBACK_CBACK_CCTL_CBACK 9
@@ -747,22 +858,38 @@ static int SIT(int c, int syntax)
747#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12 858#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
748#define CWORD_CWORD_CWORD_CWORD 13 859#define CWORD_CWORD_CWORD_CWORD 13
749#define CCTL_CCTL_CCTL_CCTL 14 860#define CCTL_CCTL_CCTL_CCTL 14
861#else
862#define CSPCL_CWORD_CWORD_CWORD 0
863#define CNL_CNL_CNL_CNL 1
864#define CWORD_CCTL_CCTL_CWORD 2
865#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
866#define CVAR_CVAR_CWORD_CVAR 4
867#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
868#define CSPCL_CWORD_CWORD_CLP 6
869#define CSPCL_CWORD_CWORD_CRP 7
870#define CBACK_CBACK_CCTL_CBACK 8
871#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
872#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
873#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
874#define CWORD_CWORD_CWORD_CWORD 12
875#define CCTL_CCTL_CCTL_CCTL 13
876#endif
750 877
751static const char syntax_index_table[258] = { 878static const char syntax_index_table[258] = {
752 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */ 879 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
753 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, 880 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
754 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN, 881#ifdef CONFIG_ASH_ALIAS
755 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD, 882 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
756 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, 883#endif
757 /* CTLQUOTEMARK */ 884 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
758 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL, 885 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
759 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL, 886 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
760 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL, 887 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
761 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL, 888 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
762 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL, 889 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
763 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL, 890 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
764 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, 891 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
765 /* CTLESC */ 892 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
766 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD, 893 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
767 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD, 894 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
768 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD, 895 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
@@ -916,12 +1043,12 @@ static const char syntax_index_table[258] = {
916 /* 161 31 */ CWORD_CWORD_CWORD_CWORD, 1043 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
917 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD, 1044 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
918 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD, 1045 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
919 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE, 1046 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
920 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD, 1047 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
921 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR, 1048 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
922 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD, 1049 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
923 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD, 1050 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
924 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE, 1051 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
925 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP, 1052 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
926 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP, 1053 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
927 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD, 1054 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
@@ -1012,90 +1139,66 @@ static const char syntax_index_table[258] = {
1012 /* 257 127 */ CWORD_CWORD_CWORD_CWORD, 1139 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1013}; 1140};
1014 1141
1015#endif /* USE_SIT_FUNCTION */ 1142#endif /* USE_SIT_FUNCTION */
1016 1143
1144/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
1017 1145
1018/* first char is indicating which tokens mark the end of a list */
1019static const char *const tokname_array[] = {
1020 "\1end of file",
1021 "\0newline",
1022 "\0redirection",
1023 "\0word",
1024 "\0assignment",
1025 "\0;",
1026 "\0&",
1027 "\0&&",
1028 "\0||",
1029 "\0|",
1030 "\0(",
1031 "\1)",
1032 "\1;;",
1033 "\1`",
1034#define KWDOFFSET 14
1035 /* the following are keywords */
1036 "\0!",
1037 "\0case",
1038 "\1do",
1039 "\1done",
1040 "\1elif",
1041 "\1else",
1042 "\1esac",
1043 "\1fi",
1044 "\0for",
1045 "\0if",
1046 "\0in",
1047 "\1then",
1048 "\0until",
1049 "\0while",
1050 "\0{",
1051 "\1}",
1052};
1053 1146
1054static const char *tokname(int tok) 1147#define ATABSIZE 39
1055{
1056 static char buf[16];
1057
1058 if (tok >= TSEMI)
1059 buf[0] = '"';
1060 sprintf(buf + (tok >= TSEMI), "%s%c",
1061 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
1062 return buf;
1063}
1064
1065static int plinno = 1; /* input line number */
1066
1067static int parselleft; /* copy of parsefile->lleft */
1068
1069static struct parsefile basepf; /* top level input file */
1070static char basebuf[BUFSIZ]; /* buffer for top level input file */
1071static struct parsefile *parsefile = &basepf; /* current input file */
1072 1148
1073/* 1149static int funcblocksize; /* size of structures in function */
1074 * NEOF is returned by parsecmd when it encounters an end of file. It 1150static int funcstringsize; /* size of strings in node */
1075 * must be distinct from NULL, so we use the address of a variable that 1151static pointer funcblock; /* block to allocate function from */
1076 * happens to be handy. 1152static char *funcstring; /* block to allocate strings from */
1077 */ 1153
1154static const short nodesize[26] = {
1155 SHELL_ALIGN(sizeof (struct ncmd)),
1156 SHELL_ALIGN(sizeof (struct npipe)),
1157 SHELL_ALIGN(sizeof (struct nredir)),
1158 SHELL_ALIGN(sizeof (struct nredir)),
1159 SHELL_ALIGN(sizeof (struct nredir)),
1160 SHELL_ALIGN(sizeof (struct nbinary)),
1161 SHELL_ALIGN(sizeof (struct nbinary)),
1162 SHELL_ALIGN(sizeof (struct nbinary)),
1163 SHELL_ALIGN(sizeof (struct nif)),
1164 SHELL_ALIGN(sizeof (struct nbinary)),
1165 SHELL_ALIGN(sizeof (struct nbinary)),
1166 SHELL_ALIGN(sizeof (struct nfor)),
1167 SHELL_ALIGN(sizeof (struct ncase)),
1168 SHELL_ALIGN(sizeof (struct nclist)),
1169 SHELL_ALIGN(sizeof (struct narg)),
1170 SHELL_ALIGN(sizeof (struct narg)),
1171 SHELL_ALIGN(sizeof (struct nfile)),
1172 SHELL_ALIGN(sizeof (struct nfile)),
1173 SHELL_ALIGN(sizeof (struct nfile)),
1174 SHELL_ALIGN(sizeof (struct nfile)),
1175 SHELL_ALIGN(sizeof (struct nfile)),
1176 SHELL_ALIGN(sizeof (struct ndup)),
1177 SHELL_ALIGN(sizeof (struct ndup)),
1178 SHELL_ALIGN(sizeof (struct nhere)),
1179 SHELL_ALIGN(sizeof (struct nhere)),
1180 SHELL_ALIGN(sizeof (struct nnot)),
1181};
1078 1182
1079static int tokpushback; /* last token pushed back */
1080 1183
1081#define NEOF ((union node *)&tokpushback) 1184static void calcsize(union node *);
1082static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 1185static void sizenodelist(struct nodelist *);
1186static union node *copynode(union node *);
1187static struct nodelist *copynodelist(struct nodelist *);
1188static char *nodesavestr(char *);
1083 1189
1084 1190
1085static void error(const char *, ...) __attribute__ ((__noreturn__));
1086static void exerror(int, const char *, ...) __attribute__ ((__noreturn__));
1087static void shellexec(char **, char **, const char *, int)
1088 __attribute__ ((noreturn));
1089static void exitshell(int) __attribute__ ((noreturn));
1090 1191
1091static int goodname(const char *); 1192static void evalstring(char *, int);
1092static void ignoresig(int); 1193union node; /* BLETCH for ansi C */
1093static void onsig(int); 1194static void evaltree(union node *, int);
1094static void dotrap(void); 1195static void evalbackcmd(union node *, struct backcmd *);
1095static int decode_signal(const char *, int);
1096 1196
1097static void setparam(char **); 1197/* in_function returns nonzero if we are currently evaluating a function */
1098static void freeparam(volatile struct shparam *); 1198#define in_function() funcnest
1199static int evalskip; /* set if we are skipping commands */
1200static int skipcount; /* number of levels to skip */
1201static int funcnest; /* depth of function calls */
1099 1202
1100/* reasons for skipping commands (see comment on breakcmd routine) */ 1203/* reasons for skipping commands (see comment on breakcmd routine) */
1101#define SKIPBREAK 1 1204#define SKIPBREAK 1
@@ -1103,160 +1206,330 @@ static void freeparam(volatile struct shparam *);
1103#define SKIPFUNC 3 1206#define SKIPFUNC 3
1104#define SKIPFILE 4 1207#define SKIPFILE 4
1105 1208
1209/*
1210 * This file was generated by the mkbuiltins program.
1211 */
1212
1213#ifdef JOBS
1214static int bgcmd(int, char **);
1215#endif
1216static int breakcmd(int, char **);
1217static int cdcmd(int, char **);
1218#ifdef CONFIG_ASH_CMDCMD
1219static int commandcmd(int, char **);
1220#endif
1221static int dotcmd(int, char **);
1222static int evalcmd(int, char **);
1223static int execcmd(int, char **);
1224static int exitcmd(int, char **);
1225#ifdef CONFIG_ASH_MATH_SUPPORT
1226static int expcmd(int, char **);
1227#endif
1228static int exportcmd(int, char **);
1229static int falsecmd(int, char **);
1230#ifdef JOBS
1231static int fgcmd(int, char **);
1232#endif
1233#ifdef CONFIG_ASH_GETOPTS
1234static int getoptscmd(int, char **);
1235#endif
1236static int hashcmd(int, char **);
1237#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1238static int helpcmd(int argc, char **argv);
1239#endif
1240#ifdef JOBS
1241static int jobscmd(int, char **);
1242#endif
1243static int localcmd(int, char **);
1244static int pwdcmd(int, char **);
1245static int readcmd(int, char **);
1246static int returncmd(int, char **);
1247static int setcmd(int, char **);
1248static int shiftcmd(int, char **);
1249static int timescmd(int, char **);
1250static int trapcmd(int, char **);
1251static int truecmd(int, char **);
1252static int typecmd(int, char **);
1253static int umaskcmd(int, char **);
1254static int unsetcmd(int, char **);
1255static int waitcmd(int, char **);
1256static int ulimitcmd(int, char **);
1257#ifdef JOBS
1258static int killcmd(int, char **);
1259#endif
1260
1261/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1262
1263#ifdef CONFIG_ASH_MAIL
1264static void chkmail(void);
1265static void changemail(const char *);
1266#endif
1267
1268/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1269
1106/* values of cmdtype */ 1270/* values of cmdtype */
1107#define CMDUNKNOWN -1 /* no entry in table for command */ 1271#define CMDUNKNOWN -1 /* no entry in table for command */
1108#define CMDNORMAL 0 /* command is an executable program */ 1272#define CMDNORMAL 0 /* command is an executable program */
1109#define CMDBUILTIN 1 /* command is a shell builtin */ 1273#define CMDFUNCTION 1 /* command is a shell function */
1110#define CMDFUNCTION 2 /* command is a shell function */ 1274#define CMDBUILTIN 2 /* command is a shell builtin */
1111 1275
1112#define DO_ERR 1 /* find_command prints errors */ 1276struct builtincmd {
1113#define DO_ABS 2 /* find_command checks absolute paths */ 1277 const char *name;
1114#define DO_NOFUN 4 /* find_command ignores functions */ 1278 int (*builtin)(int, char **);
1115#define DO_BRUTE 8 /* find_command ignores hash table */ 1279 /* unsigned flags; */
1280};
1116 1281
1117/* 1282#ifdef CONFIG_ASH_CMDCMD
1118 * Shell variables. 1283# ifdef JOBS
1119 */ 1284# ifdef CONFIG_ASH_ALIAS
1285# define COMMANDCMD (builtincmd + 7)
1286# define EXECCMD (builtincmd + 10)
1287# else
1288# define COMMANDCMD (builtincmd + 6)
1289# define EXECCMD (builtincmd + 9)
1290# endif
1291# else /* ! JOBS */
1292# ifdef CONFIG_ASH_ALIAS
1293# define COMMANDCMD (builtincmd + 6)
1294# define EXECCMD (builtincmd + 9)
1295# else
1296# define COMMANDCMD (builtincmd + 5)
1297# define EXECCMD (builtincmd + 8)
1298# endif
1299# endif /* JOBS */
1300#else /* ! CONFIG_ASH_CMDCMD */
1301# ifdef JOBS
1302# ifdef CONFIG_ASH_ALIAS
1303# define EXECCMD (builtincmd + 9)
1304# else
1305# define EXECCMD (builtincmd + 8)
1306# endif
1307# else /* ! JOBS */
1308# ifdef CONFIG_ASH_ALIAS
1309# define EXECCMD (builtincmd + 8)
1310# else
1311# define EXECCMD (builtincmd + 7)
1312# endif
1313# endif /* JOBS */
1314#endif /* CONFIG_ASH_CMDCMD */
1120 1315
1121/* flags */ 1316#define BUILTIN_NOSPEC "0"
1122#define VEXPORT 0x01 /* variable is exported */ 1317#define BUILTIN_SPECIAL "1"
1123#define VREADONLY 0x02 /* variable cannot be modified */ 1318#define BUILTIN_REGULAR "2"
1124#define VSTRFIXED 0x04 /* variable struct is staticly allocated */ 1319#define BUILTIN_SPEC_REG "3"
1125#define VTEXTFIXED 0x08 /* text is staticly allocated */ 1320#define BUILTIN_ASSIGN "4"
1126#define VSTACK 0x10 /* text is allocated on the stack */ 1321#define BUILTIN_SPEC_ASSG "5"
1127#define VUNSET 0x20 /* the variable is not set */ 1322#define BUILTIN_REG_ASSG "6"
1128#define VNOFUNC 0x40 /* don't call the callback function */ 1323#define BUILTIN_SPEC_REG_ASSG "7"
1129 1324
1325#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1326#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1130 1327
1131struct var { 1328static const struct builtincmd builtincmd[] = {
1132 struct var *next; /* next entry in hash list */ 1329 { BUILTIN_SPEC_REG ".", dotcmd },
1133 int flags; /* flags are defined above */ 1330 { BUILTIN_SPEC_REG ":", truecmd },
1134 char *text; /* name=value */ 1331#ifdef CONFIG_ASH_ALIAS
1135 void (*func) (const char *); 1332 { BUILTIN_REG_ASSG "alias", aliascmd },
1136 /* function to be called when */ 1333#endif
1137 /* the variable gets set/unset */ 1334#ifdef JOBS
1335 { BUILTIN_REGULAR "bg", bgcmd },
1336#endif
1337 { BUILTIN_SPEC_REG "break", breakcmd },
1338 { BUILTIN_REGULAR "cd", cdcmd },
1339 { BUILTIN_NOSPEC "chdir", cdcmd },
1340#ifdef CONFIG_ASH_CMDCMD
1341 { BUILTIN_REGULAR "command", commandcmd },
1342#endif
1343 { BUILTIN_SPEC_REG "continue", breakcmd },
1344 { BUILTIN_SPEC_REG "eval", evalcmd },
1345 { BUILTIN_SPEC_REG "exec", execcmd },
1346 { BUILTIN_SPEC_REG "exit", exitcmd },
1347#ifdef CONFIG_ASH_MATH_SUPPORT
1348 { BUILTIN_NOSPEC "exp", expcmd },
1349#endif
1350 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1351 { BUILTIN_REGULAR "false", falsecmd },
1352#ifdef JOBS
1353 { BUILTIN_REGULAR "fg", fgcmd },
1354#endif
1355#ifdef CONFIG_ASH_GETOPTS
1356 { BUILTIN_REGULAR "getopts", getoptscmd },
1357#endif
1358 { BUILTIN_NOSPEC "hash", hashcmd },
1359#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1360 { BUILTIN_NOSPEC "help", helpcmd },
1361#endif
1362#ifdef JOBS
1363 { BUILTIN_REGULAR "jobs", jobscmd },
1364 { BUILTIN_REGULAR "kill", killcmd },
1365#endif
1366#ifdef CONFIG_ASH_MATH_SUPPORT
1367 { BUILTIN_NOSPEC "let", expcmd },
1368#endif
1369 { BUILTIN_ASSIGN "local", localcmd },
1370 { BUILTIN_NOSPEC "pwd", pwdcmd },
1371 { BUILTIN_REGULAR "read", readcmd },
1372 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1373 { BUILTIN_SPEC_REG "return", returncmd },
1374 { BUILTIN_SPEC_REG "set", setcmd },
1375 { BUILTIN_SPEC_REG "shift", shiftcmd },
1376 { BUILTIN_SPEC_REG "times", timescmd },
1377 { BUILTIN_SPEC_REG "trap", trapcmd },
1378 { BUILTIN_REGULAR "true", truecmd },
1379 { BUILTIN_NOSPEC "type", typecmd },
1380 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1381 { BUILTIN_REGULAR "umask", umaskcmd },
1382#ifdef CONFIG_ASH_ALIAS
1383 { BUILTIN_REGULAR "unalias", unaliascmd },
1384#endif
1385 { BUILTIN_SPEC_REG "unset", unsetcmd },
1386 { BUILTIN_REGULAR "wait", waitcmd },
1138}; 1387};
1139 1388
1140struct localvar { 1389#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1141 struct localvar *next; /* next local variable in list */ 1390
1142 struct var *vp; /* the variable that was made local */ 1391
1143 int flags; /* saved flags */ 1392
1144 char *text; /* saved text */ 1393struct cmdentry {
1394 int cmdtype;
1395 union param {
1396 int index;
1397 const struct builtincmd *cmd;
1398 struct funcnode *func;
1399 } u;
1145}; 1400};
1146 1401
1147 1402
1148#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) 1403/* action to find_command() */
1149#define rmescapes(p) _rmescapes((p), 0) 1404#define DO_ERR 0x01 /* prints errors */
1150static char *_rmescapes(char *, int); 1405#define DO_ABS 0x02 /* checks absolute paths */
1151#else 1406#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1152static void rmescapes(char *); 1407#define DO_ALTPATH 0x08 /* using alternate path */
1408#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1409
1410static const char *pathopt; /* set by padvance */
1411
1412static void shellexec(char **, const char *, int)
1413 __attribute__((__noreturn__));
1414static char *padvance(const char **, const char *);
1415static void find_command(char *, struct cmdentry *, int, const char *);
1416static struct builtincmd *find_builtin(const char *);
1417static void hashcd(void);
1418static void changepath(const char *);
1419static void defun(char *, union node *);
1420static void unsetfunc(const char *);
1421
1422#ifdef CONFIG_ASH_MATH_SUPPORT
1423/* From arith.y */
1424static int dash_arith(const char *);
1153#endif 1425#endif
1154 1426
1155static int casematch(union node *, const char *); 1427/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1156static void clearredir(void);
1157static void popstring(void);
1158static void readcmdfile(const char *);
1159 1428
1160static int number(const char *); 1429static void reset(void);
1161static int is_number(const char *, int *num);
1162static char *single_quote(const char *);
1163static int nextopt(const char *);
1164 1430
1165static void redirect(union node *, int); 1431/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1166static void popredir(void);
1167static int dup_as_newfd(int, int);
1168 1432
1169static void changepath(const char *newval); 1433/*
1170static void getoptsreset(const char *value); 1434 * Shell variables.
1435 */
1171 1436
1437/* flags */
1438#define VEXPORT 0x01 /* variable is exported */
1439#define VREADONLY 0x02 /* variable cannot be modified */
1440#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1441#define VTEXTFIXED 0x08 /* text is statically allocated */
1442#define VSTACK 0x10 /* text is allocated on the stack */
1443#define VUNSET 0x20 /* the variable is not set */
1444#define VNOFUNC 0x40 /* don't call the callback function */
1445#define VNOSET 0x80 /* do not set variable - just readonly test */
1446#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1172 1447
1173static int parsenleft; /* copy of parsefile->nleft */
1174static char *parsenextc; /* copy of parsefile->nextc */
1175static int rootpid; /* pid of main shell */
1176static int rootshell; /* true if we aren't a child of the main shell */
1177 1448
1178static const char spcstr[] = " "; 1449struct var {
1179static const char snlfmt[] = "%s\n"; 1450 struct var *next; /* next entry in hash list */
1451 int flags; /* flags are defined above */
1452 const char *text; /* name=value */
1453 void (*func)(const char *);
1454 /* function to be called when */
1455 /* the variable gets set/unset */
1456};
1457
1458struct localvar {
1459 struct localvar *next; /* next local variable in list */
1460 struct var *vp; /* the variable that was made local */
1461 int flags; /* saved flags */
1462 const char *text; /* saved text */
1463};
1180 1464
1181static int sstrnleft;
1182static int herefd = -1;
1183 1465
1184static struct localvar *localvars; 1466static struct localvar *localvars;
1185 1467
1186static struct var vifs; 1468/*
1187static struct var vmail; 1469 * Shell variables.
1188static struct var vmpath; 1470 */
1189static struct var vpath;
1190static struct var vps1;
1191static struct var vps2;
1192static struct var voptind;
1193 1471
1194#ifdef CONFIG_LOCALE_SUPPORT 1472#ifdef CONFIG_ASH_GETOPTS
1195static struct var vlc_all; 1473static void getoptsreset(const char *);
1196static struct var vlc_ctype;
1197#endif 1474#endif
1198 1475
1199#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 1476#ifdef CONFIG_LOCALE_SUPPORT
1200static struct var vhistfile; 1477#include <locale.h>
1478static void change_lc_all(const char *value);
1479static void change_lc_ctype(const char *value);
1201#endif 1480#endif
1202 1481
1203struct varinit { 1482#define VTABSIZE 39
1204 struct var *var;
1205 int flags;
1206 const char *text;
1207 void (*func) (const char *);
1208};
1209 1483
1210static const char defpathvar[] = 1484static const char defpathvar[] =
1211 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; 1485 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1212#define defpath (defpathvar + 5)
1213
1214#ifdef IFS_BROKEN 1486#ifdef IFS_BROKEN
1215static const char defifsvar[] = "IFS= \t\n"; 1487static const char defifsvar[] = "IFS= \t\n";
1216
1217#define defifs (defifsvar + 4)
1218#else
1219static const char defifs[] = " \t\n";
1220#endif 1488#endif
1489static const char defifs[] = " \t\n";
1221 1490
1222static const struct varinit varinit[] = { 1491static struct var varinit[] = {
1223#ifdef IFS_BROKEN 1492#ifdef IFS_BROKEN
1224 {&vifs, VSTRFIXED | VTEXTFIXED, defifsvar, 1493 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1225#else 1494#else
1226 {&vifs, VSTRFIXED | VTEXTFIXED | VUNSET, "IFS=", 1495 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1227#endif 1496#endif
1228 NULL}, 1497
1229 {&vmail, VSTRFIXED | VTEXTFIXED | VUNSET, "MAIL=", 1498#ifdef CONFIG_ASH_MAIL
1230 NULL}, 1499 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1231 {&vmpath, VSTRFIXED | VTEXTFIXED | VUNSET, "MAILPATH=", 1500 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1232 NULL}, 1501#endif
1233 {&vpath, VSTRFIXED | VTEXTFIXED, defpathvar, 1502
1234 changepath}, 1503 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1235#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT) 1504 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1236 {&vps1, VSTRFIXED | VTEXTFIXED, "PS1=\\w \\$ ", 1505 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1237 NULL}, 1506 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1238#endif /* else vps1 depends on uid */ 1507#ifdef CONFIG_ASH_GETOPTS
1239 {&vps2, VSTRFIXED | VTEXTFIXED, "PS2=> ", 1508 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1240 NULL}, 1509#endif
1241 {&voptind, VSTRFIXED | VTEXTFIXED, "OPTIND=1",
1242 getoptsreset},
1243#ifdef CONFIG_LOCALE_SUPPORT 1510#ifdef CONFIG_LOCALE_SUPPORT
1244 {&vlc_all, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", 1511 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
1245 change_lc_all}, 1512 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
1246 {&vlc_ctype, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=",
1247 change_lc_ctype},
1248#endif 1513#endif
1249#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 1514#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1250 {&vhistfile, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", 1515 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
1251 NULL},
1252#endif 1516#endif
1253 {NULL, 0, NULL,
1254 NULL}
1255}; 1517};
1256 1518
1257#define VTABSIZE 39 1519#define vifs varinit[0]
1520#ifdef CONFIG_ASH_MAIL
1521#define vmail (&vifs)[1]
1522#define vmpath (&vmail)[1]
1523#else
1524#define vmpath vifs
1525#endif
1526#define vpath (&vmpath)[1]
1527#define vps1 (&vpath)[1]
1528#define vps2 (&vps1)[1]
1529#define vps4 (&vps2)[1]
1530#define voptind (&vps4)[1]
1258 1531
1259static struct var *vartab[VTABSIZE]; 1532#define defpath (defpathvar + 5)
1260 1533
1261/* 1534/*
1262 * The following macros access the values of the above variables. 1535 * The following macros access the values of the above variables.
@@ -1271,54 +1544,533 @@ static struct var *vartab[VTABSIZE];
1271#define pathval() (vpath.text + 5) 1544#define pathval() (vpath.text + 5)
1272#define ps1val() (vps1.text + 4) 1545#define ps1val() (vps1.text + 4)
1273#define ps2val() (vps2.text + 4) 1546#define ps2val() (vps2.text + 4)
1547#define ps4val() (vps4.text + 4)
1274#define optindval() (voptind.text + 7) 1548#define optindval() (voptind.text + 7)
1275 1549
1276#define mpathset() ((vmpath.flags & VUNSET) == 0) 1550#define mpathset() ((vmpath.flags & VUNSET) == 0)
1277 1551
1278static void initvar(void);
1279static void setvar(const char *, const char *, int); 1552static void setvar(const char *, const char *, int);
1280static void setvareq(char *, int); 1553static void setvareq(char *, int);
1281static void listsetvar(struct strlist *); 1554static void listsetvar(struct strlist *, int);
1282static const char *lookupvar(const char *); 1555static char *lookupvar(const char *);
1283static const char *bltinlookup(const char *); 1556static char *bltinlookup(const char *);
1284static char **environment(void); 1557static char **listvars(int, int, char ***);
1285static int showvarscmd(int, char **); 1558#define environment() listvars(VEXPORT, VUNSET, 0)
1286static void mklocal(char *); 1559static int showvars(const char *, int, int);
1287static void poplocalvars(void); 1560static void poplocalvars(void);
1288static int unsetvar(const char *); 1561static int unsetvar(const char *);
1289static int varequal(const char *, const char *); 1562#ifdef CONFIG_ASH_GETOPTS
1563static int setvarsafe(const char *, const char *, int);
1564#endif
1565static int varcmp(const char *, const char *);
1566static struct var **hashvar(const char *);
1290 1567
1291 1568
1292static char *arg0; /* value of $0 */ 1569static inline int varequal(const char *a, const char *b) {
1293static struct shparam shellparam; /* current positional parameters */ 1570 return !varcmp(a, b);
1294static char **argptr; /* argument list for builtin commands */ 1571}
1295static char *optionarg; /* set by nextopt (like getopt) */
1296static char *optptr; /* used by nextopt */
1297static char *minusc; /* argument to -c option */
1298 1572
1299 1573
1574static int loopnest; /* current loop nesting level */
1575
1576struct strpush {
1577 struct strpush *prev; /* preceding string on stack */
1578 char *prevstring;
1579 int prevnleft;
1300#ifdef CONFIG_ASH_ALIAS 1580#ifdef CONFIG_ASH_ALIAS
1581 struct alias *ap; /* if push was associated with an alias */
1582#endif
1583 char *string; /* remember the string since it may change */
1584};
1301 1585
1302#define ALIASINUSE 1 1586struct parsefile {
1303#define ALIASDEAD 2 1587 struct parsefile *prev; /* preceding file on stack */
1588 int linno; /* current line */
1589 int fd; /* file descriptor (or -1 if string) */
1590 int nleft; /* number of chars left in this line */
1591 int lleft; /* number of chars left in this buffer */
1592 char *nextc; /* next char in buffer */
1593 char *buf; /* input buffer */
1594 struct strpush *strpush; /* for pushing strings at this level */
1595 struct strpush basestrpush; /* so pushing one is fast */
1596};
1304 1597
1305#define ATABSIZE 39 1598/*
1599 * The parsefile structure pointed to by the global variable parsefile
1600 * contains information about the current file being read.
1601 */
1306 1602
1307struct alias { 1603
1308 struct alias *next; 1604struct redirtab {
1309 char *name; 1605 struct redirtab *next;
1310 char *val; 1606 int renamed[10];
1311 int flag; 1607 int nullredirs;
1312}; 1608};
1313 1609
1610static struct redirtab *redirlist;
1611static int nullredirs;
1612
1613extern char **environ;
1614
1615/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1616
1617
1618static void outstr(const char *, FILE *);
1619static void outcslow(int, FILE *);
1620static void flushall(void);
1621static void flushout(FILE *);
1622static int out1fmt(const char *, ...)
1623 __attribute__((__format__(__printf__,1,2)));
1624static int fmtstr(char *, size_t, const char *, ...)
1625 __attribute__((__format__(__printf__,3,4)));
1626static void xwrite(int, const void *, size_t);
1627
1628
1629#define outerr(f) ferror(f)
1630#define out2c(c) outcslow((c), stderr)
1631
1632static void out1str(const char *p)
1633{
1634 outstr(p, stdout);
1635}
1636
1637static void out2str(const char *p)
1638{
1639 outstr(p, stderr);
1640}
1641
1642static void out1c(char c)
1643{
1644 char s[2];
1645
1646 s[0] = c;
1647 s[1] = 0;
1648 outstr(s, stdout);
1649}
1650
1651/*
1652 * Initialization code.
1653 */
1654
1655/*
1656 * This routine initializes the builtin variables.
1657 */
1658
1659static inline void
1660initvar(void)
1661{
1662 struct var *vp;
1663 struct var *end;
1664 struct var **vpp;
1665
1666 /*
1667 * PS1 depends on uid
1668 */
1669#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1670 vps1.text = "PS1=\\w \\$ ";
1671#else
1672 if (!geteuid())
1673 vps1.text = "PS1=# ";
1674#endif
1675 vp = varinit;
1676 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1677 do {
1678 vpp = hashvar(vp->text);
1679 vp->next = *vpp;
1680 *vpp = vp;
1681 } while (++vp < end);
1682}
1683
1684static inline void
1685init(void)
1686{
1687
1688 /* from input.c: */
1689 {
1690 basepf.nextc = basepf.buf = basebuf;
1691 }
1692
1693 /* from trap.c: */
1694 {
1695 signal(SIGCHLD, SIG_DFL);
1696 }
1697
1698 /* from var.c: */
1699 {
1700 char **envp;
1701 char ppid[32];
1702
1703 initvar();
1704 for (envp = environ ; *envp ; envp++) {
1705 if (strchr(*envp, '=')) {
1706 setvareq(*envp, VEXPORT|VTEXTFIXED);
1707 }
1708 }
1709
1710 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1711 setvar("PPID", ppid, 0);
1712 setpwd(0, 0);
1713 }
1714}
1715
1716/* PEOF (the end of file marker) */
1717
1718/*
1719 * The input line number. Input.c just defines this variable, and saves
1720 * and restores it when files are pushed and popped. The user of this
1721 * package must set its value.
1722 */
1723
1724static int pgetc(void);
1725static int pgetc2(void);
1726static int preadbuffer(void);
1727static void pungetc(void);
1728static void pushstring(char *, void *);
1729static void popstring(void);
1730static void setinputfile(const char *, int);
1731static void setinputfd(int, int);
1732static void setinputstring(char *);
1733static void popfile(void);
1734static void popallfiles(void);
1735static void closescript(void);
1736
1737
1738/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1739
1740
1741/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1742#define FORK_FG 0
1743#define FORK_BG 1
1744#define FORK_NOJOB 2
1745
1746/* mode flags for showjob(s) */
1747#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1748#define SHOW_PID 0x04 /* include process pid */
1749#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1750
1751
1752/*
1753 * A job structure contains information about a job. A job is either a
1754 * single process or a set of processes contained in a pipeline. In the
1755 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1756 * array of pids.
1757 */
1758
1759struct procstat {
1760 pid_t pid; /* process id */
1761 int status; /* last process status from wait() */
1762 char *cmd; /* text of command being run */
1763};
1764
1765struct job {
1766 struct procstat ps0; /* status of process */
1767 struct procstat *ps; /* status or processes when more than one */
1768#if JOBS
1769 int stopstatus; /* status of a stopped job */
1770#endif
1771 uint32_t
1772 nprocs: 16, /* number of processes */
1773 state: 8,
1774#define JOBRUNNING 0 /* at least one proc running */
1775#define JOBSTOPPED 1 /* all procs are stopped */
1776#define JOBDONE 2 /* all procs are completed */
1777#if JOBS
1778 sigint: 1, /* job was killed by SIGINT */
1779 jobctl: 1, /* job running under job control */
1780#endif
1781 waited: 1, /* true if this entry has been waited for */
1782 used: 1, /* true if this entry is in used */
1783 changed: 1; /* true if status has changed */
1784 struct job *prev_job; /* previous job */
1785};
1786
1787static pid_t backgndpid; /* pid of last background process */
1788static int job_warning; /* user was warned about stopped jobs */
1789#if JOBS
1790static int jobctl; /* true if doing job control */
1791#endif
1792
1793static struct job *makejob(union node *, int);
1794static int forkshell(struct job *, union node *, int);
1795static int waitforjob(struct job *);
1796static int stoppedjobs(void);
1797
1798#if ! JOBS
1799#define setjobctl(on) /* do nothing */
1800#else
1801static void setjobctl(int);
1802static void showjobs(FILE *, int);
1803#endif
1804
1805/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1806
1807
1808/* pid of main shell */
1809static int rootpid;
1810/* true if we aren't a child of the main shell */
1811static int rootshell;
1812
1813static void readcmdfile(char *);
1814static void cmdloop(int);
1815
1816/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1817
1818
1819struct stackmark {
1820 struct stack_block *stackp;
1821 char *stacknxt;
1822 size_t stacknleft;
1823 struct stackmark *marknext;
1824};
1825
1826/* minimum size of a block */
1827#define MINSIZE SHELL_ALIGN(504)
1828
1829struct stack_block {
1830 struct stack_block *prev;
1831 char space[MINSIZE];
1832};
1833
1834static struct stack_block stackbase;
1835static struct stack_block *stackp = &stackbase;
1836static struct stackmark *markp;
1837static char *stacknxt = stackbase.space;
1838static size_t stacknleft = MINSIZE;
1839static char *sstrend = stackbase.space + MINSIZE;
1840static int herefd = -1;
1841
1842
1843static pointer ckmalloc(size_t);
1844static pointer ckrealloc(pointer, size_t);
1845static char *savestr(const char *);
1846static pointer stalloc(size_t);
1847static void stunalloc(pointer);
1848static void setstackmark(struct stackmark *);
1849static void popstackmark(struct stackmark *);
1850static void growstackblock(void);
1851static void *growstackstr(void);
1852static char *makestrspace(size_t, char *);
1853static char *stnputs(const char *, size_t, char *);
1854static char *stputs(const char *, char *);
1855
1856
1857static inline char *_STPUTC(char c, char *p) {
1858 if (p == sstrend)
1859 p = growstackstr();
1860 *p++ = c;
1861 return p;
1862}
1863
1864#define stackblock() ((void *)stacknxt)
1865#define stackblocksize() stacknleft
1866#define STARTSTACKSTR(p) ((p) = stackblock())
1867#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1868#define CHECKSTRSPACE(n, p) \
1869 ({ \
1870 char *q = (p); \
1871 size_t l = (n); \
1872 size_t m = sstrend - q; \
1873 if (l > m) \
1874 (p) = makestrspace(l, q); \
1875 0; \
1876 })
1877#define USTPUTC(c, p) (*p++ = (c))
1878#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1879#define STUNPUTC(p) (--p)
1880#define STTOPC(p) p[-1]
1881#define STADJUST(amount, p) (p += (amount))
1882
1883#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1884#define ungrabstackstr(s, p) stunalloc((s))
1885#define stackstrend() ((void *)sstrend)
1886
1887#define ckfree(p) free((pointer)(p))
1888
1889/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1890
1891
1892#define DOLATSTRLEN 4
1893
1894static char *prefix(const char *, const char *);
1895static int number(const char *);
1896static int is_number(const char *);
1897static char *single_quote(const char *);
1898static char *sstrdup(const char *);
1899
1900#define equal(s1, s2) (strcmp(s1, s2) == 0)
1901#define scopy(s1, s2) ((void)strcpy(s2, s1))
1902
1903/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1904
1905struct shparam {
1906 int nparam; /* # of positional parameters (without $0) */
1907 unsigned char malloc; /* if parameter list dynamically allocated */
1908 char **p; /* parameter list */
1909#ifdef CONFIG_ASH_GETOPTS
1910 int optind; /* next parameter to be processed by getopts */
1911 int optoff; /* used by getopts */
1912#endif
1913};
1914
1915
1916#define eflag optlist[0]
1917#define fflag optlist[1]
1918#define Iflag optlist[2]
1919#define iflag optlist[3]
1920#define mflag optlist[4]
1921#define nflag optlist[5]
1922#define sflag optlist[6]
1923#define xflag optlist[7]
1924#define vflag optlist[8]
1925#define Cflag optlist[9]
1926#define aflag optlist[10]
1927#define bflag optlist[11]
1928#define uflag optlist[12]
1929#define qflag optlist[13]
1930
1931#ifdef DEBUG
1932#define nolog optlist[14]
1933#define debug optlist[15]
1934#define NOPTS 16
1935#else
1936#define NOPTS 14
1937#endif
1938
1939/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1940
1941
1942static const char *const optletters_optnames[NOPTS] = {
1943 "e" "errexit",
1944 "f" "noglob",
1945 "I" "ignoreeof",
1946 "i" "interactive",
1947 "m" "monitor",
1948 "n" "noexec",
1949 "s" "stdin",
1950 "x" "xtrace",
1951 "v" "verbose",
1952 "C" "noclobber",
1953 "a" "allexport",
1954 "b" "notify",
1955 "u" "nounset",
1956 "q" "quietprofile",
1957#ifdef DEBUG
1958 "\0" "nolog",
1959 "\0" "debug",
1960#endif
1961};
1962
1963#define optletters(n) optletters_optnames[(n)][0]
1964#define optnames(n) (&optletters_optnames[(n)][1])
1965
1966
1967static char optlist[NOPTS];
1968
1969
1970static char *arg0; /* value of $0 */
1971static struct shparam shellparam; /* $@ current positional parameters */
1972static char **argptr; /* argument list for builtin commands */
1973static char *optionarg; /* set by nextopt (like getopt) */
1974static char *optptr; /* used by nextopt */
1975
1976static char *minusc; /* argument to -c option */
1977
1978
1979static void procargs(int, char **);
1980static void optschanged(void);
1981static void setparam(char **);
1982static void freeparam(volatile struct shparam *);
1983static int shiftcmd(int, char **);
1984static int setcmd(int, char **);
1985static int nextopt(const char *);
1986
1987/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1988
1989/* flags passed to redirect */
1990#define REDIR_PUSH 01 /* save previous values of file descriptors */
1991
1992union node;
1993static void redirect(union node *, int);
1994static void popredir(int);
1995static void clearredir(int);
1996static int copyfd(int, int);
1997static int redirectsafe(union node *, int);
1998
1999/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2000
2001
2002#ifdef DEBUG
2003static void showtree(union node *);
2004static void trace(const char *, ...);
2005static void tracev(const char *, va_list);
2006static void trargs(char **);
2007static void trputc(int);
2008static void trputs(const char *);
2009static void opentrace(void);
2010#endif
2011
2012/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2013
2014
2015/* trap handler commands */
2016static char *trap[NSIG];
2017/* current value of signal */
2018static char sigmode[NSIG - 1];
2019/* indicates specified signal received */
2020static char gotsig[NSIG - 1];
2021
2022static void clear_traps(void);
2023static void setsignal(int);
2024static void ignoresig(int);
2025static void onsig(int);
2026static void dotrap(void);
2027static void setinteractive(int);
2028static void exitshell(void) __attribute__((__noreturn__));
2029static int decode_signal(const char *, int);
2030
2031/*
2032 * This routine is called when an error or an interrupt occurs in an
2033 * interactive shell and control is returned to the main command loop.
2034 */
2035
2036static void
2037reset(void)
2038{
2039 /* from eval.c: */
2040 {
2041 evalskip = 0;
2042 loopnest = 0;
2043 funcnest = 0;
2044 }
2045
2046 /* from input.c: */
2047 {
2048 parselleft = parsenleft = 0; /* clear input buffer */
2049 popallfiles();
2050 }
2051
2052 /* from parser.c: */
2053 {
2054 tokpushback = 0;
2055 checkkwd = 0;
2056 }
2057
2058 /* from redir.c: */
2059 {
2060 clearredir(0);
2061 }
2062
2063}
2064
2065#ifdef CONFIG_ASH_ALIAS
1314static struct alias *atab[ATABSIZE]; 2066static struct alias *atab[ATABSIZE];
1315 2067
1316static void setalias(char *, char *); 2068static void setalias(const char *, const char *);
1317static struct alias **hashalias(const char *);
1318static struct alias *freealias(struct alias *); 2069static struct alias *freealias(struct alias *);
1319static struct alias **__lookupalias(const char *); 2070static struct alias **__lookupalias(const char *);
1320 2071
1321static void setalias(char *name, char *val) 2072static void
2073setalias(const char *name, const char *val)
1322{ 2074{
1323 struct alias *ap, **app; 2075 struct alias *ap, **app;
1324 2076
@@ -1327,15 +2079,15 @@ static void setalias(char *name, char *val)
1327 INTOFF; 2079 INTOFF;
1328 if (ap) { 2080 if (ap) {
1329 if (!(ap->flag & ALIASINUSE)) { 2081 if (!(ap->flag & ALIASINUSE)) {
1330 free(ap->val); 2082 ckfree(ap->val);
1331 } 2083 }
1332 ap->val = bb_xstrdup(val); 2084 ap->val = savestr(val);
1333 ap->flag &= ~ALIASDEAD; 2085 ap->flag &= ~ALIASDEAD;
1334 } else { 2086 } else {
1335 /* not found */ 2087 /* not found */
1336 ap = xmalloc(sizeof(struct alias)); 2088 ap = ckmalloc(sizeof (struct alias));
1337 ap->name = bb_xstrdup(name); 2089 ap->name = savestr(name);
1338 ap->val = bb_xstrdup(val); 2090 ap->val = savestr(val);
1339 ap->flag = 0; 2091 ap->flag = 0;
1340 ap->next = 0; 2092 ap->next = 0;
1341 *app = ap; 2093 *app = ap;
@@ -1343,7 +2095,8 @@ static void setalias(char *name, char *val)
1343 INTON; 2095 INTON;
1344} 2096}
1345 2097
1346static int unalias(char *name) 2098static int
2099unalias(const char *name)
1347{ 2100{
1348 struct alias **app; 2101 struct alias **app;
1349 2102
@@ -1359,7 +2112,8 @@ static int unalias(char *name)
1359 return (1); 2112 return (1);
1360} 2113}
1361 2114
1362static void rmaliases(void) 2115static void
2116rmaliases(void)
1363{ 2117{
1364 struct alias *ap, **app; 2118 struct alias *ap, **app;
1365 int i; 2119 int i;
@@ -1377,20 +2131,21 @@ static void rmaliases(void)
1377 INTON; 2131 INTON;
1378} 2132}
1379 2133
1380static void printalias(const struct alias *ap) 2134static struct alias *
2135lookupalias(const char *name, int check)
1381{ 2136{
1382 char *p; 2137 struct alias *ap = *__lookupalias(name);
1383 2138
1384 p = single_quote(ap->val); 2139 if (check && ap && (ap->flag & ALIASINUSE))
1385 printf("alias %s=%s\n", ap->name, p); 2140 return (NULL);
1386 stunalloc(p); 2141 return (ap);
1387} 2142}
1388 2143
1389
1390/* 2144/*
1391 * TODO - sort output 2145 * TODO - sort output
1392 */ 2146 */
1393static int aliascmd(int argc, char **argv) 2147static int
2148aliascmd(int argc, char **argv)
1394{ 2149{
1395 char *n, *v; 2150 char *n, *v;
1396 int ret = 0; 2151 int ret = 0;
@@ -1406,9 +2161,9 @@ static int aliascmd(int argc, char **argv)
1406 return (0); 2161 return (0);
1407 } 2162 }
1408 while ((n = *++argv) != NULL) { 2163 while ((n = *++argv) != NULL) {
1409 if ((v = strchr(n + 1, '=')) == NULL) { /* n+1: funny ksh stuff */ 2164 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1410 if ((ap = *__lookupalias(n)) == NULL) { 2165 if ((ap = *__lookupalias(n)) == NULL) {
1411 out2fmt("%s: %s not found\n", "alias", n); 2166 fprintf(stderr, "%s: %s not found\n", "alias", n);
1412 ret = 1; 2167 ret = 1;
1413 } else 2168 } else
1414 printalias(ap); 2169 printalias(ap);
@@ -1421,7 +2176,8 @@ static int aliascmd(int argc, char **argv)
1421 return (ret); 2176 return (ret);
1422} 2177}
1423 2178
1424static int unaliascmd(int argc, char **argv) 2179static int
2180unaliascmd(int argc, char **argv)
1425{ 2181{
1426 int i; 2182 int i;
1427 2183
@@ -1433,7 +2189,7 @@ static int unaliascmd(int argc, char **argv)
1433 } 2189 }
1434 for (i = 0; *argptr; argptr++) { 2190 for (i = 0; *argptr; argptr++) {
1435 if (unalias(*argptr)) { 2191 if (unalias(*argptr)) {
1436 out2fmt("%s: %s not found\n", "unalias", *argptr); 2192 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
1437 i = 1; 2193 i = 1;
1438 } 2194 }
1439 } 2195 }
@@ -1441,18 +2197,8 @@ static int unaliascmd(int argc, char **argv)
1441 return (i); 2197 return (i);
1442} 2198}
1443 2199
1444static struct alias **hashalias(const char *p) 2200static struct alias *
1445{ 2201freealias(struct alias *ap) {
1446 unsigned int hashval;
1447
1448 hashval = *p << 4;
1449 while (*p)
1450 hashval += *p++;
1451 return &atab[hashval % ATABSIZE];
1452}
1453
1454static struct alias *freealias(struct alias *ap)
1455{
1456 struct alias *next; 2202 struct alias *next;
1457 2203
1458 if (ap->flag & ALIASINUSE) { 2204 if (ap->flag & ALIASINUSE) {
@@ -1461,16 +2207,33 @@ static struct alias *freealias(struct alias *ap)
1461 } 2207 }
1462 2208
1463 next = ap->next; 2209 next = ap->next;
1464 free(ap->name); 2210 ckfree(ap->name);
1465 free(ap->val); 2211 ckfree(ap->val);
1466 free(ap); 2212 ckfree(ap);
1467 return next; 2213 return next;
1468} 2214}
1469 2215
2216static void
2217printalias(const struct alias *ap) {
2218 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2219}
1470 2220
1471static struct alias **__lookupalias(const char *name) 2221static struct alias **
1472{ 2222__lookupalias(const char *name) {
1473 struct alias **app = hashalias(name); 2223 unsigned int hashval;
2224 struct alias **app;
2225 const char *p;
2226 unsigned int ch;
2227
2228 p = name;
2229
2230 ch = (unsigned char)*p;
2231 hashval = ch << 4;
2232 while (ch) {
2233 hashval += ch;
2234 ch = (unsigned char)*++p;
2235 }
2236 app = &atab[hashval % ATABSIZE];
1474 2237
1475 for (; *app; app = &(*app)->next) { 2238 for (; *app; app = &(*app)->next) {
1476 if (equal(name, (*app)->name)) { 2239 if (equal(name, (*app)->name)) {
@@ -1480,362 +2243,257 @@ static struct alias **__lookupalias(const char *name)
1480 2243
1481 return app; 2244 return app;
1482} 2245}
1483#endif 2246#endif /* CONFIG_ASH_ALIAS */
1484
1485#ifdef CONFIG_ASH_MATH_SUPPORT
1486/* The generated file arith.c has been replaced with a custom hand
1487 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1488 * This is now part of libbb, so that it can be used by all the shells
1489 * in busybox. */
1490static void expari(int);
1491#endif
1492
1493static char *trap[NSIG]; /* trap handler commands */
1494static char sigmode[NSIG - 1]; /* current value of signal */
1495static char gotsig[NSIG - 1]; /* indicates specified signal received */
1496static int pendingsigs; /* indicates some signal received */
1497
1498/*
1499 * This file was generated by the mkbuiltins program.
1500 */
1501
1502#ifdef CONFIG_ASH_JOB_CONTROL
1503static int bgcmd(int, char **);
1504static int fgcmd(int, char **);
1505static int killcmd(int, char **);
1506#endif
1507static int bltincmd(int, char **);
1508static int cdcmd(int, char **);
1509static int breakcmd(int, char **);
1510
1511#ifdef CONFIG_ASH_CMDCMD
1512static int commandcmd(int, char **);
1513#endif
1514static int dotcmd(int, char **);
1515static int evalcmd(int, char **);
1516static int execcmd(int, char **);
1517static int exitcmd(int, char **);
1518static int exportcmd(int, char **);
1519static int histcmd(int, char **);
1520static int hashcmd(int, char **);
1521static int helpcmd(int, char **);
1522static int jobscmd(int, char **);
1523static int localcmd(int, char **);
1524static int pwdcmd(int, char **);
1525static int readcmd(int, char **);
1526static int returncmd(int, char **);
1527static int setcmd(int, char **);
1528static int setvarcmd(int, char **);
1529static int shiftcmd(int, char **);
1530static int trapcmd(int, char **);
1531static int umaskcmd(int, char **);
1532
1533#ifdef CONFIG_ASH_ALIAS
1534static int aliascmd(int, char **);
1535static int unaliascmd(int, char **);
1536#endif
1537static int unsetcmd(int, char **);
1538static int waitcmd(int, char **);
1539static int ulimitcmd(int, char **);
1540static int timescmd(int, char **);
1541
1542#ifdef CONFIG_ASH_MATH_SUPPORT
1543static int letcmd(int, char **);
1544#endif
1545static int typecmd(int, char **);
1546
1547#ifdef CONFIG_ASH_GETOPTS
1548static int getoptscmd(int, char **);
1549#endif
1550
1551#ifndef CONFIG_TRUE
1552static int true_main(int, char **);
1553#endif
1554#ifndef CONFIG_FALSE
1555static int false_main(int, char **);
1556#endif
1557
1558static void setpwd(const char *, int);
1559
1560
1561#define BUILTIN_NOSPEC "0"
1562#define BUILTIN_SPECIAL "1"
1563#define BUILTIN_REGULAR "2"
1564#define BUILTIN_ASSIGN "4"
1565#define BUILTIN_SPEC_ASSG "5"
1566#define BUILTIN_REG_ASSG "6"
1567
1568#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1569#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1570#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1571 2247
1572struct builtincmd {
1573 const char *name;
1574 int (*const builtinfunc) (int, char **);
1575 //unsigned flags;
1576};
1577
1578
1579/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1580 * the binary search in find_builtin() will stop working. If you value
1581 * your kneecaps, you'll be sure to *make sure* that any changes made
1582 * to this array result in the listing remaining in ascii order. You
1583 * have been warned.
1584 */
1585static const struct builtincmd builtincmds[] = {
1586 {BUILTIN_SPECIAL ".", dotcmd}, /* first, see declare DOTCMD */
1587 {BUILTIN_SPECIAL ":", true_main},
1588#ifdef CONFIG_ASH_ALIAS
1589 {BUILTIN_REG_ASSG "alias", aliascmd},
1590#endif
1591#ifdef CONFIG_ASH_JOB_CONTROL
1592 {BUILTIN_REGULAR "bg", bgcmd},
1593#endif
1594 {BUILTIN_SPECIAL "break", breakcmd},
1595 {BUILTIN_SPECIAL "builtin", bltincmd},
1596 {BUILTIN_REGULAR "cd", cdcmd},
1597 {BUILTIN_NOSPEC "chdir", cdcmd},
1598#ifdef CONFIG_ASH_CMDCMD
1599 {BUILTIN_REGULAR "command", commandcmd},
1600#endif
1601 {BUILTIN_SPECIAL "continue", breakcmd},
1602 {BUILTIN_SPECIAL "eval", evalcmd},
1603 {BUILTIN_SPECIAL "exec", execcmd},
1604 {BUILTIN_SPECIAL "exit", exitcmd},
1605 {BUILTIN_SPEC_ASSG "export", exportcmd},
1606 {BUILTIN_REGULAR "false", false_main},
1607 {BUILTIN_REGULAR "fc", histcmd},
1608#ifdef CONFIG_ASH_JOB_CONTROL
1609 {BUILTIN_REGULAR "fg", fgcmd},
1610#endif
1611#ifdef CONFIG_ASH_GETOPTS
1612 {BUILTIN_REGULAR "getopts", getoptscmd},
1613#endif
1614 {BUILTIN_NOSPEC "hash", hashcmd},
1615 {BUILTIN_NOSPEC "help", helpcmd},
1616 {BUILTIN_REGULAR "jobs", jobscmd},
1617#ifdef CONFIG_ASH_JOB_CONTROL
1618 {BUILTIN_REGULAR "kill", killcmd},
1619#endif
1620#ifdef CONFIG_ASH_MATH_SUPPORT
1621 {BUILTIN_REGULAR "let", letcmd},
1622#endif
1623 {BUILTIN_ASSIGN "local", localcmd},
1624 {BUILTIN_NOSPEC "pwd", pwdcmd},
1625 {BUILTIN_REGULAR "read", readcmd},
1626 {BUILTIN_SPEC_ASSG "readonly", exportcmd},
1627 {BUILTIN_SPECIAL "return", returncmd},
1628 {BUILTIN_SPECIAL "set", setcmd},
1629 {BUILTIN_NOSPEC "setvar", setvarcmd},
1630 {BUILTIN_SPECIAL "shift", shiftcmd},
1631 {BUILTIN_SPECIAL "times", timescmd},
1632 {BUILTIN_SPECIAL "trap", trapcmd},
1633 {BUILTIN_REGULAR "true", true_main},
1634 {BUILTIN_NOSPEC "type", typecmd},
1635 {BUILTIN_NOSPEC "ulimit", ulimitcmd},
1636 {BUILTIN_REGULAR "umask", umaskcmd},
1637#ifdef CONFIG_ASH_ALIAS
1638 {BUILTIN_REGULAR "unalias", unaliascmd},
1639#endif
1640 {BUILTIN_SPECIAL "unset", unsetcmd},
1641 {BUILTIN_REGULAR "wait", waitcmd},
1642};
1643 2248
1644#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) ) 2249/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
1645
1646#define DOTCMD &builtincmds[0]
1647static struct builtincmd *BLTINCMD;
1648static struct builtincmd *EXECCMD;
1649static struct builtincmd *EVALCMD;
1650
1651/* states */
1652#define JOBSTOPPED 1 /* all procs are stopped */
1653#define JOBDONE 2 /* all procs are completed */
1654 2250
1655/* 2251/*
1656 * A job structure contains information about a job. A job is either a 2252 * The cd and pwd commands.
1657 * single process or a set of processes contained in a pipeline. In the
1658 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1659 * array of pids.
1660 */ 2253 */
1661 2254
1662struct procstat { 2255#define CD_PHYSICAL 1
1663 pid_t pid; /* process id */ 2256#define CD_PRINT 2
1664 int status; /* status flags (defined above) */
1665 char *cmd; /* text of command being run */
1666};
1667
1668
1669static int job_warning; /* user was warned about stopped jobs */
1670
1671#ifdef CONFIG_ASH_JOB_CONTROL
1672static void setjobctl(int enable);
1673#else
1674#define setjobctl(on) /* do nothing */
1675#endif
1676
1677
1678struct job {
1679 struct procstat ps0; /* status of process */
1680 struct procstat *ps; /* status or processes when more than one */
1681 short nprocs; /* number of processes */
1682 short pgrp; /* process group of this job */
1683 char state; /* true if job is finished */
1684 char used; /* true if this entry is in used */
1685 char changed; /* true if status has changed */
1686#ifdef CONFIG_ASH_JOB_CONTROL
1687 char jobctl; /* job running under job control */
1688#endif
1689};
1690
1691static struct job *jobtab; /* array of jobs */
1692static int njobs; /* size of array */
1693static int backgndpid = -1; /* pid of last background process */
1694 2257
1695#ifdef CONFIG_ASH_JOB_CONTROL 2258static int docd(const char *, int);
1696static int initialpgrp; /* pgrp of shell on invocation */ 2259static int cdopt(void);
1697static int curjob; /* current job */
1698static int jobctl;
1699#endif
1700 2260
1701static struct job *makejob(const union node *, int); 2261static char *curdir = nullstr; /* current working directory */
1702static int forkshell(struct job *, const union node *, int); 2262static char *physdir = nullstr; /* physical working directory */
1703static int waitforjob(struct job *);
1704 2263
1705static int docd(char *, int); 2264static int
1706static void getpwd(void); 2265cdopt(void)
2266{
2267 int flags = 0;
2268 int i, j;
1707 2269
1708static char *padvance(const char **, const char *); 2270 j = 'L';
2271 while ((i = nextopt("LP"))) {
2272 if (i != j) {
2273 flags ^= CD_PHYSICAL;
2274 j = i;
2275 }
2276 }
1709 2277
1710static char nullstr[1]; /* zero length string */ 2278 return flags;
1711static char *curdir = nullstr; /* current working directory */ 2279}
1712 2280
1713static int cdcmd(int argc, char **argv) 2281static int
2282cdcmd(int argc, char **argv)
1714{ 2283{
1715 const char *dest; 2284 const char *dest;
1716 const char *path; 2285 const char *path;
1717 char *p; 2286 const char *p;
2287 char c;
1718 struct stat statb; 2288 struct stat statb;
1719 int print = 0; 2289 int flags;
1720 2290
1721 nextopt(nullstr); 2291 flags = cdopt();
1722 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL) 2292 dest = *argptr;
1723 error("HOME not set"); 2293 if (!dest)
1724 if (*dest == '\0') 2294 dest = bltinlookup(homestr);
1725 dest = "."; 2295 else if (dest[0] == '-' && dest[1] == '\0') {
1726 if (dest[0] == '-' && dest[1] == '\0') {
1727 dest = bltinlookup("OLDPWD"); 2296 dest = bltinlookup("OLDPWD");
1728 if (!dest || !*dest) { 2297 flags |= CD_PRINT;
1729 dest = curdir; 2298 goto step7;
2299 }
2300 if (!dest)
2301 dest = nullstr;
2302 if (*dest == '/')
2303 goto step7;
2304 if (*dest == '.') {
2305 c = dest[1];
2306dotdot:
2307 switch (c) {
2308 case '\0':
2309 case '/':
2310 goto step6;
2311 case '.':
2312 c = dest[2];
2313 if (c != '.')
2314 goto dotdot;
1730 } 2315 }
1731 print = 1;
1732 if (dest)
1733 print = 1;
1734 else
1735 dest = ".";
1736 } 2316 }
1737 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL) 2317 if (!*dest)
1738 path = nullstr; 2318 dest = ".";
1739 while ((p = padvance(&path, dest)) != NULL) { 2319 if (!(path = bltinlookup("CDPATH"))) {
2320step6:
2321step7:
2322 p = dest;
2323 goto docd;
2324 }
2325 do {
2326 c = *path;
2327 p = padvance(&path, dest);
1740 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 2328 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1741 if (!print) { 2329 if (c && c != ':')
1742 /* 2330 flags |= CD_PRINT;
1743 * XXX - rethink 2331docd:
1744 */ 2332 if (!docd(p, flags))
1745 if (p[0] == '.' && p[1] == '/' && p[2] != '\0') 2333 goto out;
1746 p += 2; 2334 break;
1747 print = strcmp(p, dest);
1748 }
1749 if (docd(p, print) >= 0)
1750 return 0;
1751
1752 } 2335 }
1753 } 2336 } while (path);
1754 error("can't cd to %s", dest); 2337 error("can't cd to %s", dest);
1755 /* NOTREACHED */ 2338 /* NOTREACHED */
2339out:
2340 if (flags & CD_PRINT)
2341 out1fmt(snlfmt, curdir);
2342 return 0;
1756} 2343}
1757 2344
1758 2345
1759/* 2346/*
1760 * Update curdir (the name of the current directory) in response to a 2347 * Update curdir (the name of the current directory) in response to a
1761 * cd command. We also call hashcd to let the routines in exec.c know 2348 * cd command.
1762 * that the current directory has changed.
1763 */ 2349 */
1764 2350
1765static void hashcd(void); 2351static inline const char *
1766 2352updatepwd(const char *dir)
1767static inline void updatepwd(const char *dir)
1768{ 2353{
1769 hashcd(); /* update command hash table */ 2354 char *new;
2355 char *p;
2356 char *cdcomppath;
2357 const char *lim;
1770 2358
1771 /* 2359 cdcomppath = sstrdup(dir);
1772 * If our argument is NULL, we don't know the current directory 2360 STARTSTACKSTR(new);
1773 */ 2361 if (*dir != '/') {
1774 if (dir == NULL || curdir == nullstr) { 2362 if (curdir == nullstr)
1775 setpwd(0, 1); 2363 return 0;
2364 new = stputs(curdir, new);
2365 }
2366 new = makestrspace(strlen(dir) + 2, new);
2367 lim = stackblock() + 1;
2368 if (*dir != '/') {
2369 if (new[-1] != '/')
2370 USTPUTC('/', new);
2371 if (new > lim && *lim == '/')
2372 lim++;
1776 } else { 2373 } else {
1777 setpwd(dir, 1); 2374 USTPUTC('/', new);
2375 cdcomppath++;
2376 if (dir[1] == '/' && dir[2] != '/') {
2377 USTPUTC('/', new);
2378 cdcomppath++;
2379 lim++;
2380 }
2381 }
2382 p = strtok(cdcomppath, "/");
2383 while (p) {
2384 switch(*p) {
2385 case '.':
2386 if (p[1] == '.' && p[2] == '\0') {
2387 while (new > lim) {
2388 STUNPUTC(new);
2389 if (new[-1] == '/')
2390 break;
2391 }
2392 break;
2393 } else if (p[1] == '\0')
2394 break;
2395 /* fall through */
2396 default:
2397 new = stputs(p, new);
2398 USTPUTC('/', new);
2399 }
2400 p = strtok(0, "/");
1778 } 2401 }
2402 if (new > lim)
2403 STUNPUTC(new);
2404 *new = 0;
2405 return stackblock();
1779} 2406}
1780 2407
1781/* 2408/*
1782 * Actually do the chdir. In an interactive shell, print the 2409 * Actually do the chdir. We also call hashcd to let the routines in exec.c
1783 * directory name if "print" is nonzero. 2410 * know that the current directory has changed.
1784 */ 2411 */
1785 2412
1786static int docd(char *dest, int print) 2413static int
2414docd(const char *dest, int flags)
1787{ 2415{
1788 TRACE(("docd(\"%s\", %d) called\n", dest, print)); 2416 const char *dir = 0;
2417 int err;
2418
2419 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2420
1789 INTOFF; 2421 INTOFF;
1790 if (chdir(dest) < 0) { 2422 if (!(flags & CD_PHYSICAL)) {
1791 INTON; 2423 dir = updatepwd(dest);
1792 return -1; 2424 if (dir)
2425 dest = dir;
1793 } 2426 }
1794 updatepwd(dest); 2427 err = chdir(dest);
2428 if (err)
2429 goto out;
2430 setpwd(dir, 1);
2431 hashcd();
2432out:
1795 INTON; 2433 INTON;
1796 if (print && iflag) 2434 return err;
1797 puts(curdir);
1798 return 0;
1799} 2435}
1800 2436
1801 2437/*
1802static int pwdcmd(int argc, char **argv) 2438 * Find out what the current directory is. If we already know the current
2439 * directory, this routine returns immediately.
2440 */
2441static inline char *
2442getpwd(void)
1803{ 2443{
1804 puts(curdir); 2444 char *dir = getcwd(0, 0);
1805 return 0; 2445 return dir ? dir : nullstr;
1806} 2446}
1807 2447
1808/* Ask system the current directory */ 2448static int
1809static void getpwd(void) 2449pwdcmd(int argc, char **argv)
1810{ 2450{
1811 curdir = xgetcwd(0); 2451 int flags;
1812 if (curdir == 0) 2452 const char *dir = curdir;
1813 curdir = nullstr; 2453
2454 flags = cdopt();
2455 if (flags) {
2456 if (physdir == nullstr)
2457 setpwd(dir, 0);
2458 dir = physdir;
2459 }
2460 out1fmt(snlfmt, dir);
2461 return 0;
1814} 2462}
1815 2463
1816static void setpwd(const char *val, int setold) 2464static void
2465setpwd(const char *val, int setold)
1817{ 2466{
1818 char *cated = NULL; 2467 char *oldcur, *dir;
2468
2469 oldcur = dir = curdir;
1819 2470
1820 if (setold) { 2471 if (setold) {
1821 setvar("OLDPWD", curdir, VEXPORT); 2472 setvar("OLDPWD", oldcur, VEXPORT);
1822 } 2473 }
1823 INTOFF; 2474 INTOFF;
1824 if (curdir != nullstr) { 2475 if (physdir != nullstr) {
1825 if (val != NULL && *val != '/') 2476 if (physdir != oldcur)
1826 val = cated = concat_path_file(curdir, val); 2477 free(physdir);
1827 free(curdir); 2478 physdir = nullstr;
2479 }
2480 if (oldcur == val || !val) {
2481 char *s = getpwd();
2482 physdir = s;
2483 if (!val)
2484 dir = s;
2485 } else
2486 dir = savestr(val);
2487 if (oldcur != dir && oldcur != nullstr) {
2488 free(oldcur);
1828 } 2489 }
1829 if (!val) 2490 curdir = dir;
1830 getpwd();
1831 else
1832 curdir = bb_simplify_path(val);
1833 if (cated)
1834 free(cated);
1835 INTON; 2491 INTON;
1836 setvar("PWD", curdir, VEXPORT); 2492 setvar("PWD", dir, VEXPORT);
1837} 2493}
1838 2494
2495/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2496
1839/* 2497/*
1840 * Errors and exceptions. 2498 * Errors and exceptions.
1841 */ 2499 */
@@ -1844,32 +2502,10 @@ static void setpwd(const char *val, int setold)
1844 * Code to handle exceptions in C. 2502 * Code to handle exceptions in C.
1845 */ 2503 */
1846 2504
1847/*
1848 * We enclose jmp_buf in a structure so that we can declare pointers to
1849 * jump locations. The global variable handler contains the location to
1850 * jump to when an exception occurs, and the global variable exception
1851 * contains a code identifying the exeception. To implement nested
1852 * exception handlers, the user should save the value of handler on entry
1853 * to an inner scope, set handler to point to a jmploc structure for the
1854 * inner scope, and restore handler on exit from the scope.
1855 */
1856
1857struct jmploc {
1858 jmp_buf loc;
1859};
1860 2505
1861/* exceptions */
1862#define EXINT 0 /* SIGINT received */
1863#define EXERROR 1 /* a generic error */
1864#define EXSHELLPROC 2 /* execute a shell procedure */
1865#define EXEXEC 3 /* command execution failed */
1866#define EXREDIR 4 /* redirection error */
1867
1868static struct jmploc *handler;
1869static int exception;
1870 2506
1871static void exverror(int, const char *, va_list) 2507static void exverror(int, const char *, va_list)
1872 __attribute__ ((__noreturn__)); 2508 __attribute__((__noreturn__));
1873 2509
1874/* 2510/*
1875 * Called to raise an exception. Since C doesn't include exceptions, we 2511 * Called to raise an exception. Since C doesn't include exceptions, we
@@ -1877,15 +2513,15 @@ static void exverror(int, const char *, va_list)
1877 * stored in the global variable "exception". 2513 * stored in the global variable "exception".
1878 */ 2514 */
1879 2515
1880static void exraise(int) __attribute__ ((__noreturn__)); 2516static void
1881 2517exraise(int e)
1882static void exraise(int e)
1883{ 2518{
1884#ifdef DEBUG 2519#ifdef DEBUG
1885 if (handler == NULL) 2520 if (handler == NULL)
1886 abort(); 2521 abort();
1887#endif 2522#endif
1888 flushall(); 2523 INTOFF;
2524
1889 exception = e; 2525 exception = e;
1890 longjmp(handler->loc, 1); 2526 longjmp(handler->loc, 1);
1891} 2527}
@@ -1895,62 +2531,74 @@ static void exraise(int e)
1895 * Called from trap.c when a SIGINT is received. (If the user specifies 2531 * Called from trap.c when a SIGINT is received. (If the user specifies
1896 * that SIGINT is to be trapped or ignored using the trap builtin, then 2532 * that SIGINT is to be trapped or ignored using the trap builtin, then
1897 * this routine is not called.) Suppressint is nonzero when interrupts 2533 * this routine is not called.) Suppressint is nonzero when interrupts
1898 * are held using the INTOFF macro. The call to _exit is necessary because 2534 * are held using the INTOFF macro. (The test for iflag is just
1899 * there is a short period after a fork before the signal handlers are 2535 * defensive programming.)
1900 * set to the appropriate value for the child. (The test for iflag is
1901 * just defensive programming.)
1902 */ 2536 */
1903 2537
1904static void onint(void) 2538static void
1905{ 2539onint(void) {
1906 sigset_t mysigset; 2540 int i;
1907 2541
1908 if (suppressint) {
1909 intpending++;
1910 return;
1911 }
1912 intpending = 0; 2542 intpending = 0;
1913 sigemptyset(&mysigset); 2543 sigsetmask(0);
1914 sigprocmask(SIG_SETMASK, &mysigset, NULL); 2544 i = EXSIG;
1915 if (!(rootshell && iflag)) { 2545 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
1916 signal(SIGINT, SIG_DFL); 2546 if (!(rootshell && iflag)) {
1917 raise(SIGINT); 2547 signal(SIGINT, SIG_DFL);
2548 raise(SIGINT);
2549 }
2550 i = EXINT;
1918 } 2551 }
1919 exraise(EXINT); 2552 exraise(i);
1920 /* NOTREACHED */ 2553 /* NOTREACHED */
1921} 2554}
1922 2555
2556static void
2557exvwarning(const char *msg, va_list ap)
2558{
2559 FILE *errs;
2560 const char *name;
2561 const char *fmt;
1923 2562
1924static char *commandname; /* currently executing command */ 2563 errs = stderr;
2564 name = arg0;
2565 fmt = "%s: ";
2566 if (commandname) {
2567 name = commandname;
2568 fmt = "%s: %d: ";
2569 }
2570 fprintf(errs, fmt, name, startlinno);
2571 vfprintf(errs, msg, ap);
2572 outcslow('\n', errs);
2573}
1925 2574
1926/* 2575/*
1927 * Exverror is called to raise the error exception. If the first argument 2576 * Exverror is called to raise the error exception. If the second argument
1928 * is not NULL then error prints an error message using printf style 2577 * is not NULL then error prints an error message using printf style
1929 * formatting. It then raises the error exception. 2578 * formatting. It then raises the error exception.
1930 */ 2579 */
1931static void exverror(int cond, const char *msg, va_list ap) 2580static void
2581exverror(int cond, const char *msg, va_list ap)
1932{ 2582{
1933 CLEAR_PENDING_INT;
1934 INTOFF;
1935
1936#ifdef DEBUG 2583#ifdef DEBUG
1937 if (msg) 2584 if (msg) {
1938 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid())); 2585 TRACE(("exverror(%d, \"", cond));
1939 else 2586 TRACEV((msg, ap));
2587 TRACE(("\") pid=%d\n", getpid()));
2588 } else
1940 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); 2589 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2590 if (msg)
1941#endif 2591#endif
1942 if (msg) { 2592 exvwarning(msg, ap);
1943 if (commandname) 2593
1944 out2fmt("%s: ", commandname); 2594 flushall();
1945 vfprintf(stderr, msg, ap);
1946 out2c('\n');
1947 }
1948 exraise(cond); 2595 exraise(cond);
1949 /* NOTREACHED */ 2596 /* NOTREACHED */
1950} 2597}
1951 2598
1952 2599
1953static void error(const char *msg, ...) 2600static void
2601error(const char *msg, ...)
1954{ 2602{
1955 va_list ap; 2603 va_list ap;
1956 2604
@@ -1961,7 +2609,8 @@ static void error(const char *msg, ...)
1961} 2609}
1962 2610
1963 2611
1964static void exerror(int cond, const char *msg, ...) 2612static void
2613exerror(int cond, const char *msg, ...)
1965{ 2614{
1966 va_list ap; 2615 va_list ap;
1967 2616
@@ -1971,82 +2620,20 @@ static void exerror(int cond, const char *msg, ...)
1971 va_end(ap); 2620 va_end(ap);
1972} 2621}
1973 2622
1974
1975
1976/* 2623/*
1977 * Table of error messages. 2624 * error/warning routines for external builtins
1978 */ 2625 */
1979 2626
1980struct errname { 2627static void
1981 short errcode; /* error number */ 2628sh_warnx(const char *fmt, ...)
1982 short action; /* operation which encountered the error */ 2629{
1983}; 2630 va_list ap;
1984
1985/*
1986 * Types of operations (passed to the errmsg routine).
1987 */
1988
1989#define E_OPEN 01 /* opening a file */
1990#define E_CREAT 02 /* creating a file */
1991#define E_EXEC 04 /* executing a program */
1992
1993#define ALL (E_OPEN|E_CREAT|E_EXEC)
1994 2631
1995static const struct errname errormsg[] = { 2632 va_start(ap, fmt);
1996 {EINTR, ALL}, 2633 exvwarning(fmt, ap);
1997 {EACCES, ALL}, 2634 va_end(ap);
1998 {EIO, ALL}, 2635}
1999 {ENOENT, E_OPEN},
2000 {ENOENT, E_CREAT},
2001 {ENOENT, E_EXEC},
2002 {ENOTDIR, E_OPEN},
2003 {ENOTDIR, E_CREAT},
2004 {ENOTDIR, E_EXEC},
2005 {EISDIR, ALL},
2006 {EEXIST, E_CREAT},
2007#ifdef EMFILE
2008 {EMFILE, ALL},
2009#endif
2010 {ENFILE, ALL},
2011 {ENOSPC, ALL},
2012#ifdef EDQUOT
2013 {EDQUOT, ALL},
2014#endif
2015#ifdef ENOSR
2016 {ENOSR, ALL},
2017#endif
2018 {ENXIO, ALL},
2019 {EROFS, ALL},
2020 {ETXTBSY, ALL},
2021#ifdef EAGAIN
2022 {EAGAIN, E_EXEC},
2023#endif
2024 {ENOMEM, ALL},
2025#ifdef ENOLINK
2026 {ENOLINK, ALL},
2027#endif
2028#ifdef EMULTIHOP
2029 {EMULTIHOP, ALL},
2030#endif
2031#ifdef ECOMM
2032 {ECOMM, ALL},
2033#endif
2034#ifdef ESTALE
2035 {ESTALE, ALL},
2036#endif
2037#ifdef ETIMEDOUT
2038 {ETIMEDOUT, ALL},
2039#endif
2040#ifdef ELOOP
2041 {ELOOP, ALL},
2042#endif
2043 {E2BIG, E_EXEC},
2044#ifdef ELIBACC
2045 {ELIBACC, E_EXEC},
2046#endif
2047};
2048 2636
2049#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
2050 2637
2051/* 2638/*
2052 * Return a string describing an error. The returned string may be a 2639 * Return a string describing an error. The returned string may be a
@@ -2054,57 +2641,47 @@ static const struct errname errormsg[] = {
2054 * Action describes the operation that got the error. 2641 * Action describes the operation that got the error.
2055 */ 2642 */
2056 2643
2057static const char *errmsg(int e, int action) 2644static const char *
2645errmsg(int e, const char *em)
2058{ 2646{
2059 struct errname const *ep; 2647 if(e == ENOENT || e == ENOTDIR) {
2060 static char buf[12];
2061 2648
2062 for (ep = errormsg; ep < errormsg + ERRNAME_SIZE; ep++) { 2649 return em;
2063 if (ep->errcode == e && (ep->action & action) != 0)
2064 return strerror(e);
2065 } 2650 }
2066 2651 return strerror(e);
2067 snprintf(buf, sizeof buf, "error %d", e);
2068 return buf;
2069} 2652}
2070 2653
2071 2654
2072#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE 2655/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2073static void __inton()
2074{
2075 if (--suppressint == 0 && intpending) {
2076 onint();
2077 }
2078}
2079static void forceinton(void)
2080{
2081 suppressint = 0;
2082 if (intpending)
2083 onint();
2084}
2085#endif
2086
2087/* flags in argument to evaltree */
2088#define EV_EXIT 01 /* exit after evaluating tree */
2089#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2090#define EV_BACKCMD 04 /* command executing within back quotes */
2091 2656
2092static int evalskip; /* set if we are skipping commands */ 2657/*
2093static int skipcount; /* number of levels to skip */ 2658 * Evaluate a command.
2094static int loopnest; /* current loop nesting level */ 2659 */
2095static int funcnest; /* depth of function calls */
2096 2660
2661/* flags in argument to evaltree */
2662#define EV_EXIT 01 /* exit after evaluating tree */
2663#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2664#define EV_BACKCMD 04 /* command executing within back quotes */
2097 2665
2098static struct strlist *cmdenviron; /* environment for builtin command */
2099static int exitstatus; /* exit status of last command */
2100static int oexitstatus; /* saved exit status */
2101 2666
2102static void evalsubshell(const union node *, int); 2667static void evalloop(union node *, int);
2668static void evalfor(union node *, int);
2669static void evalcase(union node *, int);
2670static void evalsubshell(union node *, int);
2103static void expredir(union node *); 2671static void expredir(union node *);
2672static void evalpipe(union node *, int);
2673static void evalcommand(union node *, int);
2674static int evalbltin(const struct builtincmd *, int, char **);
2675static int evalfun(struct funcnode *, int, char **, int);
2104static void prehash(union node *); 2676static void prehash(union node *);
2105static void eprintlist(struct strlist *); 2677static int eprintlist(struct strlist *, int);
2678static int bltincmd(int, char **);
2679
2680
2681static const struct builtincmd bltin = {
2682 "\0\0", bltincmd
2683};
2106 2684
2107static union node *parsecmd(int);
2108 2685
2109/* 2686/*
2110 * Called to reset things after an exception. 2687 * Called to reset things after an exception.
@@ -2113,9 +2690,9 @@ static union node *parsecmd(int);
2113/* 2690/*
2114 * The eval commmand. 2691 * The eval commmand.
2115 */ 2692 */
2116static void evalstring(char *, int);
2117 2693
2118static int evalcmd(int argc, char **argv) 2694static int
2695evalcmd(int argc, char **argv)
2119{ 2696{
2120 char *p; 2697 char *p;
2121 char *concat; 2698 char *concat;
@@ -2127,8 +2704,7 @@ static int evalcmd(int argc, char **argv)
2127 STARTSTACKSTR(concat); 2704 STARTSTACKSTR(concat);
2128 ap = argv + 2; 2705 ap = argv + 2;
2129 for (;;) { 2706 for (;;) {
2130 while (*p) 2707 concat = stputs(p, concat);
2131 STPUTC(*p++, concat);
2132 if ((p = *ap++) == NULL) 2708 if ((p = *ap++) == NULL)
2133 break; 2709 break;
2134 STPUTC(' ', concat); 2710 STPUTC(' ', concat);
@@ -2141,79 +2717,154 @@ static int evalcmd(int argc, char **argv)
2141 return exitstatus; 2717 return exitstatus;
2142} 2718}
2143 2719
2720
2144/* 2721/*
2145 * Execute a command or commands contained in a string. 2722 * Execute a command or commands contained in a string.
2146 */ 2723 */
2147 2724
2148static void evaltree(union node *, int); 2725static void
2149static void setinputstring(char *); 2726evalstring(char *s, int flag)
2150static void popfile(void);
2151static void setstackmark(struct stackmark *mark);
2152static void popstackmark(struct stackmark *mark);
2153
2154
2155static void evalstring(char *s, int flag)
2156{ 2727{
2157 union node *n; 2728 union node *n;
2158 struct stackmark smark; 2729 struct stackmark smark;
2159 2730
2160 setstackmark(&smark); 2731 setstackmark(&smark);
2161 setinputstring(s); 2732 setinputstring(s);
2733
2162 while ((n = parsecmd(0)) != NEOF) { 2734 while ((n = parsecmd(0)) != NEOF) {
2163 evaltree(n, flag); 2735 evaltree(n, flag);
2164 popstackmark(&smark); 2736 popstackmark(&smark);
2737 if (evalskip)
2738 break;
2165 } 2739 }
2166 popfile(); 2740 popfile();
2167 popstackmark(&smark); 2741 popstackmark(&smark);
2168} 2742}
2169 2743
2170static struct builtincmd *find_builtin(const char *); 2744
2171static void expandarg(union node *, struct arglist *, int);
2172static void calcsize(const union node *);
2173static union node *copynode(const union node *);
2174 2745
2175/* 2746/*
2176 * Make a copy of a parse tree. 2747 * Evaluate a parse tree. The value is left in the global variable
2748 * exitstatus.
2177 */ 2749 */
2178 2750
2179static int funcblocksize; /* size of structures in function */ 2751static void
2180static int funcstringsize; /* size of strings in node */ 2752evaltree(union node *n, int flags)
2181static pointer funcblock; /* block to allocate function from */
2182static char *funcstring; /* block to allocate strings from */
2183
2184
2185static inline union node *copyfunc(union node *n)
2186{ 2753{
2187 if (n == NULL) 2754 int checkexit = 0;
2188 return NULL; 2755 void (*evalfn)(union node *, int);
2189 funcblocksize = 0; 2756 unsigned isor;
2190 funcstringsize = 0; 2757 int status;
2191 calcsize(n); 2758 if (n == NULL) {
2192 funcblock = xmalloc(funcblocksize + funcstringsize); 2759 TRACE(("evaltree(NULL) called\n"));
2193 funcstring = (char *) funcblock + funcblocksize; 2760 goto out;
2194 return copynode(n); 2761 }
2762 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2763 getpid(), n, n->type, flags));
2764 switch (n->type) {
2765 default:
2766#ifdef DEBUG
2767 out1fmt("Node type = %d\n", n->type);
2768 flushout(stdout);
2769 break;
2770#endif
2771 case NNOT:
2772 evaltree(n->nnot.com, EV_TESTED);
2773 status = !exitstatus;
2774 goto setstatus;
2775 case NREDIR:
2776 expredir(n->nredir.redirect);
2777 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2778 if (!status) {
2779 evaltree(n->nredir.n, flags & EV_TESTED);
2780 status = exitstatus;
2781 }
2782 popredir(0);
2783 goto setstatus;
2784 case NCMD:
2785 evalfn = evalcommand;
2786checkexit:
2787 if (eflag && !(flags & EV_TESTED))
2788 checkexit = ~0;
2789 goto calleval;
2790 case NFOR:
2791 evalfn = evalfor;
2792 goto calleval;
2793 case NWHILE:
2794 case NUNTIL:
2795 evalfn = evalloop;
2796 goto calleval;
2797 case NSUBSHELL:
2798 case NBACKGND:
2799 evalfn = evalsubshell;
2800 goto calleval;
2801 case NPIPE:
2802 evalfn = evalpipe;
2803 goto checkexit;
2804 case NCASE:
2805 evalfn = evalcase;
2806 goto calleval;
2807 case NAND:
2808 case NOR:
2809 case NSEMI:
2810#if NAND + 1 != NOR
2811#error NAND + 1 != NOR
2812#endif
2813#if NOR + 1 != NSEMI
2814#error NOR + 1 != NSEMI
2815#endif
2816 isor = n->type - NAND;
2817 evaltree(
2818 n->nbinary.ch1,
2819 (flags | ((isor >> 1) - 1)) & EV_TESTED
2820 );
2821 if (!exitstatus == isor)
2822 break;
2823 if (!evalskip) {
2824 n = n->nbinary.ch2;
2825evaln:
2826 evalfn = evaltree;
2827calleval:
2828 evalfn(n, flags);
2829 break;
2830 }
2831 break;
2832 case NIF:
2833 evaltree(n->nif.test, EV_TESTED);
2834 if (evalskip)
2835 break;
2836 if (exitstatus == 0) {
2837 n = n->nif.ifpart;
2838 goto evaln;
2839 } else if (n->nif.elsepart) {
2840 n = n->nif.elsepart;
2841 goto evaln;
2842 }
2843 goto success;
2844 case NDEFUN:
2845 defun(n->narg.text, n->narg.next);
2846success:
2847 status = 0;
2848setstatus:
2849 exitstatus = status;
2850 break;
2851 }
2852out:
2853 if (pendingsigs)
2854 dotrap();
2855 if (flags & EV_EXIT || checkexit & exitstatus)
2856 exraise(EXEXIT);
2195} 2857}
2196 2858
2197/*
2198 * Add a new command entry, replacing any existing command entry for
2199 * the same name.
2200 */
2201 2859
2202static inline void addcmdentry(char *name, struct cmdentry *entry) 2860#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2203{ 2861static
2204 struct tblentry *cmdp; 2862#endif
2863void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2205 2864
2206 INTOFF;
2207 cmdp = cmdlookup(name, 1);
2208 if (cmdp->cmdtype == CMDFUNCTION) {
2209 free(cmdp->param.func);
2210 }
2211 cmdp->cmdtype = entry->cmdtype;
2212 cmdp->param = entry->u;
2213 INTON;
2214}
2215 2865
2216static inline void evalloop(const union node *n, int flags) 2866static void
2867evalloop(union node *n, int flags)
2217{ 2868{
2218 int status; 2869 int status;
2219 2870
@@ -2221,9 +2872,11 @@ static inline void evalloop(const union node *n, int flags)
2221 status = 0; 2872 status = 0;
2222 flags &= EV_TESTED; 2873 flags &= EV_TESTED;
2223 for (;;) { 2874 for (;;) {
2875 int i;
2876
2224 evaltree(n->nbinary.ch1, EV_TESTED); 2877 evaltree(n->nbinary.ch1, EV_TESTED);
2225 if (evalskip) { 2878 if (evalskip) {
2226 skipping:if (evalskip == SKIPCONT && --skipcount <= 0) { 2879skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2227 evalskip = 0; 2880 evalskip = 0;
2228 continue; 2881 continue;
2229 } 2882 }
@@ -2231,13 +2884,11 @@ static inline void evalloop(const union node *n, int flags)
2231 evalskip = 0; 2884 evalskip = 0;
2232 break; 2885 break;
2233 } 2886 }
2234 if (n->type == NWHILE) { 2887 i = exitstatus;
2235 if (exitstatus != 0) 2888 if (n->type != NWHILE)
2236 break; 2889 i = !i;
2237 } else { 2890 if (i != 0)
2238 if (exitstatus == 0) 2891 break;
2239 break;
2240 }
2241 evaltree(n->nbinary.ch2, flags); 2892 evaltree(n->nbinary.ch2, flags);
2242 status = exitstatus; 2893 status = exitstatus;
2243 if (evalskip) 2894 if (evalskip)
@@ -2247,7 +2898,10 @@ static inline void evalloop(const union node *n, int flags)
2247 exitstatus = status; 2898 exitstatus = status;
2248} 2899}
2249 2900
2250static void evalfor(const union node *n, int flags) 2901
2902
2903static void
2904evalfor(union node *n, int flags)
2251{ 2905{
2252 struct arglist arglist; 2906 struct arglist arglist;
2253 union node *argp; 2907 union node *argp;
@@ -2256,9 +2910,9 @@ static void evalfor(const union node *n, int flags)
2256 2910
2257 setstackmark(&smark); 2911 setstackmark(&smark);
2258 arglist.lastp = &arglist.list; 2912 arglist.lastp = &arglist.list;
2259 for (argp = n->nfor.args; argp; argp = argp->narg.next) { 2913 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2260 oexitstatus = exitstatus;
2261 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); 2914 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2915 /* XXX */
2262 if (evalskip) 2916 if (evalskip)
2263 goto out; 2917 goto out;
2264 } 2918 }
@@ -2267,7 +2921,7 @@ static void evalfor(const union node *n, int flags)
2267 exitstatus = 0; 2921 exitstatus = 0;
2268 loopnest++; 2922 loopnest++;
2269 flags &= EV_TESTED; 2923 flags &= EV_TESTED;
2270 for (sp = arglist.list; sp; sp = sp->next) { 2924 for (sp = arglist.list ; sp ; sp = sp->next) {
2271 setvar(n->nfor.var, sp->text, 0); 2925 setvar(n->nfor.var, sp->text, 0);
2272 evaltree(n->nfor.body, flags); 2926 evaltree(n->nfor.body, flags);
2273 if (evalskip) { 2927 if (evalskip) {
@@ -2281,11 +2935,14 @@ static void evalfor(const union node *n, int flags)
2281 } 2935 }
2282 } 2936 }
2283 loopnest--; 2937 loopnest--;
2284 out: 2938out:
2285 popstackmark(&smark); 2939 popstackmark(&smark);
2286} 2940}
2287 2941
2288static inline void evalcase(const union node *n, int flags) 2942
2943
2944static void
2945evalcase(union node *n, int flags)
2289{ 2946{
2290 union node *cp; 2947 union node *cp;
2291 union node *patp; 2948 union node *patp;
@@ -2294,10 +2951,10 @@ static inline void evalcase(const union node *n, int flags)
2294 2951
2295 setstackmark(&smark); 2952 setstackmark(&smark);
2296 arglist.lastp = &arglist.list; 2953 arglist.lastp = &arglist.list;
2297 oexitstatus = exitstatus;
2298 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 2954 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2299 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) { 2955 exitstatus = 0;
2300 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) { 2956 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2957 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2301 if (casematch(patp, arglist.list->text)) { 2958 if (casematch(patp, arglist.list->text)) {
2302 if (evalskip == 0) { 2959 if (evalskip == 0) {
2303 evaltree(cp->nclist.body, flags); 2960 evaltree(cp->nclist.body, flags);
@@ -2306,10 +2963,81 @@ static inline void evalcase(const union node *n, int flags)
2306 } 2963 }
2307 } 2964 }
2308 } 2965 }
2309 out: 2966out:
2310 popstackmark(&smark); 2967 popstackmark(&smark);
2311} 2968}
2312 2969
2970
2971
2972/*
2973 * Kick off a subshell to evaluate a tree.
2974 */
2975
2976static void
2977evalsubshell(union node *n, int flags)
2978{
2979 struct job *jp;
2980 int backgnd = (n->type == NBACKGND);
2981 int status;
2982
2983 expredir(n->nredir.redirect);
2984 if (!backgnd && flags & EV_EXIT && !trap[0])
2985 goto nofork;
2986 INTOFF;
2987 jp = makejob(n, 1);
2988 if (forkshell(jp, n, backgnd) == 0) {
2989 INTON;
2990 flags |= EV_EXIT;
2991 if (backgnd)
2992 flags &=~ EV_TESTED;
2993nofork:
2994 redirect(n->nredir.redirect, 0);
2995 evaltreenr(n->nredir.n, flags);
2996 /* never returns */
2997 }
2998 status = 0;
2999 if (! backgnd)
3000 status = waitforjob(jp);
3001 exitstatus = status;
3002 INTON;
3003}
3004
3005
3006
3007/*
3008 * Compute the names of the files in a redirection list.
3009 */
3010
3011static void
3012expredir(union node *n)
3013{
3014 union node *redir;
3015
3016 for (redir = n ; redir ; redir = redir->nfile.next) {
3017 struct arglist fn;
3018 fn.lastp = &fn.list;
3019 switch (redir->type) {
3020 case NFROMTO:
3021 case NFROM:
3022 case NTO:
3023 case NCLOBBER:
3024 case NAPPEND:
3025 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3026 redir->nfile.expfname = fn.list->text;
3027 break;
3028 case NFROMFD:
3029 case NTOFD:
3030 if (redir->ndup.vname) {
3031 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3032 fixredir(redir, fn.list->text, 1);
3033 }
3034 break;
3035 }
3036 }
3037}
3038
3039
3040
2313/* 3041/*
2314 * Evaluate a pipeline. All the processes in the pipeline are children 3042 * Evaluate a pipeline. All the processes in the pipeline are children
2315 * of the process creating the pipeline. (This differs from some versions 3043 * of the process creating the pipeline. (This differs from some versions
@@ -2317,7 +3045,8 @@ static inline void evalcase(const union node *n, int flags)
2317 * of all the rest.) 3045 * of all the rest.)
2318 */ 3046 */
2319 3047
2320static inline void evalpipe(union node *n, int flags) 3048static void
3049evalpipe(union node *n, int flags)
2321{ 3050{
2322 struct job *jp; 3051 struct job *jp;
2323 struct nodelist *lp; 3052 struct nodelist *lp;
@@ -2325,15 +3054,15 @@ static inline void evalpipe(union node *n, int flags)
2325 int prevfd; 3054 int prevfd;
2326 int pip[2]; 3055 int pip[2];
2327 3056
2328 TRACE(("evalpipe(0x%lx) called\n", (long) n)); 3057 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2329 pipelen = 0; 3058 pipelen = 0;
2330 for (lp = n->npipe.cmdlist; lp; lp = lp->next) 3059 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2331 pipelen++; 3060 pipelen++;
2332 flags |= EV_EXIT; 3061 flags |= EV_EXIT;
2333 INTOFF; 3062 INTOFF;
2334 jp = makejob(n, pipelen); 3063 jp = makejob(n, pipelen);
2335 prevfd = -1; 3064 prevfd = -1;
2336 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 3065 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2337 prehash(lp->n); 3066 prehash(lp->n);
2338 pip[1] = -1; 3067 pip[1] = -1;
2339 if (lp->next) { 3068 if (lp->next) {
@@ -2355,7 +3084,8 @@ static inline void evalpipe(union node *n, int flags)
2355 dup2(pip[1], 1); 3084 dup2(pip[1], 1);
2356 close(pip[1]); 3085 close(pip[1]);
2357 } 3086 }
2358 evaltree(lp->n, flags); 3087 evaltreenr(lp->n, flags);
3088 /* never returns */
2359 } 3089 }
2360 if (prevfd >= 0) 3090 if (prevfd >= 0)
2361 close(prevfd); 3091 close(prevfd);
@@ -2369,21 +3099,101 @@ static inline void evalpipe(union node *n, int flags)
2369 INTON; 3099 INTON;
2370} 3100}
2371 3101
2372static void find_command(const char *, struct cmdentry *, int, const char *);
2373 3102
2374static int isassignment(const char *word) 3103
3104/*
3105 * Execute a command inside back quotes. If it's a builtin command, we
3106 * want to save its output in a block obtained from malloc. Otherwise
3107 * we fork off a subprocess and get the output of the command via a pipe.
3108 * Should be called with interrupts off.
3109 */
3110
3111static void
3112evalbackcmd(union node *n, struct backcmd *result)
2375{ 3113{
2376 if (!is_name(*word)) { 3114 int saveherefd;
2377 return 0; 3115
3116 result->fd = -1;
3117 result->buf = NULL;
3118 result->nleft = 0;
3119 result->jp = NULL;
3120 if (n == NULL) {
3121 goto out;
2378 } 3122 }
2379 do { 3123
2380 word++; 3124 saveherefd = herefd;
2381 } while (is_in_name(*word)); 3125 herefd = -1;
2382 return *word == '='; 3126
3127 {
3128 int pip[2];
3129 struct job *jp;
3130
3131 if (pipe(pip) < 0)
3132 error("Pipe call failed");
3133 jp = makejob(n, 1);
3134 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3135 FORCEINTON;
3136 close(pip[0]);
3137 if (pip[1] != 1) {
3138 close(1);
3139 copyfd(pip[1], 1);
3140 close(pip[1]);
3141 }
3142 eflag = 0;
3143 evaltreenr(n, EV_EXIT);
3144 /* NOTREACHED */
3145 }
3146 close(pip[1]);
3147 result->fd = pip[0];
3148 result->jp = jp;
3149 }
3150 herefd = saveherefd;
3151out:
3152 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3153 result->fd, result->buf, result->nleft, result->jp));
3154}
3155
3156#ifdef CONFIG_ASH_CMDCMD
3157static inline char **
3158parse_command_args(char **argv, const char **path)
3159{
3160 char *cp, c;
3161
3162 for (;;) {
3163 cp = *++argv;
3164 if (!cp)
3165 return 0;
3166 if (*cp++ != '-')
3167 break;
3168 if (!(c = *cp++))
3169 break;
3170 if (c == '-' && !*cp) {
3171 argv++;
3172 break;
3173 }
3174 do {
3175 switch (c) {
3176 case 'p':
3177 *path = defpath;
3178 break;
3179 default:
3180 /* run 'typecmd' for other options */
3181 return 0;
3182 }
3183 } while ((c = *cp++));
3184 }
3185 return argv;
2383} 3186}
3187#endif
2384 3188
2385 3189
2386static void evalcommand(union node *cmd, int flags) 3190
3191/*
3192 * Execute a simple command.
3193 */
3194
3195static void
3196evalcommand(union node *cmd, int flags)
2387{ 3197{
2388 struct stackmark smark; 3198 struct stackmark smark;
2389 union node *argp; 3199 union node *argp;
@@ -2391,562 +3201,312 @@ static void evalcommand(union node *cmd, int flags)
2391 struct arglist varlist; 3201 struct arglist varlist;
2392 char **argv; 3202 char **argv;
2393 int argc; 3203 int argc;
2394 char **envp;
2395 struct strlist *sp; 3204 struct strlist *sp;
2396 int mode;
2397 struct cmdentry cmdentry; 3205 struct cmdentry cmdentry;
2398 struct job *jp; 3206 struct job *jp;
2399 char *volatile savecmdname;
2400 volatile struct shparam saveparam;
2401 struct localvar *volatile savelocalvars;
2402 volatile int e;
2403 char *lastarg; 3207 char *lastarg;
2404 const char *path; 3208 const char *path;
2405 int spclbltin; 3209 int spclbltin;
2406 struct jmploc *volatile savehandler; 3210 int cmd_is_exec;
2407 struct jmploc jmploc; 3211 int status;
2408 3212 char **nargv;
2409#if __GNUC__
2410 /* Avoid longjmp clobbering */
2411 (void) &argv;
2412 (void) &argc;
2413 (void) &lastarg;
2414 (void) &flags;
2415 (void) &spclbltin;
2416#endif
2417 3213
2418 /* First expand the arguments. */ 3214 /* First expand the arguments. */
2419 TRACE(("evalcommand(0x%lx, %d) called\n", (long) cmd, flags)); 3215 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2420 setstackmark(&smark); 3216 setstackmark(&smark);
2421 arglist.lastp = &arglist.list; 3217 back_exitstatus = 0;
2422 varlist.lastp = &varlist.list;
2423 arglist.list = 0;
2424 oexitstatus = exitstatus;
2425 exitstatus = 0;
2426 path = pathval();
2427 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2428 expandarg(argp, &varlist, EXP_VARTILDE);
2429 }
2430 for (argp = cmd->ncmd.args; argp && !arglist.list; argp = argp->narg.next) {
2431 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2432 }
2433 if (argp) {
2434 struct builtincmd *bcmd;
2435 int pseudovarflag;
2436 3218
2437 bcmd = find_builtin(arglist.list->text); 3219 cmdentry.cmdtype = CMDBUILTIN;
2438 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 3220 cmdentry.u.cmd = &bltin;
2439 for (; argp; argp = argp->narg.next) { 3221 varlist.lastp = &varlist.list;
2440 if (pseudovarflag && isassignment(argp->narg.text)) {
2441 expandarg(argp, &arglist, EXP_VARTILDE);
2442 continue;
2443 }
2444 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2445 }
2446 }
2447 *arglist.lastp = NULL;
2448 *varlist.lastp = NULL; 3222 *varlist.lastp = NULL;
2449 expredir(cmd->ncmd.redirect); 3223 arglist.lastp = &arglist.list;
3224 *arglist.lastp = NULL;
3225
2450 argc = 0; 3226 argc = 0;
2451 for (sp = arglist.list; sp; sp = sp->next) 3227 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
2452 argc++; 3228 struct strlist **spp;
2453 argv = stalloc(sizeof(char *) * (argc + 1));
2454 3229
2455 for (sp = arglist.list; sp; sp = sp->next) { 3230 spp = arglist.lastp;
3231 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3232 for (sp = *spp; sp; sp = sp->next)
3233 argc++;
3234 }
3235
3236 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3237 for (sp = arglist.list ; sp ; sp = sp->next) {
2456 TRACE(("evalcommand arg: %s\n", sp->text)); 3238 TRACE(("evalcommand arg: %s\n", sp->text));
2457 *argv++ = sp->text; 3239 *nargv++ = sp->text;
2458 } 3240 }
2459 *argv = NULL; 3241 *nargv = NULL;
3242
2460 lastarg = NULL; 3243 lastarg = NULL;
2461 if (iflag && funcnest == 0 && argc > 0) 3244 if (iflag && funcnest == 0 && argc > 0)
2462 lastarg = argv[-1]; 3245 lastarg = nargv[-1];
2463 argv -= argc; 3246
3247 expredir(cmd->ncmd.redirect);
3248 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH);
3249
3250 path = vpath.text;
3251 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3252 struct strlist **spp;
3253 char *p;
3254
3255 spp = varlist.lastp;
3256 expandarg(argp, &varlist, EXP_VARTILDE);
3257
3258 /*
3259 * Modify the command lookup path, if a PATH= assignment
3260 * is present
3261 */
3262 p = (*spp)->text;
3263 if (varequal(p, path))
3264 path = p;
3265 }
2464 3266
2465 /* Print the command if xflag is set. */ 3267 /* Print the command if xflag is set. */
2466 if (xflag) { 3268 if (xflag) {
2467 out2c('+'); 3269 int sep;
2468 eprintlist(varlist.list); 3270
2469 eprintlist(arglist.list); 3271 out2str(ps4val());
3272 sep = 0;
3273 sep = eprintlist(varlist.list, sep);
3274 eprintlist(arglist.list, sep);
2470 out2c('\n'); 3275 out2c('\n');
3276 flushall();
2471 } 3277 }
2472 3278
3279 cmd_is_exec = 0;
3280 spclbltin = -1;
3281
2473 /* Now locate the command. */ 3282 /* Now locate the command. */
2474 if (argc == 0) { 3283 if (argc) {
2475 cmdentry.cmdtype = CMDBUILTIN;
2476 cmdentry.u.cmd = BLTINCMD;
2477 spclbltin = 1;
2478 } else {
2479 const char *oldpath; 3284 const char *oldpath;
2480 int findflag = DO_ERR; 3285 int cmd_flag = DO_ERR;
2481 int oldfindflag;
2482 3286
2483 /* 3287 path += 5;
2484 * Modify the command lookup path, if a PATH= assignment
2485 * is present
2486 */
2487 for (sp = varlist.list; sp; sp = sp->next)
2488 if (varequal(sp->text, defpathvar)) {
2489 path = sp->text + 5;
2490 findflag |= DO_BRUTE;
2491 }
2492 oldpath = path; 3288 oldpath = path;
2493 oldfindflag = findflag;
2494 spclbltin = -1;
2495 for (;;) { 3289 for (;;) {
2496 find_command(argv[0], &cmdentry, findflag, path); 3290 find_command(argv[0], &cmdentry, cmd_flag, path);
2497 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 3291 if (cmdentry.cmdtype == CMDUNKNOWN) {
2498 exitstatus = 127; 3292 status = 127;
2499 goto out; 3293 flushout(stderr);
3294 goto bail;
2500 } 3295 }
3296
2501 /* implement bltin and command here */ 3297 /* implement bltin and command here */
2502 if (cmdentry.cmdtype != CMDBUILTIN) { 3298 if (cmdentry.cmdtype != CMDBUILTIN)
3299 break;
3300 if (spclbltin < 0)
3301 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3302 if (cmdentry.u.cmd == EXECCMD)
3303 cmd_is_exec++;
3304#ifdef CONFIG_ASH_CMDCMD
3305 if (cmdentry.u.cmd == COMMANDCMD) {
3306
3307 path = oldpath;
3308 nargv = parse_command_args(argv, &path);
3309 if (!nargv)
3310 break;
3311 argc -= nargv - argv;
3312 argv = nargv;
3313 cmd_flag |= DO_NOFUNC;
3314 } else
3315#endif
2503 break; 3316 break;
2504 }
2505 if (spclbltin < 0) {
2506 spclbltin = !!(IS_BUILTIN_SPECIAL(cmdentry.u.cmd)) * 2;
2507 }
2508 if (cmdentry.u.cmd == BLTINCMD) {
2509 for (;;) {
2510 struct builtincmd *bcmd;
2511
2512 argv++;
2513 if (--argc == 0)
2514 goto found;
2515 if (!(bcmd = find_builtin(*argv))) {
2516 out2fmt("%s: not found\n", *argv);
2517 exitstatus = 127;
2518 goto out;
2519 }
2520 cmdentry.u.cmd = bcmd;
2521 if (bcmd != BLTINCMD)
2522 break;
2523 }
2524 }
2525 if (cmdentry.u.cmd == find_builtin("command")) {
2526 argv++;
2527 if (--argc == 0) {
2528 goto found;
2529 }
2530 if (*argv[0] == '-') {
2531 if (!equal(argv[0], "-p")) {
2532 argv--;
2533 argc++;
2534 break;
2535 }
2536 argv++;
2537 if (--argc == 0) {
2538 goto found;
2539 }
2540 path = defpath;
2541 findflag |= DO_BRUTE;
2542 } else {
2543 path = oldpath;
2544 findflag = oldfindflag;
2545 }
2546 findflag |= DO_NOFUN;
2547 continue;
2548 }
2549 found:
2550 break;
2551 } 3317 }
2552 } 3318 }
2553 3319
2554 /* Fork off a child process if necessary. */ 3320 if (status) {
2555 if (cmd->ncmd.backgnd 3321 /* We have a redirection error. */
2556 || (cmdentry.cmdtype == CMDNORMAL && (!(flags & EV_EXIT) || trap[0])) 3322 if (spclbltin > 0)
2557 ) { 3323 exraise(EXERROR);
2558 INTOFF; 3324bail:
2559 jp = makejob(cmd, 1); 3325 exitstatus = status;
2560 mode = cmd->ncmd.backgnd; 3326 goto out;
2561 if (forkshell(jp, cmd, mode) != 0)
2562 goto parent; /* at end of routine */
2563 FORCEINTON;
2564 flags |= EV_EXIT;
2565 } else {
2566 flags &= ~EV_EXIT;
2567 } 3327 }
2568 3328
2569 /* This is the child process if a fork occurred. */
2570 /* Execute the command. */ 3329 /* Execute the command. */
2571 if (cmdentry.cmdtype == CMDFUNCTION) { 3330 switch (cmdentry.cmdtype) {
2572#ifdef DEBUG 3331 default:
2573 trputs("Shell function: "); 3332 /* Fork off a child process if necessary. */
2574 trargs(argv); 3333 if (!(flags & EV_EXIT) || trap[0]) {
2575#endif 3334 INTOFF;
2576 exitstatus = oexitstatus; 3335 jp = makejob(cmd, 1);
2577 saveparam = shellparam; 3336 if (forkshell(jp, cmd, FORK_FG) != 0) {
2578 shellparam.malloc = 0; 3337 exitstatus = waitforjob(jp);
2579 shellparam.nparam = argc - 1; 3338 INTON;
2580 shellparam.p = argv + 1; 3339 break;
2581 INTOFF;
2582 savelocalvars = localvars;
2583 localvars = NULL;
2584 INTON;
2585 if (setjmp(jmploc.loc)) {
2586 if (exception == EXREDIR) {
2587 exitstatus = 2;
2588 goto funcdone;
2589 } 3340 }
2590 saveparam.optind = shellparam.optind; 3341 FORCEINTON;
2591 saveparam.optoff = shellparam.optoff;
2592 freeparam(&shellparam);
2593 shellparam = saveparam;
2594 poplocalvars();
2595 localvars = savelocalvars;
2596 handler = savehandler;
2597 longjmp(handler->loc, 1);
2598 }
2599 savehandler = handler;
2600 handler = &jmploc;
2601 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2602 listsetvar(varlist.list);
2603 funcnest++;
2604 evaltree(cmdentry.u.func, flags & EV_TESTED);
2605 funcnest--;
2606 funcdone:
2607 INTOFF;
2608 poplocalvars();
2609 localvars = savelocalvars;
2610 saveparam.optind = shellparam.optind;
2611 saveparam.optoff = shellparam.optoff;
2612 freeparam(&shellparam);
2613 shellparam = saveparam;
2614 handler = savehandler;
2615 popredir();
2616 INTON;
2617 if (evalskip == SKIPFUNC) {
2618 evalskip = 0;
2619 skipcount = 0;
2620 } 3342 }
2621 } else if (cmdentry.cmdtype == CMDBUILTIN) { 3343 listsetvar(varlist.list, VEXPORT|VSTACK);
2622 int redir; 3344 shellexec(argv, path, cmdentry.u.index);
3345 /* NOTREACHED */
2623 3346
2624#ifdef DEBUG 3347 case CMDBUILTIN:
2625 trputs("builtin command: "); 3348 cmdenviron = varlist.list;
2626 trargs(argv); 3349 if (cmdenviron) {
2627#endif 3350 struct strlist *list = cmdenviron;
2628 redir = (cmdentry.u.cmd == EXECCMD) ? 0 : REDIR_PUSH; 3351 int i = VNOSET;
2629 savecmdname = commandname; 3352 if (spclbltin > 0 || argc == 0) {
2630 if (spclbltin) { 3353 i = 0;
2631 listsetvar(varlist.list); 3354 if (cmd_is_exec && argc > 1)
2632 } else { 3355 i = VEXPORT;
2633 cmdenviron = varlist.list; 3356 }
2634 } 3357 listsetvar(list, i);
2635 e = -1; 3358 }
2636 if (setjmp(jmploc.loc)) { 3359 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
2637 e = exception; 3360 int exit_status;
2638 exitstatus = (e == EXINT) ? SIGINT + 128 : 2; 3361 int i, j;
2639 goto cmddone; 3362
2640 } 3363 i = exception;
2641 savehandler = handler; 3364 if (i == EXEXIT)
2642 handler = &jmploc; 3365 goto raise;
2643 redirect(cmd->ncmd.redirect, redir); 3366
2644 commandname = argv[0]; 3367 exit_status = 2;
2645 argptr = argv + 1; 3368 j = 0;
2646 optptr = NULL; /* initialize nextopt */ 3369 if (i == EXINT)
2647 exitstatus = (*cmdentry.u.cmd->builtinfunc) (argc, argv); 3370 j = SIGINT;
2648 flushall(); 3371 if (i == EXSIG)
2649 cmddone: 3372 j = pendingsigs;
2650 cmdenviron = NULL; 3373 if (j)
2651 commandname = savecmdname; 3374 exit_status = j + 128;
2652 handler = savehandler; 3375 exitstatus = exit_status;
2653 if (e != -1) { 3376
2654 if (e == EXINT || spclbltin & 2) { 3377 if (i == EXINT || spclbltin > 0) {
2655 if (e == EXREDIR) 3378raise:
2656 exraise(e); 3379 longjmp(handler->loc, 1);
2657 } 3380 }
2658 FORCEINTON; 3381 FORCEINTON;
2659 } 3382 }
2660 if (cmdentry.u.cmd != EXECCMD) 3383 break;
2661 popredir();
2662 } else {
2663#ifdef DEBUG
2664 trputs("normal command: ");
2665 trargs(argv);
2666#endif
2667 redirect(cmd->ncmd.redirect, 0);
2668 clearredir();
2669 for (sp = varlist.list; sp; sp = sp->next)
2670 setvareq(sp->text, VEXPORT | VSTACK);
2671 envp = environment();
2672 shellexec(argv, envp, path, cmdentry.u.index);
2673 }
2674 if (flags & EV_EXIT)
2675 exitshell(exitstatus);
2676 goto out;
2677 3384
2678 parent: /* parent process gets here (if we forked) */ 3385 case CMDFUNCTION:
2679 if (mode == 0) { /* argument to fork */ 3386 listsetvar(varlist.list, 0);
2680 exitstatus = waitforjob(jp); 3387 if (evalfun(cmdentry.u.func, argc, argv, flags))
3388 goto raise;
3389 break;
2681 } 3390 }
2682 INTON;
2683 3391
2684 out: 3392out:
3393 popredir(cmd_is_exec);
2685 if (lastarg) 3394 if (lastarg)
3395 /* dsl: I think this is intended to be used to support
3396 * '_' in 'vi' command mode during line editing...
3397 * However I implemented that within libedit itself.
3398 */
2686 setvar("_", lastarg, 0); 3399 setvar("_", lastarg, 0);
2687 popstackmark(&smark); 3400 popstackmark(&smark);
2688} 3401}
2689 3402
2690/* 3403static int
2691 * Evaluate a parse tree. The value is left in the global variable 3404evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
2692 * exitstatus. 3405 char *volatile savecmdname;
2693 */ 3406 struct jmploc *volatile savehandler;
2694static void evaltree(union node *n, int flags) 3407 struct jmploc jmploc;
2695{ 3408 int i;
2696 int checkexit = 0;
2697
2698 if (n == NULL) {
2699 TRACE(("evaltree(NULL) called\n"));
2700 goto out;
2701 }
2702 TRACE(("evaltree(0x%lx: %d) called\n", (long) n, n->type));
2703 switch (n->type) {
2704 case NSEMI:
2705 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2706 if (evalskip)
2707 goto out;
2708 evaltree(n->nbinary.ch2, flags);
2709 break;
2710 case NAND:
2711 evaltree(n->nbinary.ch1, EV_TESTED);
2712 if (evalskip || exitstatus != 0)
2713 goto out;
2714 evaltree(n->nbinary.ch2, flags);
2715 break;
2716 case NOR:
2717 evaltree(n->nbinary.ch1, EV_TESTED);
2718 if (evalskip || exitstatus == 0)
2719 goto out;
2720 evaltree(n->nbinary.ch2, flags);
2721 break;
2722 case NREDIR:
2723 expredir(n->nredir.redirect);
2724 redirect(n->nredir.redirect, REDIR_PUSH);
2725 evaltree(n->nredir.n, flags);
2726 popredir();
2727 break;
2728 case NSUBSHELL:
2729 evalsubshell(n, flags);
2730 break;
2731 case NBACKGND:
2732 evalsubshell(n, flags);
2733 break;
2734 case NIF:{
2735 evaltree(n->nif.test, EV_TESTED);
2736 if (evalskip)
2737 goto out;
2738 if (exitstatus == 0)
2739 evaltree(n->nif.ifpart, flags);
2740 else if (n->nif.elsepart)
2741 evaltree(n->nif.elsepart, flags);
2742 else
2743 exitstatus = 0;
2744 break;
2745 }
2746 case NWHILE:
2747 case NUNTIL:
2748 evalloop(n, flags);
2749 break;
2750 case NFOR:
2751 evalfor(n, flags);
2752 break;
2753 case NCASE:
2754 evalcase(n, flags);
2755 break;
2756 case NDEFUN:{
2757 struct builtincmd *bcmd;
2758 struct cmdentry entry;
2759 3409
2760 if ((bcmd = find_builtin(n->narg.text)) && IS_BUILTIN_SPECIAL(bcmd) 3410 savecmdname = commandname;
2761 ) { 3411 if ((i = setjmp(jmploc.loc)))
2762 out2fmt("%s is a special built-in\n", n->narg.text); 3412 goto cmddone;
2763 exitstatus = 1; 3413 savehandler = handler;
2764 break; 3414 handler = &jmploc;
2765 } 3415 commandname = argv[0];
2766 entry.cmdtype = CMDFUNCTION; 3416 argptr = argv + 1;
2767 entry.u.func = copyfunc(n->narg.next); 3417 optptr = NULL; /* initialize nextopt */
2768 addcmdentry(n->narg.text, &entry); 3418 exitstatus = (*cmd->builtin)(argc, argv);
2769 exitstatus = 0; 3419 flushall();
2770 break; 3420cmddone:
2771 } 3421 exitstatus |= outerr(stdout);
2772 case NNOT: 3422 commandname = savecmdname;
2773 evaltree(n->nnot.com, EV_TESTED); 3423 exsig = 0;
2774 exitstatus = !exitstatus; 3424 handler = savehandler;
2775 break;
2776 3425
2777 case NPIPE: 3426 return i;
2778 evalpipe(n, flags);
2779 checkexit = 1;
2780 break;
2781 case NCMD:
2782 evalcommand(n, flags);
2783 checkexit = 1;
2784 break;
2785#ifdef DEBUG
2786 default:
2787 printf("Node type = %d\n", n->type);
2788 break;
2789#endif
2790 }
2791 out:
2792 if (pendingsigs)
2793 dotrap();
2794 if (flags & EV_EXIT ||
2795 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2796 )
2797 exitshell(exitstatus);
2798} 3427}
2799 3428
2800/* 3429static int
2801 * Kick off a subshell to evaluate a tree. 3430evalfun(struct funcnode *func, int argc, char **argv, int flags)
2802 */
2803
2804static void evalsubshell(const union node *n, int flags)
2805{ 3431{
2806 struct job *jp = 0; 3432 volatile struct shparam saveparam;
2807 int backgnd = (n->type == NBACKGND); 3433 struct localvar *volatile savelocalvars;
3434 struct jmploc *volatile savehandler;
3435 struct jmploc jmploc;
3436 int e;
2808 3437
2809 expredir(n->nredir.redirect); 3438 saveparam = shellparam;
2810 if (!backgnd && flags & EV_EXIT && !trap[0]) 3439 savelocalvars = localvars;
2811 goto nofork; 3440 if ((e = setjmp(jmploc.loc))) {
2812 INTOFF; 3441 goto funcdone;
2813 jp = makejob(n, 1);
2814 if (forkshell(jp, n, backgnd) == 0) {
2815 INTON;
2816 flags |= EV_EXIT;
2817 if (backgnd)
2818 flags &= ~EV_TESTED;
2819 nofork:
2820 redirect(n->nredir.redirect, 0);
2821 evaltree(n->nredir.n, flags); /* never returns */
2822 }
2823 if (!backgnd) {
2824 exitstatus = waitforjob(jp);
2825 } 3442 }
3443 INTOFF;
3444 savehandler = handler;
3445 handler = &jmploc;
3446 localvars = NULL;
3447 shellparam.malloc = 0;
3448 func->count++;
2826 INTON; 3449 INTON;
2827} 3450 shellparam.nparam = argc - 1;
2828 3451 shellparam.p = argv + 1;
2829/* 3452#ifdef CONFIG_ASH_GETOPTS
2830 * Compute the names of the files in a redirection list. 3453 shellparam.optind = 1;
2831 */ 3454 shellparam.optoff = -1;
2832 3455#endif
2833static void fixredir(union node *n, const char *text, int err); 3456 funcnest++;
2834 3457 evaltree(&func->n, flags & EV_TESTED);
2835static void expredir(union node *n) 3458 funcnest--;
2836{ 3459funcdone:
2837 union node *redir; 3460 INTOFF;
2838 3461 freefunc(func);
2839 for (redir = n; redir; redir = redir->nfile.next) { 3462 poplocalvars();
2840 struct arglist fn; 3463 localvars = savelocalvars;
2841 3464 freeparam(&shellparam);
2842 fn.lastp = &fn.list; 3465 shellparam = saveparam;
2843 oexitstatus = exitstatus; 3466 handler = savehandler;
2844 switch (redir->type) { 3467 INTON;
2845 case NFROMTO: 3468 if (evalskip == SKIPFUNC) {
2846 case NFROM: 3469 evalskip = 0;
2847 case NTO: 3470 skipcount = 0;
2848 case NAPPEND:
2849 case NTOOV:
2850 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2851 redir->nfile.expfname = fn.list->text;
2852 break;
2853 case NFROMFD:
2854 case NTOFD:
2855 if (redir->ndup.vname) {
2856 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2857 fixredir(redir, fn.list->text, 1);
2858 }
2859 break;
2860 }
2861 }
2862}
2863
2864
2865/*
2866 * Execute a command inside back quotes. If it's a builtin command, we
2867 * want to save its output in a block obtained from malloc. Otherwise
2868 * we fork off a subprocess and get the output of the command via a pipe.
2869 * Should be called with interrupts off.
2870 */
2871
2872static void evalbackcmd(union node *n, struct backcmd *result)
2873{
2874 int pip[2];
2875 struct job *jp;
2876 struct stackmark smark; /* unnecessary */
2877
2878 setstackmark(&smark);
2879 result->fd = -1;
2880 result->buf = NULL;
2881 result->nleft = 0;
2882 result->jp = NULL;
2883 if (n == NULL) {
2884 exitstatus = 0;
2885 goto out;
2886 }
2887 exitstatus = 0;
2888 if (pipe(pip) < 0)
2889 error("Pipe call failed");
2890 jp = makejob(n, 1);
2891 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2892 FORCEINTON;
2893 close(pip[0]);
2894 if (pip[1] != 1) {
2895 close(1);
2896 dup_as_newfd(pip[1], 1);
2897 close(pip[1]);
2898 }
2899 eflag = 0;
2900 evaltree(n, EV_EXIT);
2901 } 3471 }
2902 close(pip[1]); 3472 return e;
2903 result->fd = pip[0];
2904 result->jp = jp;
2905 out:
2906 popstackmark(&smark);
2907 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2908 result->fd, result->buf, result->nleft, result->jp));
2909} 3473}
2910 3474
2911 3475
2912/* 3476/*
2913 * Execute a simple command.
2914 */
2915
2916/*
2917 * Search for a command. This is called before we fork so that the 3477 * Search for a command. This is called before we fork so that the
2918 * location of the command will be available in the parent as well as 3478 * location of the command will be available in the parent as well as
2919 * the child. The check for "goodname" is an overly conservative 3479 * the child.
2920 * check that the name will not be subject to expansion.
2921 */ 3480 */
2922 3481
2923static void prehash(union node *n) 3482static void
3483prehash(union node *n)
2924{ 3484{
2925 struct cmdentry entry; 3485 struct cmdentry entry;
2926 3486
2927 if (n->type == NCMD && n->ncmd.args) 3487 if (n->type == NCMD && n->ncmd.args)
2928 if (goodname(n->ncmd.args->narg.text)) 3488 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
2929 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
2930} 3489}
2931 3490
2932 3491
3492
2933/* 3493/*
2934 * Builtin commands. Builtin commands whose functions are closely 3494 * Builtin commands. Builtin commands whose functions are closely
2935 * tied to evaluation are implemented here. 3495 * tied to evaluation are implemented here.
2936 */ 3496 */
2937 3497
2938/* 3498/*
2939 * No command given, or a bltin command with no arguments. Set the 3499 * No command given.
2940 * specified variables.
2941 */ 3500 */
2942 3501
2943int bltincmd(int argc, char **argv) 3502static int
3503bltincmd(int argc, char **argv)
2944{ 3504{
2945 /* 3505 /*
2946 * Preserve exitstatus of a previous possible redirection 3506 * Preserve exitstatus of a previous possible redirection
2947 * as POSIX mandates 3507 * as POSIX mandates
2948 */ 3508 */
2949 return exitstatus; 3509 return back_exitstatus;
2950} 3510}
2951 3511
2952 3512
@@ -2961,16 +3521,17 @@ int bltincmd(int argc, char **argv)
2961 * in the standard shell so we don't make it one here. 3521 * in the standard shell so we don't make it one here.
2962 */ 3522 */
2963 3523
2964static int breakcmd(int argc, char **argv) 3524static int
3525breakcmd(int argc, char **argv)
2965{ 3526{
2966 int n = argc > 1 ? number(argv[1]) : 1; 3527 int n = argc > 1 ? number(argv[1]) : 1;
2967 3528
2968 if (n <= 0) 3529 if (n <= 0)
2969 error("Illegal number: %s", argv[1]); 3530 error(illnum, argv[1]);
2970 if (n > loopnest) 3531 if (n > loopnest)
2971 n = loopnest; 3532 n = loopnest;
2972 if (n > 0) { 3533 if (n > 0) {
2973 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK; 3534 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
2974 skipcount = n; 3535 skipcount = n;
2975 } 3536 }
2976 return 0; 3537 return 0;
@@ -2981,15 +3542,17 @@ static int breakcmd(int argc, char **argv)
2981 * The return command. 3542 * The return command.
2982 */ 3543 */
2983 3544
2984static int returncmd(int argc, char **argv) 3545static int
3546returncmd(int argc, char **argv)
2985{ 3547{
2986 int ret = argc > 1 ? number(argv[1]) : oexitstatus; 3548 int ret = argc > 1 ? number(argv[1]) : exitstatus;
2987 3549
2988 if (funcnest) { 3550 if (funcnest) {
2989 evalskip = SKIPFUNC; 3551 evalskip = SKIPFUNC;
2990 skipcount = 1; 3552 skipcount = 1;
2991 return ret; 3553 return ret;
2992 } else { 3554 }
3555 else {
2993 /* Do what ksh does; skip the rest of the file */ 3556 /* Do what ksh does; skip the rest of the file */
2994 evalskip = SKIPFILE; 3557 evalskip = SKIPFILE;
2995 skipcount = 1; 3558 skipcount = 1;
@@ -2998,101 +3561,102 @@ static int returncmd(int argc, char **argv)
2998} 3561}
2999 3562
3000 3563
3001#ifndef CONFIG_FALSE 3564static int
3002static int false_main(int argc, char **argv) 3565falsecmd(int argc, char **argv)
3003{ 3566{
3004 return 1; 3567 return 1;
3005} 3568}
3006#endif
3007 3569
3008#ifndef CONFIG_TRUE
3009static int true_main(int argc, char **argv)
3010{
3011 return 0;
3012}
3013#endif
3014
3015/*
3016 * Controls whether the shell is interactive or not.
3017 */
3018
3019static void setsignal(int signo);
3020
3021#ifdef CONFIG_ASH_MAIL
3022static void chkmail(int silent);
3023#endif
3024
3025static void setinteractive(int on)
3026{
3027 static int is_interactive;
3028 static int do_banner = 0;
3029
3030 if (on == is_interactive)
3031 return;
3032 setsignal(SIGINT);
3033 setsignal(SIGQUIT);
3034 setsignal(SIGTERM);
3035#ifdef CONFIG_ASH_MAIL
3036 chkmail(1);
3037#endif
3038 is_interactive = on;
3039 if (do_banner == 0 && is_interactive) {
3040 /* Looks like they want an interactive shell */
3041#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
3042 printf("\n\n" BB_BANNER " Built-in shell (ash)\n");
3043 printf("Enter 'help' for a list of built-in commands.\n\n");
3044#endif
3045 do_banner = 1;
3046 }
3047}
3048 3570
3049static void optschanged(void) 3571static int
3572truecmd(int argc, char **argv)
3050{ 3573{
3051 setinteractive(iflag); 3574 return 0;
3052 setjobctl(mflag);
3053} 3575}
3054 3576
3055 3577
3056static int execcmd(int argc, char **argv) 3578static int
3579execcmd(int argc, char **argv)
3057{ 3580{
3058 if (argc > 1) { 3581 if (argc > 1) {
3059 struct strlist *sp; 3582 iflag = 0; /* exit on error */
3060
3061 iflag = 0; /* exit on error */
3062 mflag = 0; 3583 mflag = 0;
3063 optschanged(); 3584 optschanged();
3064 for (sp = cmdenviron; sp; sp = sp->next) 3585 shellexec(argv + 1, pathval(), 0);
3065 setvareq(sp->text, VEXPORT | VSTACK);
3066 shellexec(argv + 1, environment(), pathval(), 0);
3067 } 3586 }
3068 return 0; 3587 return 0;
3069} 3588}
3070 3589
3071static void eprintlist(struct strlist *sp) 3590
3591static int
3592eprintlist(struct strlist *sp, int sep)
3072{ 3593{
3073 for (; sp; sp = sp->next) { 3594 while (sp) {
3074 out2fmt(" %s", sp->text); 3595 const char *p;
3596
3597 p = " %s" + (1 - sep);
3598 sep |= 1;
3599 fprintf(stderr, p, sp->text);
3600 sp = sp->next;
3075 } 3601 }
3602
3603 return sep;
3076} 3604}
3605/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3606
3607/*
3608 * When commands are first encountered, they are entered in a hash table.
3609 * This ensures that a full path search will not have to be done for them
3610 * on each invocation.
3611 *
3612 * We should investigate converting to a linear search, even though that
3613 * would make the command name "hash" a misnomer.
3614 */
3615
3616#define CMDTABLESIZE 31 /* should be prime */
3617#define ARB 1 /* actual size determined at run time */
3618
3619
3620
3621struct tblentry {
3622 struct tblentry *next; /* next entry in hash chain */
3623 union param param; /* definition of builtin function */
3624 short cmdtype; /* index identifying command */
3625 char rehash; /* if set, cd done since entry created */
3626 char cmdname[ARB]; /* name of command */
3627};
3628
3629
3630static struct tblentry *cmdtable[CMDTABLESIZE];
3631static int builtinloc = -1; /* index in path of %builtin, or -1 */
3632
3633
3634static void tryexec(char *, char **, char **);
3635static void printentry(struct tblentry *);
3636static void clearcmdentry(int);
3637static struct tblentry *cmdlookup(const char *, int);
3638static void delete_cmd_entry(void);
3639
3077 3640
3078/* 3641/*
3079 * Exec a program. Never returns. If you change this routine, you may 3642 * Exec a program. Never returns. If you change this routine, you may
3080 * have to change the find_command routine as well. 3643 * have to change the find_command routine as well.
3081 */ 3644 */
3082 3645
3083static const char *pathopt; /* set by padvance */ 3646static void
3084 3647shellexec(char **argv, const char *path, int idx)
3085static void shellexec(char **argv, char **envp, const char *path, int idx)
3086{ 3648{
3087 char *cmdname; 3649 char *cmdname;
3088 int e; 3650 int e;
3651 char **envp;
3089 3652
3653 clearredir(1);
3654 envp = environment();
3090 if (strchr(argv[0], '/') != NULL 3655 if (strchr(argv[0], '/') != NULL
3091#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3656#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3092 || find_applet_by_name(argv[0]) 3657 || find_applet_by_name(argv[0])
3093#endif 3658#endif
3094 ) 3659 ) {
3095 {
3096 tryexec(argv[0], argv, envp); 3660 tryexec(argv[0], argv, envp);
3097 e = errno; 3661 e = errno;
3098 } else { 3662 } else {
@@ -3119,167 +3683,17 @@ static void shellexec(char **argv, char **envp, const char *path, int idx)
3119 exerrno = 2; 3683 exerrno = 2;
3120 break; 3684 break;
3121 } 3685 }
3686 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3687 argv[0], e, suppressint ));
3122 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC)); 3688 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3123 /* NOTREACHED */ 3689 /* NOTREACHED */
3124} 3690}
3125 3691
3126/*
3127 * Clear traps on a fork.
3128 */
3129static void clear_traps(void)
3130{
3131 char **tp;
3132
3133 for (tp = trap; tp < &trap[NSIG]; tp++) {
3134 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3135 INTOFF;
3136 free(*tp);
3137 *tp = NULL;
3138 if (tp != &trap[0])
3139 setsignal(tp - trap);
3140 INTON;
3141 }
3142 }
3143}
3144
3145
3146static int preadbuffer(void);
3147static void pushfile(void);
3148
3149/*
3150 * Read a character from the script, returning PEOF on end of file.
3151 * Nul characters in the input are silently discarded.
3152 */
3153
3154#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
3155#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3156static int pgetc(void)
3157{
3158 return pgetc_macro();
3159}
3160#else
3161static int pgetc_macro(void)
3162{
3163 return --parsenleft >= 0 ? *parsenextc++ : preadbuffer();
3164}
3165
3166static inline int pgetc(void)
3167{
3168 return pgetc_macro();
3169}
3170#endif
3171
3172 3692
3173/* 3693static void
3174 * Undo the last call to pgetc. Only one character may be pushed back. 3694tryexec(char *cmd, char **argv, char **envp)
3175 * PEOF may be pushed back.
3176 */
3177
3178static void pungetc(void)
3179{
3180 parsenleft++;
3181 parsenextc--;
3182}
3183
3184
3185static void popfile(void)
3186{
3187 struct parsefile *pf = parsefile;
3188
3189 INTOFF;
3190 if (pf->fd >= 0)
3191 close(pf->fd);
3192 free(pf->buf);
3193 while (pf->strpush)
3194 popstring();
3195 parsefile = pf->prev;
3196 free(pf);
3197 parsenleft = parsefile->nleft;
3198 parselleft = parsefile->lleft;
3199 parsenextc = parsefile->nextc;
3200 plinno = parsefile->linno;
3201 INTON;
3202}
3203
3204
3205/*
3206 * Return to top level.
3207 */
3208
3209static void popallfiles(void)
3210{
3211 while (parsefile != &basepf)
3212 popfile();
3213}
3214
3215/*
3216 * Close the file(s) that the shell is reading commands from. Called
3217 * after a fork is done.
3218 */
3219
3220static void closescript(void)
3221{
3222 popallfiles();
3223 if (parsefile->fd > 0) {
3224 close(parsefile->fd);
3225 parsefile->fd = 0;
3226 }
3227}
3228
3229
3230/*
3231 * Like setinputfile, but takes an open file descriptor. Call this with
3232 * interrupts off.
3233 */
3234
3235static void setinputfd(int fd, int push)
3236{
3237 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3238 if (push) {
3239 pushfile();
3240 parsefile->buf = 0;
3241 } else {
3242 closescript();
3243 while (parsefile->strpush)
3244 popstring();
3245 }
3246 parsefile->fd = fd;
3247 if (parsefile->buf == NULL)
3248 parsefile->buf = xmalloc(BUFSIZ);
3249 parselleft = parsenleft = 0;
3250 plinno = 1;
3251}
3252
3253
3254/*
3255 * Set the input to take input from a file. If push is set, push the
3256 * old input onto the stack first.
3257 */
3258
3259static void setinputfile(const char *fname, int push)
3260{
3261 int fd;
3262 int myfileno2;
3263
3264 INTOFF;
3265 if ((fd = open(fname, O_RDONLY)) < 0)
3266 error("Can't open %s", fname);
3267 if (fd < 10) {
3268 myfileno2 = dup_as_newfd(fd, 10);
3269 close(fd);
3270 if (myfileno2 < 0)
3271 error("Out of file descriptors");
3272 fd = myfileno2;
3273 }
3274 setinputfd(fd, push);
3275 INTON;
3276}
3277
3278
3279static void tryexec(char *cmd, char **argv, char **envp)
3280{ 3695{
3281 int repeated = 0; 3696 int repeated = 0;
3282
3283#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3697#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3284 int flg_bb = 0; 3698 int flg_bb = 0;
3285 char *name = cmd; 3699 char *name = cmd;
@@ -3310,24 +3724,33 @@ static void tryexec(char *cmd, char **argv, char **envp)
3310 } 3724 }
3311 } 3725 }
3312#endif 3726#endif
3313 repeat: 3727
3728repeat:
3729#ifdef SYSV
3730 do {
3731 execve(cmd, argv, envp);
3732 } while (errno == EINTR);
3733#else
3314 execve(cmd, argv, envp); 3734 execve(cmd, argv, envp);
3735#endif
3315 if (repeated++) { 3736 if (repeated++) {
3316 free(argv); 3737 ckfree(argv);
3317 } else if (errno == ENOEXEC) { 3738 } else if (errno == ENOEXEC) {
3318 char **ap; 3739 char **ap;
3319 char **new; 3740 char **new;
3320 3741
3321 for (ap = argv; *ap; ap++); 3742 for (ap = argv; *ap; ap++)
3322 ap = new = xmalloc((ap - argv + 2) * sizeof(char *)); 3743 ;
3744 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3323 *ap++ = cmd = "/bin/sh"; 3745 *ap++ = cmd = "/bin/sh";
3324 while ((*ap++ = *argv++)); 3746 while ((*ap++ = *argv++))
3747 ;
3325 argv = new; 3748 argv = new;
3326 goto repeat; 3749 goto repeat;
3327 } 3750 }
3328} 3751}
3329 3752
3330static char *commandtext(const union node *); 3753
3331 3754
3332/* 3755/*
3333 * Do a path search. The variable path (passed by reference) should be 3756 * Do a path search. The variable path (passed by reference) should be
@@ -3339,23 +3762,19 @@ static char *commandtext(const union node *);
3339 * NULL. 3762 * NULL.
3340 */ 3763 */
3341 3764
3342static const char *pathopt; 3765static char *
3343 3766padvance(const char **path, const char *name)
3344static void growstackblock(void);
3345
3346
3347static char *padvance(const char **path, const char *name)
3348{ 3767{
3349 const char *p; 3768 const char *p;
3350 char *q; 3769 char *q;
3351 const char *start; 3770 const char *start;
3352 int len; 3771 size_t len;
3353 3772
3354 if (*path == NULL) 3773 if (*path == NULL)
3355 return NULL; 3774 return NULL;
3356 start = *path; 3775 start = *path;
3357 for (p = start; *p && *p != ':' && *p != '%'; p++); 3776 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3358 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 3777 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3359 while (stackblocksize() < len) 3778 while (stackblocksize() < len)
3360 growstackblock(); 3779 growstackblock();
3361 q = stackblock(); 3780 q = stackblock();
@@ -3368,8 +3787,7 @@ static char *padvance(const char **path, const char *name)
3368 pathopt = NULL; 3787 pathopt = NULL;
3369 if (*p == '%') { 3788 if (*p == '%') {
3370 pathopt = ++p; 3789 pathopt = ++p;
3371 while (*p && *p != ':') 3790 while (*p && *p != ':') p++;
3372 p++;
3373 } 3791 }
3374 if (*p == ':') 3792 if (*p == ':')
3375 *path = p + 1; 3793 *path = p + 1;
@@ -3378,181 +3796,74 @@ static char *padvance(const char **path, const char *name)
3378 return stalloc(len); 3796 return stalloc(len);
3379} 3797}
3380 3798
3381/*
3382 * Wrapper around strcmp for qsort/bsearch/...
3383 */
3384static int pstrcmp(const void *a, const void *b)
3385{
3386 return strcmp((const char *) a, (*(const char *const *) b) + 1);
3387}
3388
3389/*
3390 * Find a keyword is in a sorted array.
3391 */
3392
3393static const char *const *findkwd(const char *s)
3394{
3395 return bsearch(s, tokname_array + KWDOFFSET,
3396 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
3397 sizeof(const char *), pstrcmp);
3398}
3399 3799
3400 3800
3401/*** Command hashing code ***/ 3801/*** Command hashing code ***/
3402 3802
3403static int hashcmd(int argc, char **argv) 3803
3804static int
3805hashcmd(int argc, char **argv)
3404{ 3806{
3405 struct tblentry **pp; 3807 struct tblentry **pp;
3406 struct tblentry *cmdp; 3808 struct tblentry *cmdp;
3407 int c; 3809 int c;
3408 int verbose;
3409 struct cmdentry entry; 3810 struct cmdentry entry;
3410 char *name; 3811 char *name;
3411 3812
3412#ifdef CONFIG_ASH_ALIAS 3813 while ((c = nextopt("r")) != '\0') {
3413 const struct alias *ap; 3814 clearcmdentry(0);
3414#endif 3815 return 0;
3415
3416 verbose = 0;
3417 while ((c = nextopt("rvV")) != '\0') {
3418 if (c == 'r') {
3419 clearcmdentry(0);
3420 return 0;
3421 } else if (c == 'v' || c == 'V') {
3422 verbose = c;
3423 }
3424 } 3816 }
3425 if (*argptr == NULL) { 3817 if (*argptr == NULL) {
3426 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 3818 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3427 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 3819 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3428 if (cmdp->cmdtype != CMDBUILTIN) { 3820 if (cmdp->cmdtype == CMDNORMAL)
3429 printentry(cmdp, verbose); 3821 printentry(cmdp);
3430 }
3431 } 3822 }
3432 } 3823 }
3433 return 0; 3824 return 0;
3434 } 3825 }
3435 c = 0; 3826 c = 0;
3436 while ((name = *argptr++) != NULL) { 3827 while ((name = *argptr) != NULL) {
3437 if ((cmdp = cmdlookup(name, 0)) != NULL 3828 if ((cmdp = cmdlookup(name, 0)) != NULL
3438 && (cmdp->cmdtype == CMDNORMAL 3829 && (cmdp->cmdtype == CMDNORMAL
3439 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 3830 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3440 delete_cmd_entry(); 3831 delete_cmd_entry();
3441#ifdef CONFIG_ASH_ALIAS
3442 /* Then look at the aliases */
3443 if ((ap = *__lookupalias(name)) != NULL) {
3444 if (verbose == 'v')
3445 printf("%s is an alias for %s\n", name, ap->val);
3446 else
3447 printalias(ap);
3448 continue;
3449 }
3450#endif
3451 /* First look at the keywords */
3452 if (findkwd(name) != 0) {
3453 if (verbose == 'v')
3454 printf("%s is a shell keyword\n", name);
3455 else
3456 puts(name);
3457 continue;
3458 }
3459
3460 find_command(name, &entry, DO_ERR, pathval()); 3832 find_command(name, &entry, DO_ERR, pathval());
3461 if (entry.cmdtype == CMDUNKNOWN) 3833 if (entry.cmdtype == CMDUNKNOWN)
3462 c = 1; 3834 c = 1;
3463 else if (verbose) { 3835 argptr++;
3464 cmdp = cmdlookup(name, 0);
3465 if (cmdp)
3466 printentry(cmdp, verbose == 'v');
3467 flushall();
3468 }
3469 } 3836 }
3470 return c; 3837 return c;
3471} 3838}
3472 3839
3473static void printentry(struct tblentry *cmdp, int verbose) 3840
3841static void
3842printentry(struct tblentry *cmdp)
3474{ 3843{
3475 int idx; 3844 int idx;
3476 const char *path; 3845 const char *path;
3477 char *name; 3846 char *name;
3478 3847
3479 printf("%s%s", cmdp->cmdname, (verbose ? " is " : "")); 3848 idx = cmdp->param.index;
3480 if (cmdp->cmdtype == CMDNORMAL) { 3849 path = pathval();
3481 idx = cmdp->param.index; 3850 do {
3482 path = pathval(); 3851 name = padvance(&path, cmdp->cmdname);
3483 do { 3852 stunalloc(name);
3484 name = padvance(&path, cmdp->cmdname); 3853 } while (--idx >= 0);
3485 stunalloc(name); 3854 out1str(name);
3486 } while (--idx >= 0); 3855 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
3487 if (verbose)
3488 out1str(name);
3489 } else if (cmdp->cmdtype == CMDBUILTIN) {
3490 if (verbose)
3491 out1str("a shell builtin");
3492 } else if (cmdp->cmdtype == CMDFUNCTION) {
3493 if (verbose) {
3494 INTOFF;
3495 out1str("a function\n");
3496 name = commandtext(cmdp->param.func);
3497 printf("%s() {\n %s\n}", cmdp->cmdname, name);
3498 free(name);
3499 INTON;
3500 }
3501#ifdef DEBUG
3502 } else {
3503 error("internal error: cmdtype %d", cmdp->cmdtype);
3504#endif
3505 }
3506 puts(cmdp->rehash ? "*" : nullstr);
3507} 3856}
3508 3857
3509 3858
3510 3859
3511/*** List the available builtins ***/
3512
3513
3514static int helpcmd(int argc, char **argv)
3515{
3516 int col, i;
3517
3518 printf("\nBuilt-in commands:\n-------------------\n");
3519 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
3520 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3521 builtincmds[i].name + 1);
3522 if (col > 60) {
3523 printf("\n");
3524 col = 0;
3525 }
3526 }
3527#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3528 {
3529 extern const struct BB_applet applets[];
3530 extern const size_t NUM_APPLETS;
3531
3532 for (i = 0; i < NUM_APPLETS; i++) {
3533
3534 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
3535 if (col > 60) {
3536 printf("\n");
3537 col = 0;
3538 }
3539 }
3540 }
3541#endif
3542 printf("\n\n");
3543 return EXIT_SUCCESS;
3544}
3545
3546/* 3860/*
3547 * Resolve a command name. If you change this routine, you may have to 3861 * Resolve a command name. If you change this routine, you may have to
3548 * change the shellexec routine as well. 3862 * change the shellexec routine as well.
3549 */ 3863 */
3550 3864
3551static int prefix(const char *, const char *);
3552
3553static void 3865static void
3554find_command(const char *name, struct cmdentry *entry, int act, 3866find_command(char *name, struct cmdentry *entry, int act, const char *path)
3555 const char *path)
3556{ 3867{
3557 struct tblentry *cmdp; 3868 struct tblentry *cmdp;
3558 int idx; 3869 int idx;
@@ -3560,28 +3871,23 @@ find_command(const char *name, struct cmdentry *entry, int act,
3560 char *fullname; 3871 char *fullname;
3561 struct stat statb; 3872 struct stat statb;
3562 int e; 3873 int e;
3563 int bltin;
3564 int firstchange;
3565 int updatetbl; 3874 int updatetbl;
3566 int regular;
3567 struct builtincmd *bcmd; 3875 struct builtincmd *bcmd;
3568 3876
3569 /* If name contains a slash, don't use the hash table */ 3877 /* If name contains a slash, don't use PATH or hash table */
3570 if (strchr(name, '/') != NULL) { 3878 if (strchr(name, '/') != NULL) {
3879 entry->u.index = -1;
3571 if (act & DO_ABS) { 3880 if (act & DO_ABS) {
3572 while (stat(name, &statb) < 0) { 3881 while (stat(name, &statb) < 0) {
3573 if (errno != ENOENT && errno != ENOTDIR) 3882#ifdef SYSV
3574 e = errno; 3883 if (errno == EINTR)
3884 continue;
3885#endif
3575 entry->cmdtype = CMDUNKNOWN; 3886 entry->cmdtype = CMDUNKNOWN;
3576 entry->u.index = -1;
3577 return; 3887 return;
3578 } 3888 }
3579 entry->cmdtype = CMDNORMAL;
3580 entry->u.index = -1;
3581 return;
3582 } 3889 }
3583 entry->cmdtype = CMDNORMAL; 3890 entry->cmdtype = CMDNORMAL;
3584 entry->u.index = 0;
3585 return; 3891 return;
3586 } 3892 }
3587 3893
@@ -3593,69 +3899,50 @@ find_command(const char *name, struct cmdentry *entry, int act,
3593 } 3899 }
3594#endif 3900#endif
3595 3901
3596 updatetbl = 1; 3902 updatetbl = (path == pathval());
3597 if (act & DO_BRUTE) { 3903 if (!updatetbl) {
3598 firstchange = path_change(path, &bltin); 3904 act |= DO_ALTPATH;
3599 } else { 3905 if (strstr(path, "%builtin") != NULL)
3600 bltin = builtinloc; 3906 act |= DO_ALTBLTIN;
3601 firstchange = 9999;
3602 } 3907 }
3603 3908
3604 /* If name is in the table, and not invalidated by cd, we're done */ 3909 /* If name is in the table, check answer will be ok */
3605 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) { 3910 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3606 if (cmdp->cmdtype == CMDFUNCTION) { 3911 int bit;
3607 if (act & DO_NOFUN) {
3608 updatetbl = 0;
3609 } else {
3610 goto success;
3611 }
3612 } else if (act & DO_BRUTE) {
3613 if ((cmdp->cmdtype == CMDNORMAL &&
3614 cmdp->param.index >= firstchange) ||
3615 (cmdp->cmdtype == CMDBUILTIN &&
3616 ((builtinloc < 0 && bltin >= 0) ?
3617 bltin : builtinloc) >= firstchange)) {
3618 /* need to recompute the entry */
3619 } else {
3620 goto success;
3621 }
3622 } else {
3623 goto success;
3624 }
3625 }
3626
3627 bcmd = find_builtin(name);
3628 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
3629 3912
3630 if (regular) { 3913 switch (cmdp->cmdtype) {
3631 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) { 3914 default:
3632 goto success; 3915#if DEBUG
3916 abort();
3917#endif
3918 case CMDNORMAL:
3919 bit = DO_ALTPATH;
3920 break;
3921 case CMDFUNCTION:
3922 bit = DO_NOFUNC;
3923 break;
3924 case CMDBUILTIN:
3925 bit = DO_ALTBLTIN;
3926 break;
3633 } 3927 }
3634 } else if (act & DO_BRUTE) { 3928 if (act & bit) {
3635 if (firstchange == 0) {
3636 updatetbl = 0; 3929 updatetbl = 0;
3637 } 3930 cmdp = NULL;
3931 } else if (cmdp->rehash == 0)
3932 /* if not invalidated by cd, we're done */
3933 goto success;
3638 } 3934 }
3639 3935
3640 /* If %builtin not in path, check for builtin next */ 3936 /* If %builtin not in path, check for builtin next */
3641 if (regular || (bltin < 0 && bcmd)) { 3937 bcmd = find_builtin(name);
3642 builtin: 3938 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3643 if (!updatetbl) { 3939 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3644 entry->cmdtype = CMDBUILTIN; 3940 )))
3645 entry->u.cmd = bcmd; 3941 goto builtin_success;
3646 return;
3647 }
3648 INTOFF;
3649 cmdp = cmdlookup(name, 1);
3650 cmdp->cmdtype = CMDBUILTIN;
3651 cmdp->param.cmd = bcmd;
3652 INTON;
3653 goto success;
3654 }
3655 3942
3656 /* We have to search path. */ 3943 /* We have to search path. */
3657 prev = -1; /* where to start */ 3944 prev = -1; /* where to start */
3658 if (cmdp && cmdp->rehash) { /* doing a rehash */ 3945 if (cmdp && cmdp->rehash) { /* doing a rehash */
3659 if (cmdp->cmdtype == CMDBUILTIN) 3946 if (cmdp->cmdtype == CMDBUILTIN)
3660 prev = builtinloc; 3947 prev = builtinloc;
3661 else 3948 else
@@ -3664,52 +3951,52 @@ find_command(const char *name, struct cmdentry *entry, int act,
3664 3951
3665 e = ENOENT; 3952 e = ENOENT;
3666 idx = -1; 3953 idx = -1;
3667 loop: 3954loop:
3668 while ((fullname = padvance(&path, name)) != NULL) { 3955 while ((fullname = padvance(&path, name)) != NULL) {
3669 stunalloc(fullname); 3956 stunalloc(fullname);
3670 idx++; 3957 idx++;
3671 if (idx >= firstchange) {
3672 updatetbl = 0;
3673 }
3674 if (pathopt) { 3958 if (pathopt) {
3675 if (prefix("builtin", pathopt)) { 3959 if (prefix(pathopt, "builtin")) {
3676 if ((bcmd = find_builtin(name))) { 3960 if (bcmd)
3677 goto builtin; 3961 goto builtin_success;
3678 }
3679 continue; 3962 continue;
3680 } else if (!(act & DO_NOFUN) && prefix("func", pathopt)) { 3963 } else if (!(act & DO_NOFUNC) &&
3964 prefix(pathopt, "func")) {
3681 /* handled below */ 3965 /* handled below */
3682 } else { 3966 } else {
3683 continue; /* ignore unimplemented options */ 3967 /* ignore unimplemented options */
3968 continue;
3684 } 3969 }
3685 } 3970 }
3686 /* if rehash, don't redo absolute path names */ 3971 /* if rehash, don't redo absolute path names */
3687 if (fullname[0] == '/' && idx <= prev && idx < firstchange) { 3972 if (fullname[0] == '/' && idx <= prev) {
3688 if (idx < prev) 3973 if (idx < prev)
3689 continue; 3974 continue;
3690 TRACE(("searchexec \"%s\": no change\n", name)); 3975 TRACE(("searchexec \"%s\": no change\n", name));
3691 goto success; 3976 goto success;
3692 } 3977 }
3693 while (stat(fullname, &statb) < 0) { 3978 while (stat(fullname, &statb) < 0) {
3979#ifdef SYSV
3980 if (errno == EINTR)
3981 continue;
3982#endif
3694 if (errno != ENOENT && errno != ENOTDIR) 3983 if (errno != ENOENT && errno != ENOTDIR)
3695 e = errno; 3984 e = errno;
3696 goto loop; 3985 goto loop;
3697 } 3986 }
3698 e = EACCES; /* if we fail, this will be the error */ 3987 e = EACCES; /* if we fail, this will be the error */
3699 if (!S_ISREG(statb.st_mode)) 3988 if (!S_ISREG(statb.st_mode))
3700 continue; 3989 continue;
3701 if (pathopt) { /* this is a %func directory */ 3990 if (pathopt) { /* this is a %func directory */
3702 stalloc(strlen(fullname) + 1); 3991 stalloc(strlen(fullname) + 1);
3703 readcmdfile(fullname); 3992 readcmdfile(fullname);
3704 if ((cmdp = cmdlookup(name, 0)) == NULL 3993 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3705 || cmdp->cmdtype != CMDFUNCTION) 3994 cmdp->cmdtype != CMDFUNCTION)
3706 error("%s not defined in %s", name, fullname); 3995 error("%s not defined in %s", name, fullname);
3707 stunalloc(fullname); 3996 stunalloc(fullname);
3708 goto success; 3997 goto success;
3709 } 3998 }
3710 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); 3999 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3711 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3712 be a function and we're being called with DO_NOFUN */
3713 if (!updatetbl) { 4000 if (!updatetbl) {
3714 entry->cmdtype = CMDNORMAL; 4001 entry->cmdtype = CMDNORMAL;
3715 entry->u.index = idx; 4002 entry->u.index = idx;
@@ -3727,46 +4014,72 @@ find_command(const char *name, struct cmdentry *entry, int act,
3727 if (cmdp && updatetbl) 4014 if (cmdp && updatetbl)
3728 delete_cmd_entry(); 4015 delete_cmd_entry();
3729 if (act & DO_ERR) 4016 if (act & DO_ERR)
3730 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC)); 4017 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
3731 entry->cmdtype = CMDUNKNOWN; 4018 entry->cmdtype = CMDUNKNOWN;
3732 return; 4019 return;
3733 4020
3734 success: 4021builtin_success:
4022 if (!updatetbl) {
4023 entry->cmdtype = CMDBUILTIN;
4024 entry->u.cmd = bcmd;
4025 return;
4026 }
4027 INTOFF;
4028 cmdp = cmdlookup(name, 1);
4029 cmdp->cmdtype = CMDBUILTIN;
4030 cmdp->param.cmd = bcmd;
4031 INTON;
4032success:
3735 cmdp->rehash = 0; 4033 cmdp->rehash = 0;
3736 entry->cmdtype = cmdp->cmdtype; 4034 entry->cmdtype = cmdp->cmdtype;
3737 entry->u = cmdp->param; 4035 entry->u = cmdp->param;
3738} 4036}
3739 4037
3740 4038
4039/*
4040 * Wrapper around strcmp for qsort/bsearch/...
4041 */
4042static int pstrcmp(const void *a, const void *b)
4043{
4044 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4045}
3741 4046
3742/* 4047/*
3743 * Search the table of builtin commands. 4048 * Search the table of builtin commands.
3744 */ 4049 */
3745 4050
3746static struct builtincmd *find_builtin(const char *name) 4051static struct builtincmd *
4052find_builtin(const char *name)
3747{ 4053{
3748 struct builtincmd *bp; 4054 struct builtincmd *bp;
3749 4055
3750 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd), 4056 bp = bsearch(
3751 pstrcmp); 4057 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4058 pstrcmp
4059 );
3752 return bp; 4060 return bp;
3753} 4061}
3754 4062
3755 4063
4064
3756/* 4065/*
3757 * Called when a cd is done. Marks all commands so the next time they 4066 * Called when a cd is done. Marks all commands so the next time they
3758 * are executed they will be rehashed. 4067 * are executed they will be rehashed.
3759 */ 4068 */
3760 4069
3761static void hashcd(void) 4070static void
4071hashcd(void)
3762{ 4072{
3763 struct tblentry **pp; 4073 struct tblentry **pp;
3764 struct tblentry *cmdp; 4074 struct tblentry *cmdp;
3765 4075
3766 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 4076 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3767 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 4077 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3768 if (cmdp->cmdtype == CMDNORMAL 4078 if (cmdp->cmdtype == CMDNORMAL || (
3769 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) 4079 cmdp->cmdtype == CMDBUILTIN &&
4080 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4081 builtinloc > 0
4082 ))
3770 cmdp->rehash = 1; 4083 cmdp->rehash = 1;
3771 } 4084 }
3772 } 4085 }
@@ -3775,23 +4088,48 @@ static void hashcd(void)
3775 4088
3776 4089
3777/* 4090/*
4091 * Fix command hash table when PATH changed.
3778 * Called before PATH is changed. The argument is the new value of PATH; 4092 * Called before PATH is changed. The argument is the new value of PATH;
3779 * pathval() still returns the old value at this point. Called with 4093 * pathval() still returns the old value at this point.
3780 * interrupts off. 4094 * Called with interrupts off.
3781 */ 4095 */
3782 4096
3783static void changepath(const char *newval) 4097static void
4098changepath(const char *newval)
3784{ 4099{
4100 const char *old, *new;
4101 int idx;
3785 int firstchange; 4102 int firstchange;
3786 int bltin; 4103 int idx_bltin;
3787 4104
3788 firstchange = path_change(newval, &bltin); 4105 old = pathval();
3789 if (builtinloc < 0 && bltin >= 0) 4106 new = newval;
3790 builtinloc = bltin; /* zap builtins */ 4107 firstchange = 9999; /* assume no change */
4108 idx = 0;
4109 idx_bltin = -1;
4110 for (;;) {
4111 if (*old != *new) {
4112 firstchange = idx;
4113 if ((*old == '\0' && *new == ':')
4114 || (*old == ':' && *new == '\0'))
4115 firstchange++;
4116 old = new; /* ignore subsequent differences */
4117 }
4118 if (*new == '\0')
4119 break;
4120 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4121 idx_bltin = idx;
4122 if (*new == ':') {
4123 idx++;
4124 }
4125 new++, old++;
4126 }
4127 if (builtinloc < 0 && idx_bltin >= 0)
4128 builtinloc = idx_bltin; /* zap builtins */
4129 if (builtinloc >= 0 && idx_bltin < 0)
4130 firstchange = 0;
3791 clearcmdentry(firstchange); 4131 clearcmdentry(firstchange);
3792 builtinloc = bltin; 4132 builtinloc = idx_bltin;
3793 /* Ensure that getenv("PATH") stays current */
3794 setenv("PATH", newval, 1);
3795} 4133}
3796 4134
3797 4135
@@ -3800,21 +4138,23 @@ static void changepath(const char *newval)
3800 * PATH which has changed. 4138 * PATH which has changed.
3801 */ 4139 */
3802 4140
3803static void clearcmdentry(int firstchange) 4141static void
4142clearcmdentry(int firstchange)
3804{ 4143{
3805 struct tblentry **tblp; 4144 struct tblentry **tblp;
3806 struct tblentry **pp; 4145 struct tblentry **pp;
3807 struct tblentry *cmdp; 4146 struct tblentry *cmdp;
3808 4147
3809 INTOFF; 4148 INTOFF;
3810 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { 4149 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3811 pp = tblp; 4150 pp = tblp;
3812 while ((cmdp = *pp) != NULL) { 4151 while ((cmdp = *pp) != NULL) {
3813 if ((cmdp->cmdtype == CMDNORMAL && 4152 if ((cmdp->cmdtype == CMDNORMAL &&
3814 cmdp->param.index >= firstchange) 4153 cmdp->param.index >= firstchange)
3815 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= firstchange)) { 4154 || (cmdp->cmdtype == CMDBUILTIN &&
4155 builtinloc >= firstchange)) {
3816 *pp = cmdp->next; 4156 *pp = cmdp->next;
3817 free(cmdp); 4157 ckfree(cmdp);
3818 } else { 4158 } else {
3819 pp = &cmdp->next; 4159 pp = &cmdp->next;
3820 } 4160 }
@@ -3824,43 +4164,45 @@ static void clearcmdentry(int firstchange)
3824} 4164}
3825 4165
3826 4166
4167
3827/* 4168/*
3828 * Locate a command in the command hash table. If "add" is nonzero, 4169 * Locate a command in the command hash table. If "add" is nonzero,
3829 * add the command to the table if it is not already present. The 4170 * add the command to the table if it is not already present. The
3830 * variable "lastcmdentry" is set to point to the address of the link 4171 * variable "lastcmdentry" is set to point to the address of the link
3831 * pointing to the entry, so that delete_cmd_entry can delete the 4172 * pointing to the entry, so that delete_cmd_entry can delete the
3832 * entry. 4173 * entry.
4174 *
4175 * Interrupts must be off if called with add != 0.
3833 */ 4176 */
3834 4177
3835static struct tblentry **lastcmdentry; 4178static struct tblentry **lastcmdentry;
3836 4179
3837static struct tblentry *cmdlookup(const char *name, int add) 4180
4181static struct tblentry *
4182cmdlookup(const char *name, int add)
3838{ 4183{
3839 int hashval; 4184 unsigned int hashval;
3840 const char *p; 4185 const char *p;
3841 struct tblentry *cmdp; 4186 struct tblentry *cmdp;
3842 struct tblentry **pp; 4187 struct tblentry **pp;
3843 4188
3844 p = name; 4189 p = name;
3845 hashval = *p << 4; 4190 hashval = (unsigned char)*p << 4;
3846 while (*p) 4191 while (*p)
3847 hashval += *p++; 4192 hashval += (unsigned char)*p++;
3848 hashval &= 0x7FFF; 4193 hashval &= 0x7FFF;
3849 pp = &cmdtable[hashval % CMDTABLESIZE]; 4194 pp = &cmdtable[hashval % CMDTABLESIZE];
3850 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 4195 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3851 if (equal(cmdp->cmdname, name)) 4196 if (equal(cmdp->cmdname, name))
3852 break; 4197 break;
3853 pp = &cmdp->next; 4198 pp = &cmdp->next;
3854 } 4199 }
3855 if (add && cmdp == NULL) { 4200 if (add && cmdp == NULL) {
3856 INTOFF; 4201 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
3857 cmdp = *pp = xmalloc(sizeof(struct tblentry) - ARB 4202 + strlen(name) + 1);
3858 + strlen(name) + 1);
3859 cmdp->next = NULL; 4203 cmdp->next = NULL;
3860 cmdp->cmdtype = CMDUNKNOWN; 4204 cmdp->cmdtype = CMDUNKNOWN;
3861 cmdp->rehash = 0;
3862 strcpy(cmdp->cmdname, name); 4205 strcpy(cmdp->cmdname, name);
3863 INTON;
3864 } 4206 }
3865 lastcmdentry = pp; 4207 lastcmdentry = pp;
3866 return cmdp; 4208 return cmdp;
@@ -3870,90 +4212,218 @@ static struct tblentry *cmdlookup(const char *name, int add)
3870 * Delete the command entry returned on the last lookup. 4212 * Delete the command entry returned on the last lookup.
3871 */ 4213 */
3872 4214
3873static void delete_cmd_entry(void) 4215static void
4216delete_cmd_entry(void)
3874{ 4217{
3875 struct tblentry *cmdp; 4218 struct tblentry *cmdp;
3876 4219
3877 INTOFF; 4220 INTOFF;
3878 cmdp = *lastcmdentry; 4221 cmdp = *lastcmdentry;
3879 *lastcmdentry = cmdp->next; 4222 *lastcmdentry = cmdp->next;
3880 free(cmdp); 4223 if (cmdp->cmdtype == CMDFUNCTION)
4224 freefunc(cmdp->param.func);
4225 ckfree(cmdp);
3881 INTON; 4226 INTON;
3882} 4227}
3883 4228
3884 4229
4230/*
4231 * Add a new command entry, replacing any existing command entry for
4232 * the same name - except special builtins.
4233 */
3885 4234
4235static inline void
4236addcmdentry(char *name, struct cmdentry *entry)
4237{
4238 struct tblentry *cmdp;
3886 4239
4240 cmdp = cmdlookup(name, 1);
4241 if (cmdp->cmdtype == CMDFUNCTION) {
4242 freefunc(cmdp->param.func);
4243 }
4244 cmdp->cmdtype = entry->cmdtype;
4245 cmdp->param = entry->u;
4246 cmdp->rehash = 0;
4247}
3887 4248
3888static const unsigned char nodesize[26] = { 4249/*
3889 ALIGN(sizeof(struct nbinary)), 4250 * Make a copy of a parse tree.
3890 ALIGN(sizeof(struct ncmd)), 4251 */
3891 ALIGN(sizeof(struct npipe)), 4252
3892 ALIGN(sizeof(struct nredir)), 4253static inline struct funcnode *
3893 ALIGN(sizeof(struct nredir)), 4254copyfunc(union node *n)
3894 ALIGN(sizeof(struct nredir)), 4255{
3895 ALIGN(sizeof(struct nbinary)), 4256 struct funcnode *f;
3896 ALIGN(sizeof(struct nbinary)), 4257 size_t blocksize;
3897 ALIGN(sizeof(struct nif)), 4258
3898 ALIGN(sizeof(struct nbinary)), 4259 funcblocksize = offsetof(struct funcnode, n);
3899 ALIGN(sizeof(struct nbinary)), 4260 funcstringsize = 0;
3900 ALIGN(sizeof(struct nfor)), 4261 calcsize(n);
3901 ALIGN(sizeof(struct ncase)), 4262 blocksize = funcblocksize;
3902 ALIGN(sizeof(struct nclist)), 4263 f = ckmalloc(blocksize + funcstringsize);
3903 ALIGN(sizeof(struct narg)), 4264 funcblock = (char *) f + offsetof(struct funcnode, n);
3904 ALIGN(sizeof(struct narg)), 4265 funcstring = (char *) f + blocksize;
3905 ALIGN(sizeof(struct nfile)), 4266 copynode(n);
3906 ALIGN(sizeof(struct nfile)), 4267 f->count = 0;
3907 ALIGN(sizeof(struct nfile)), 4268 return f;
3908 ALIGN(sizeof(struct nfile)), 4269}
3909 ALIGN(sizeof(struct nfile)), 4270
3910 ALIGN(sizeof(struct ndup)), 4271/*
3911 ALIGN(sizeof(struct ndup)), 4272 * Define a shell function.
3912 ALIGN(sizeof(struct nhere)), 4273 */
3913 ALIGN(sizeof(struct nhere)), 4274
3914 ALIGN(sizeof(struct nnot)), 4275static void
3915}; 4276defun(char *name, union node *func)
4277{
4278 struct cmdentry entry;
3916 4279
4280 INTOFF;
4281 entry.cmdtype = CMDFUNCTION;
4282 entry.u.func = copyfunc(func);
4283 addcmdentry(name, &entry);
4284 INTON;
4285}
3917 4286
3918 4287
3919/* 4288/*
3920 * Delete a function if it exists. 4289 * Delete a function if it exists.
3921 */ 4290 */
3922 4291
3923static void unsetfunc(char *name) 4292static void
4293unsetfunc(const char *name)
3924{ 4294{
3925 struct tblentry *cmdp; 4295 struct tblentry *cmdp;
3926 4296
3927 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) { 4297 if ((cmdp = cmdlookup(name, 0)) != NULL &&
3928 free(cmdp->param.func); 4298 cmdp->cmdtype == CMDFUNCTION)
3929 delete_cmd_entry(); 4299 delete_cmd_entry();
3930 }
3931} 4300}
3932 4301
3933
3934/* 4302/*
3935 * Locate and print what a word is... 4303 * Locate and print what a word is...
3936 */ 4304 */
3937 4305
3938static int typecmd(int argc, char **argv) 4306
4307#ifdef CONFIG_ASH_CMDCMD
4308static int
4309describe_command(char *command, int describe_command_verbose)
4310#else
4311#define describe_command_verbose 1
4312static int
4313describe_command(char *command)
4314#endif
4315{
4316 struct cmdentry entry;
4317 struct tblentry *cmdp;
4318#ifdef CONFIG_ASH_ALIAS
4319 const struct alias *ap;
4320#endif
4321 const char *path = pathval();
4322
4323 if (describe_command_verbose) {
4324 out1str(command);
4325 }
4326
4327 /* First look at the keywords */
4328 if (findkwd(command)) {
4329 out1str(describe_command_verbose ? " is a shell keyword" : command);
4330 goto out;
4331 }
4332
4333#ifdef CONFIG_ASH_ALIAS
4334 /* Then look at the aliases */
4335 if ((ap = lookupalias(command, 0)) != NULL) {
4336 if (describe_command_verbose) {
4337 out1fmt(" is an alias for %s", ap->val);
4338 } else {
4339 out1str("alias ");
4340 printalias(ap);
4341 return 0;
4342 }
4343 goto out;
4344 }
4345#endif
4346 /* Then check if it is a tracked alias */
4347 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4348 entry.cmdtype = cmdp->cmdtype;
4349 entry.u = cmdp->param;
4350 } else {
4351 /* Finally use brute force */
4352 find_command(command, &entry, DO_ABS, path);
4353 }
4354
4355 switch (entry.cmdtype) {
4356 case CMDNORMAL: {
4357 int j = entry.u.index;
4358 char *p;
4359 if (j == -1) {
4360 p = command;
4361 } else {
4362 do {
4363 p = padvance(&path, command);
4364 stunalloc(p);
4365 } while (--j >= 0);
4366 }
4367 if (describe_command_verbose) {
4368 out1fmt(" is%s %s",
4369 (cmdp ? " a tracked alias for" : nullstr), p
4370 );
4371 } else {
4372 out1str(p);
4373 }
4374 break;
4375 }
4376
4377 case CMDFUNCTION:
4378 if (describe_command_verbose) {
4379 out1str(" is a shell function");
4380 } else {
4381 out1str(command);
4382 }
4383 break;
4384
4385 case CMDBUILTIN:
4386 if (describe_command_verbose) {
4387 out1fmt(" is a %sshell builtin",
4388 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4389 "special " : nullstr
4390 );
4391 } else {
4392 out1str(command);
4393 }
4394 break;
4395
4396 default:
4397 if (describe_command_verbose) {
4398 out1str(": not found\n");
4399 }
4400 return 127;
4401 }
4402
4403out:
4404 out1c('\n');
4405 return 0;
4406}
4407
4408static int
4409typecmd(int argc, char **argv)
3939{ 4410{
3940 int i; 4411 int i;
3941 int err = 0; 4412 int err = 0;
3942 char *argv_a[2];
3943
3944 argv_a[1] = 0;
3945 4413
3946 for (i = 1; i < argc; i++) { 4414 for (i = 1; i < argc; i++) {
3947 argv_a[0] = argv[i]; 4415#ifdef CONFIG_ASH_CMDCMD
3948 argptr = argv_a; 4416 err |= describe_command(argv[i], 1);
3949 optptr = "v"; 4417#else
3950 err |= hashcmd(2, argv); 4418 err |= describe_command(argv[i]);
4419#endif
3951 } 4420 }
3952 return err; 4421 return err;
3953} 4422}
3954 4423
3955#ifdef CONFIG_ASH_CMDCMD 4424#ifdef CONFIG_ASH_CMDCMD
3956static int commandcmd(int argc, char **argv) 4425static int
4426commandcmd(int argc, char **argv)
3957{ 4427{
3958 int c; 4428 int c;
3959 int default_path = 0; 4429 int default_path = 0;
@@ -3962,6 +4432,12 @@ static int commandcmd(int argc, char **argv)
3962 4432
3963 while ((c = nextopt("pvV")) != '\0') 4433 while ((c = nextopt("pvV")) != '\0')
3964 switch (c) { 4434 switch (c) {
4435 default:
4436#ifdef DEBUG
4437 fprintf(stderr,
4438"command: nextopt returned character code 0%o\n", c);
4439 return EX_SOFTWARE;
4440#endif
3965 case 'p': 4441 case 'p':
3966 default_path = 1; 4442 default_path = 1;
3967 break; 4443 break;
@@ -3973,68 +4449,37 @@ static int commandcmd(int argc, char **argv)
3973 break; 4449 break;
3974 } 4450 }
3975 4451
3976 if (default_path + verify_only + verbose_verify_only > 1 || !*argptr) { 4452 if (default_path + verify_only + verbose_verify_only > 1 ||
3977 out2str("command [-p] command [arg ...]\n" 4453 !*argptr) {
4454 fprintf(stderr,
4455 "command [-p] command [arg ...]\n"
3978 "command {-v|-V} command\n"); 4456 "command {-v|-V} command\n");
3979 return EX_USAGE; 4457 return EX_USAGE;
3980 } 4458 }
3981 4459
3982 if (verify_only || verbose_verify_only) { 4460 if (verify_only || verbose_verify_only) {
3983 char *argv_a[2]; 4461 return describe_command(*argptr, verbose_verify_only);
3984
3985 argv_a[1] = 0;
3986 argv_a[0] = *argptr;
3987 argptr = argv_a;
3988 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
3989 return hashcmd(argc, argv);
3990 } 4462 }
3991 4463
3992 return 0; 4464 return 0;
3993} 4465}
3994#endif 4466#endif
3995 4467
3996static int path_change(const char *newval, int *bltin) 4468/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
3997{
3998 const char *old, *new;
3999 int idx;
4000 int firstchange;
4001
4002 old = pathval();
4003 new = newval;
4004 firstchange = 9999; /* assume no change */
4005 idx = 0;
4006 *bltin = -1;
4007 for (;;) {
4008 if (*old != *new) {
4009 firstchange = idx;
4010 if ((*old == '\0' && *new == ':')
4011 || (*old == ':' && *new == '\0'))
4012 firstchange++;
4013 old = new; /* ignore subsequent differences */
4014 }
4015 if (*new == '\0')
4016 break;
4017 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4018 *bltin = idx;
4019 if (*new == ':') {
4020 idx++;
4021 }
4022 new++, old++;
4023 }
4024 if (builtinloc >= 0 && *bltin < 0)
4025 firstchange = 0;
4026 return firstchange;
4027}
4028 4469
4029/* 4470/*
4030 * Routines to expand arguments to commands. We have to deal with 4471 * Routines to expand arguments to commands. We have to deal with
4031 * backquotes, shell variables, and file metacharacters. 4472 * backquotes, shell variables, and file metacharacters.
4032 */ 4473 */
4474
4033/* 4475/*
4034 * _rmescape() flags 4476 * _rmescape() flags
4035 */ 4477 */
4036#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ 4478#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4037#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 4479#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4480#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4481#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4482#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4038 4483
4039/* 4484/*
4040 * Structure specifying which parts of the string should be searched 4485 * Structure specifying which parts of the string should be searched
@@ -4042,66 +4487,87 @@ static int path_change(const char *newval, int *bltin)
4042 */ 4487 */
4043 4488
4044struct ifsregion { 4489struct ifsregion {
4045 struct ifsregion *next; /* next region in list */ 4490 struct ifsregion *next; /* next region in list */
4046 int begoff; /* offset of start of region */ 4491 int begoff; /* offset of start of region */
4047 int endoff; /* offset of end of region */ 4492 int endoff; /* offset of end of region */
4048 int nulonly; /* search for nul bytes only */ 4493 int nulonly; /* search for nul bytes only */
4049}; 4494};
4050 4495
4051 4496/* output of current string */
4052static char *expdest; /* output of current string */ 4497static char *expdest;
4053static struct nodelist *argbackq; /* list of back quote expressions */ 4498/* list of back quote expressions */
4054static struct ifsregion ifsfirst; /* first struct in list of ifs regions */ 4499static struct nodelist *argbackq;
4055static struct ifsregion *ifslastp; /* last struct in list */ 4500/* first struct in list of ifs regions */
4056static struct arglist exparg; /* holds expanded arg list */ 4501static struct ifsregion ifsfirst;
4502/* last struct in list */
4503static struct ifsregion *ifslastp;
4504/* holds expanded arg list */
4505static struct arglist exparg;
4057 4506
4058static void argstr(char *, int); 4507static void argstr(char *, int);
4059static char *exptilde(char *, int); 4508static char *exptilde(char *, char *, int);
4060static void expbackq(union node *, int, int); 4509static void expbackq(union node *, int, int);
4061static int subevalvar(char *, char *, int, int, int, int, int); 4510static const char *subevalvar(char *, char *, int, int, int, int, int);
4511static char *evalvar(char *, int);
4062static int varisset(char *, int); 4512static int varisset(char *, int);
4063static void strtodest(const char *, int, int); 4513static void strtodest(const char *, int, int);
4514static void memtodest(const char *p, size_t len, int syntax, int quotes);
4064static void varvalue(char *, int, int); 4515static void varvalue(char *, int, int);
4065static void recordregion(int, int, int); 4516static void recordregion(int, int, int);
4066static void removerecordregions(int); 4517static void removerecordregions(int);
4067static void ifsbreakup(char *, struct arglist *); 4518static void ifsbreakup(char *, struct arglist *);
4068static void ifsfree(void); 4519static void ifsfree(void);
4069static void expandmeta(struct strlist *, int); 4520static void expandmeta(struct strlist *, int);
4070
4071#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4072#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4073#if !defined(GLOB_BROKEN)
4074static void addglob(const glob_t *); 4521static void addglob(const glob_t *);
4075#endif 4522static void addfname(char *);
4076#endif 4523static int patmatch(char *, const char *);
4077#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4078static void expmeta(char *, char *);
4079#endif
4080#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4081static struct strlist *expsort(struct strlist *);
4082static struct strlist *msort(struct strlist *, int);
4083#endif
4084static int patmatch(char *, char *, int);
4085 4524
4086#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) 4525static int cvtnum(long);
4087static int patmatch2(char *, char *, int); 4526static size_t esclen(const char *, const char *);
4088#else 4527static char *scanleft(char *, char *, char *, char *, int, int);
4089static int pmatch(char *, char *, int); 4528static char *scanright(char *, char *, char *, char *, int, int);
4529static void varunset(const char *, const char *, const char *, int)
4530 __attribute__((__noreturn__));
4531
4532
4533#define pmatch(a, b) !fnmatch((a), (b), 0)
4534/*
4535 * Prepare a pattern for a glob(3) call.
4536 *
4537 * Returns an stalloced string.
4538 */
4539
4540static inline char *
4541preglob(const char *pattern, int quoted, int flag) {
4542 flag |= RMESCAPE_GLOB;
4543 if (quoted) {
4544 flag |= RMESCAPE_QUOTED;
4545 }
4546 return _rmescapes((char *)pattern, flag);
4547}
4548
4549
4550static size_t
4551esclen(const char *start, const char *p) {
4552 size_t esc = 0;
4553
4554 while (p > start && *--p == CTLESC) {
4555 esc++;
4556 }
4557 return esc;
4558}
4090 4559
4091#define patmatch2 patmatch
4092#endif
4093static char *cvtnum(int, char *);
4094 4560
4095/* 4561/*
4096 * Expand shell variables and backquotes inside a here document. 4562 * Expand shell variables and backquotes inside a here document.
4097 */ 4563 */
4098 4564
4099/* arg: the document, fd: where to write the expanded version */ 4565static inline void
4100static inline void expandhere(union node *arg, int fd) 4566expandhere(union node *arg, int fd)
4101{ 4567{
4102 herefd = fd; 4568 herefd = fd;
4103 expandarg(arg, (struct arglist *) NULL, 0); 4569 expandarg(arg, (struct arglist *)NULL, 0);
4104 xwrite(fd, stackblock(), expdest - stackblock()); 4570 xwrite(fd, stackblock(), expdest - (char *)stackblock());
4105} 4571}
4106 4572
4107 4573
@@ -4112,7 +4578,8 @@ static inline void expandhere(union node *arg, int fd)
4112 * here document expansion. 4578 * here document expansion.
4113 */ 4579 */
4114 4580
4115static void expandarg(union node *arg, struct arglist *arglist, int flag) 4581void
4582expandarg(union node *arg, struct arglist *arglist, int flag)
4116{ 4583{
4117 struct strlist *sp; 4584 struct strlist *sp;
4118 char *p; 4585 char *p;
@@ -4123,7 +4590,7 @@ static void expandarg(union node *arg, struct arglist *arglist, int flag)
4123 ifslastp = NULL; 4590 ifslastp = NULL;
4124 argstr(arg->narg.text, flag); 4591 argstr(arg->narg.text, flag);
4125 if (arglist == NULL) { 4592 if (arglist == NULL) {
4126 return; /* here document expanded */ 4593 return; /* here document expanded */
4127 } 4594 }
4128 STPUTC('\0', expdest); 4595 STPUTC('\0', expdest);
4129 p = grabstackstr(expdest); 4596 p = grabstackstr(expdest);
@@ -4137,14 +4604,15 @@ static void expandarg(union node *arg, struct arglist *arglist, int flag)
4137 exparg.lastp = &exparg.list; 4604 exparg.lastp = &exparg.list;
4138 expandmeta(exparg.list, flag); 4605 expandmeta(exparg.list, flag);
4139 } else { 4606 } else {
4140 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 4607 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4141 rmescapes(p); 4608 rmescapes(p);
4142 sp = (struct strlist *) stalloc(sizeof(struct strlist)); 4609 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4143 sp->text = p; 4610 sp->text = p;
4144 *exparg.lastp = sp; 4611 *exparg.lastp = sp;
4145 exparg.lastp = &sp->next; 4612 exparg.lastp = &sp->next;
4146 } 4613 }
4147 ifsfree(); 4614 if (ifsfirst.next)
4615 ifsfree();
4148 *exparg.lastp = NULL; 4616 *exparg.lastp = NULL;
4149 if (exparg.list) { 4617 if (exparg.list) {
4150 *arglist->lastp = exparg.list; 4618 *arglist->lastp = exparg.list;
@@ -4153,239 +4621,166 @@ static void expandarg(union node *arg, struct arglist *arglist, int flag)
4153} 4621}
4154 4622
4155 4623
4624
4156/* 4625/*
4157 * Expand a variable, and return a pointer to the next character in the 4626 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4158 * input string. 4627 * characters to allow for further processing. Otherwise treat
4628 * $@ like $* since no splitting will be performed.
4159 */ 4629 */
4160 4630
4161static inline char *evalvar(char *p, int flag) 4631static void
4162{ 4632argstr(char *p, int flag)
4163 int subtype; 4633{
4164 int varflags; 4634 static const char spclchars[] = {
4165 char *var; 4635 '=',
4166 const char *val; 4636 ':',
4167 int patloc; 4637 CTLQUOTEMARK,
4638 CTLENDVAR,
4639 CTLESC,
4640 CTLVAR,
4641 CTLBACKQ,
4642 CTLBACKQ | CTLQUOTE,
4643#ifdef CONFIG_ASH_MATH_SUPPORT
4644 CTLENDARI,
4645#endif
4646 0
4647 };
4648 const char *reject = spclchars;
4168 int c; 4649 int c;
4169 int set; 4650 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4170 int special; 4651 int breakall = flag & EXP_WORD;
4652 int inquotes;
4653 size_t length;
4171 int startloc; 4654 int startloc;
4172 int varlen;
4173 int easy;
4174 int quotes = flag & (EXP_FULL | EXP_CASE);
4175 4655
4176 varflags = *p++; 4656 if (!(flag & EXP_VARTILDE)) {
4177 subtype = varflags & VSTYPE; 4657 reject += 2;
4178 var = p; 4658 } else if (flag & EXP_VARTILDE2) {
4179 special = 0; 4659 reject++;
4180 if (!is_name(*p))
4181 special = 1;
4182 p = strchr(p, '=') + 1;
4183 again: /* jump here after setting a variable with ${var=text} */
4184 if (special) {
4185 set = varisset(var, varflags & VSNUL);
4186 val = NULL;
4187 } else {
4188 val = lookupvar(var);
4189 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4190 val = NULL;
4191 set = 0;
4192 } else
4193 set = 1;
4194 } 4660 }
4195 varlen = 0; 4661 inquotes = 0;
4196 startloc = expdest - stackblock(); 4662 length = 0;
4197 if (set && subtype != VSPLUS) { 4663 if (flag & EXP_TILDE) {
4198 /* insert the value of the variable */ 4664 char *q;
4199 if (special) {
4200 varvalue(var, varflags & VSQUOTE, flag);
4201 if (subtype == VSLENGTH) {
4202 varlen = expdest - stackblock() - startloc;
4203 STADJUST(-varlen, expdest);
4204 }
4205 } else {
4206 if (subtype == VSLENGTH) {
4207 varlen = strlen(val);
4208 } else {
4209 strtodest(val,
4210 varflags & VSQUOTE ? DQSYNTAX : BASESYNTAX, quotes);
4211 }
4212 }
4213 }
4214
4215 if (subtype == VSPLUS)
4216 set = !set;
4217
4218 easy = ((varflags & VSQUOTE) == 0 ||
4219 (*var == '@' && shellparam.nparam != 1));
4220
4221 4665
4222 switch (subtype) { 4666 flag &= ~EXP_TILDE;
4223 case VSLENGTH: 4667tilde:
4224 expdest = cvtnum(varlen, expdest); 4668 q = p;
4225 goto record; 4669 if (*q == CTLESC && (flag & EXP_QWORD))
4226 4670 q++;
4227 case VSNORMAL: 4671 if (*q == '~')
4228 if (!easy) 4672 p = exptilde(p, q, flag);
4229 break; 4673 }
4230 record: 4674start:
4231 recordregion(startloc, expdest - stackblock(), varflags & VSQUOTE); 4675 startloc = expdest - (char *)stackblock();
4232 break; 4676 for (;;) {
4233 4677 length += strcspn(p + length, reject);
4234 case VSPLUS: 4678 c = p[length];
4235 case VSMINUS: 4679 if (c && (!(c & 0x80)
4236 if (!set) { 4680#ifdef CONFIG_ASH_MATH_SUPPORT
4237 argstr(p, flag); 4681 || c == CTLENDARI
4238 break; 4682#endif
4239 } 4683 )) {
4240 if (easy) 4684 /* c == '=' || c == ':' || c == CTLENDARI */
4241 goto record; 4685 length++;
4242 break; 4686 }
4243 4687 if (length > 0) {
4244 case VSTRIMLEFT: 4688 int newloc;
4245 case VSTRIMLEFTMAX: 4689 expdest = stnputs(p, length, expdest);
4246 case VSTRIMRIGHT: 4690 newloc = expdest - (char *)stackblock();
4247 case VSTRIMRIGHTMAX: 4691 if (breakall && !inquotes && newloc > startloc) {
4248 if (!set) 4692 recordregion(startloc, newloc, 0);
4249 break;
4250 /*
4251 * Terminate the string and start recording the pattern
4252 * right after it
4253 */
4254 STPUTC('\0', expdest);
4255 patloc = expdest - stackblock();
4256 if (subevalvar(p, NULL, patloc, subtype,
4257 startloc, varflags, quotes) == 0) {
4258 int amount = (expdest - stackblock() - patloc) + 1;
4259
4260 STADJUST(-amount, expdest);
4261 }
4262 /* Remove any recorded regions beyond start of variable */
4263 removerecordregions(startloc);
4264 goto record;
4265
4266 case VSASSIGN:
4267 case VSQUESTION:
4268 if (!set) {
4269 if (subevalvar(p, var, 0, subtype, startloc, varflags, quotes)) {
4270 varflags &= ~VSNUL;
4271 /*
4272 * Remove any recorded regions beyond
4273 * start of variable
4274 */
4275 removerecordregions(startloc);
4276 goto again;
4277 } 4693 }
4278 break; 4694 startloc = newloc;
4279 } 4695 }
4280 if (easy) 4696 p += length + 1;
4281 goto record; 4697 length = 0;
4282 break;
4283
4284#ifdef DEBUG
4285 default:
4286 abort();
4287#endif
4288 }
4289 4698
4290 if (subtype != VSNORMAL) { /* skip to end of alternative */ 4699 switch (c) {
4291 int nesting = 1; 4700 case '\0':
4292 4701 goto breakloop;
4293 for (;;) { 4702 case '=':
4294 if ((c = *p++) == CTLESC) 4703 if (flag & EXP_VARTILDE2) {
4295 p++; 4704 p--;
4296 else if (c == CTLBACKQ || c == (CTLBACKQ | CTLQUOTE)) { 4705 continue;
4297 if (set)
4298 argbackq = argbackq->next;
4299 } else if (c == CTLVAR) {
4300 if ((*p++ & VSTYPE) != VSNORMAL)
4301 nesting++;
4302 } else if (c == CTLENDVAR) {
4303 if (--nesting == 0)
4304 break;
4305 } 4706 }
4707 flag |= EXP_VARTILDE2;
4708 reject++;
4709 /* fall through */
4710 case ':':
4711 /*
4712 * sort of a hack - expand tildes in variable
4713 * assignments (after the first '=' and after ':'s).
4714 */
4715 if (*--p == '~') {
4716 goto tilde;
4717 }
4718 continue;
4306 } 4719 }
4307 }
4308 return p;
4309}
4310
4311 4720
4312/* 4721 switch (c) {
4313 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 4722 case CTLENDVAR: /* ??? */
4314 * characters to allow for further processing. Otherwise treat 4723 goto breakloop;
4315 * $@ like $* since no splitting will be performed.
4316 */
4317
4318static void argstr(char *p, int flag)
4319{
4320 char c;
4321 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4322 int firsteq = 1;
4323
4324 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4325 p = exptilde(p, flag);
4326 for (;;) {
4327 switch (c = *p++) {
4328 case '\0':
4329 case CTLENDVAR: /* ??? */
4330 return;
4331 case CTLQUOTEMARK: 4724 case CTLQUOTEMARK:
4332 /* "$@" syntax adherence hack */ 4725 /* "$@" syntax adherence hack */
4333 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') 4726 if (
4334 break; 4727 !inquotes &&
4335 if ((flag & EXP_FULL) != 0) 4728 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4336 STPUTC(c, expdest); 4729 (p[4] == CTLQUOTEMARK || (
4730 p[4] == CTLENDVAR &&
4731 p[5] == CTLQUOTEMARK
4732 ))
4733 ) {
4734 p = evalvar(p + 1, flag) + 1;
4735 goto start;
4736 }
4737 inquotes = !inquotes;
4738addquote:
4739 if (quotes) {
4740 p--;
4741 length++;
4742 startloc++;
4743 }
4337 break; 4744 break;
4338 case CTLESC: 4745 case CTLESC:
4339 if (quotes) 4746 startloc++;
4340 STPUTC(c, expdest); 4747 length++;
4341 c = *p++; 4748 goto addquote;
4342 STPUTC(c, expdest);
4343 break;
4344 case CTLVAR: 4749 case CTLVAR:
4345 p = evalvar(p, flag); 4750 p = evalvar(p, flag);
4346 break; 4751 goto start;
4347 case CTLBACKQ: 4752 case CTLBACKQ:
4348 case CTLBACKQ | CTLQUOTE: 4753 c = 0;
4349 expbackq(argbackq->n, c & CTLQUOTE, flag); 4754 case CTLBACKQ|CTLQUOTE:
4755 expbackq(argbackq->n, c, quotes);
4350 argbackq = argbackq->next; 4756 argbackq = argbackq->next;
4351 break; 4757 goto start;
4352#ifdef CONFIG_ASH_MATH_SUPPORT 4758#ifdef CONFIG_ASH_MATH_SUPPORT
4353 case CTLENDARI: 4759 case CTLENDARI:
4354 expari(flag); 4760 p--;
4355 break; 4761 expari(quotes);
4762 goto start;
4356#endif 4763#endif
4357 case ':':
4358 case '=':
4359 /*
4360 * sort of a hack - expand tildes in variable
4361 * assignments (after the first '=' and after ':'s).
4362 */
4363 STPUTC(c, expdest);
4364 if (flag & EXP_VARTILDE && *p == '~') {
4365 if (c == '=') {
4366 if (firsteq)
4367 firsteq = 0;
4368 else
4369 break;
4370 }
4371 p = exptilde(p, flag);
4372 }
4373 break;
4374 default:
4375 STPUTC(c, expdest);
4376 } 4764 }
4377 } 4765 }
4766breakloop:
4767 ;
4378} 4768}
4379 4769
4380static char *exptilde(char *p, int flag) 4770static char *
4771exptilde(char *startp, char *p, int flag)
4381{ 4772{
4382 char c, *startp = p; 4773 char c;
4774 char *name;
4383 struct passwd *pw; 4775 struct passwd *pw;
4384 const char *home; 4776 const char *home;
4385 int quotes = flag & (EXP_FULL | EXP_CASE); 4777 int quotes = flag & (EXP_FULL | EXP_CASE);
4778 int startloc;
4386 4779
4387 while ((c = *p) != '\0') { 4780 name = p + 1;
4388 switch (c) { 4781
4782 while ((c = *++p) != '\0') {
4783 switch(c) {
4389 case CTLESC: 4784 case CTLESC:
4390 return (startp); 4785 return (startp);
4391 case CTLQUOTEMARK: 4786 case CTLQUOTEMARK:
@@ -4395,32 +4790,35 @@ static char *exptilde(char *p, int flag)
4395 goto done; 4790 goto done;
4396 break; 4791 break;
4397 case '/': 4792 case '/':
4793 case CTLENDVAR:
4398 goto done; 4794 goto done;
4399 } 4795 }
4400 p++;
4401 } 4796 }
4402 done: 4797done:
4403 *p = '\0'; 4798 *p = '\0';
4404 if (*(startp + 1) == '\0') { 4799 if (*name == '\0') {
4405 if ((home = lookupvar("HOME")) == NULL) 4800 if ((home = lookupvar(homestr)) == NULL)
4406 goto lose; 4801 goto lose;
4407 } else { 4802 } else {
4408 if ((pw = getpwnam(startp + 1)) == NULL) 4803 if ((pw = getpwnam(name)) == NULL)
4409 goto lose; 4804 goto lose;
4410 home = pw->pw_dir; 4805 home = pw->pw_dir;
4411 } 4806 }
4412 if (*home == '\0') 4807 if (*home == '\0')
4413 goto lose; 4808 goto lose;
4414 *p = c; 4809 *p = c;
4810 startloc = expdest - (char *)stackblock();
4415 strtodest(home, SQSYNTAX, quotes); 4811 strtodest(home, SQSYNTAX, quotes);
4812 recordregion(startloc, expdest - (char *)stackblock(), 0);
4416 return (p); 4813 return (p);
4417 lose: 4814lose:
4418 *p = c; 4815 *p = c;
4419 return (startp); 4816 return (startp);
4420} 4817}
4421 4818
4422 4819
4423static void removerecordregions(int endoff) 4820static void
4821removerecordregions(int endoff)
4424{ 4822{
4425 if (ifslastp == NULL) 4823 if (ifslastp == NULL)
4426 return; 4824 return;
@@ -4428,10 +4826,9 @@ static void removerecordregions(int endoff)
4428 if (ifsfirst.endoff > endoff) { 4826 if (ifsfirst.endoff > endoff) {
4429 while (ifsfirst.next != NULL) { 4827 while (ifsfirst.next != NULL) {
4430 struct ifsregion *ifsp; 4828 struct ifsregion *ifsp;
4431
4432 INTOFF; 4829 INTOFF;
4433 ifsp = ifsfirst.next->next; 4830 ifsp = ifsfirst.next->next;
4434 free(ifsfirst.next); 4831 ckfree(ifsfirst.next);
4435 ifsfirst.next = ifsp; 4832 ifsfirst.next = ifsp;
4436 INTON; 4833 INTON;
4437 } 4834 }
@@ -4446,13 +4843,12 @@ static void removerecordregions(int endoff)
4446 4843
4447 ifslastp = &ifsfirst; 4844 ifslastp = &ifsfirst;
4448 while (ifslastp->next && ifslastp->next->begoff < endoff) 4845 while (ifslastp->next && ifslastp->next->begoff < endoff)
4449 ifslastp = ifslastp->next; 4846 ifslastp=ifslastp->next;
4450 while (ifslastp->next != NULL) { 4847 while (ifslastp->next != NULL) {
4451 struct ifsregion *ifsp; 4848 struct ifsregion *ifsp;
4452
4453 INTOFF; 4849 INTOFF;
4454 ifsp = ifslastp->next->next; 4850 ifsp = ifslastp->next->next;
4455 free(ifslastp->next); 4851 ckfree(ifslastp->next);
4456 ifslastp->next = ifsp; 4852 ifslastp->next = ifsp;
4457 INTON; 4853 INTON;
4458 } 4854 }
@@ -4466,62 +4862,60 @@ static void removerecordregions(int endoff)
4466 * Expand arithmetic expression. Backup to start of expression, 4862 * Expand arithmetic expression. Backup to start of expression,
4467 * evaluate, place result in (backed up) result, adjust string position. 4863 * evaluate, place result in (backed up) result, adjust string position.
4468 */ 4864 */
4469static void expari(int flag) 4865void
4866expari(int quotes)
4470{ 4867{
4471 char *p, *start; 4868 char *p, *start;
4472 int errcode;
4473 int result;
4474 int begoff; 4869 int begoff;
4475 int quotes = flag & (EXP_FULL | EXP_CASE); 4870 int flag;
4476 int quoted; 4871 int len;
4477 4872
4478 /* ifsfree(); */ 4873 /* ifsfree(); */
4479 4874
4480 /* 4875 /*
4481 * This routine is slightly over-complicated for 4876 * This routine is slightly over-complicated for
4482 * efficiency. First we make sure there is 4877 * efficiency. Next we scan backwards looking for the
4483 * enough space for the result, which may be bigger 4878 * start of arithmetic.
4484 * than the expression if we add exponentation. Next we
4485 * scan backwards looking for the start of arithmetic. If the
4486 * next previous character is a CTLESC character, then we
4487 * have to rescan starting from the beginning since CTLESC
4488 * characters have to be processed left to right.
4489 */ 4879 */
4490 CHECKSTRSPACE(10, expdest);
4491 USTPUTC('\0', expdest);
4492 start = stackblock(); 4880 start = stackblock();
4493 p = expdest - 1; 4881 p = expdest - 1;
4494 while (*p != CTLARI && p >= start) 4882 *p = '\0';
4495 --p; 4883 p--;
4496 if (*p != CTLARI) 4884 do {
4497 error("missing CTLARI (shouldn't happen)"); 4885 int esc;
4498 if (p > start && *(p - 1) == CTLESC) 4886
4499 for (p = start; *p != CTLARI; p++) 4887 while (*p != CTLARI) {
4500 if (*p == CTLESC) 4888 p--;
4501 p++; 4889#ifdef DEBUG
4890 if (p < start) {
4891 error("missing CTLARI (shouldn't happen)");
4892 }
4893#endif
4894 }
4895
4896 esc = esclen(start, p);
4897 if (!(esc % 2)) {
4898 break;
4899 }
4900
4901 p -= esc + 1;
4902 } while (1);
4502 4903
4503 if (p[1] == '"')
4504 quoted = 1;
4505 else
4506 quoted = 0;
4507 begoff = p - start; 4904 begoff = p - start;
4905
4508 removerecordregions(begoff); 4906 removerecordregions(begoff);
4907
4908 flag = p[1];
4909
4910 expdest = p;
4911
4509 if (quotes) 4912 if (quotes)
4510 rmescapes(p + 2); 4913 rmescapes(p + 2);
4511 result = arith(p + 2, &errcode);
4512 if (errcode < 0) {
4513 if (errcode == -2)
4514 error("divide by zero");
4515 else
4516 error("syntax error: \"%s\"\n", p + 2);
4517 }
4518 snprintf(p, 12, "%d", result);
4519 while (*p++);
4520 4914
4521 if (quoted == 0) 4915 len = cvtnum(dash_arith(p + 2));
4522 recordregion(begoff, p - 1 - start, 0); 4916
4523 result = expdest - p + 1; 4917 if (flag != '"')
4524 STADJUST(-result, expdest); 4918 recordregion(begoff, begoff + len, 0);
4525} 4919}
4526#endif 4920#endif
4527 4921
@@ -4529,229 +4923,378 @@ static void expari(int flag)
4529 * Expand stuff in backwards quotes. 4923 * Expand stuff in backwards quotes.
4530 */ 4924 */
4531 4925
4532static void expbackq(union node *cmd, int quoted, int flag) 4926static void
4927expbackq(union node *cmd, int quoted, int quotes)
4533{ 4928{
4534 volatile struct backcmd in; 4929 struct backcmd in;
4535 int i; 4930 int i;
4536 char buf[128]; 4931 char buf[128];
4537 char *p; 4932 char *p;
4538 char *dest = expdest; 4933 char *dest;
4539 volatile struct ifsregion saveifs; 4934 int startloc;
4540 struct ifsregion *volatile savelastp; 4935 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4541 struct nodelist *volatile saveargbackq; 4936 struct stackmark smark;
4542 char lastc;
4543 int startloc = dest - stackblock();
4544 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
4545 volatile int saveherefd;
4546 int quotes = flag & (EXP_FULL | EXP_CASE);
4547 struct jmploc jmploc;
4548 struct jmploc *volatile savehandler;
4549 int ex;
4550
4551#if __GNUC__
4552 /* Avoid longjmp clobbering */
4553 (void) &dest;
4554 (void) &syntax;
4555#endif
4556
4557 in.fd = -1;
4558 in.buf = 0;
4559 in.jp = 0;
4560 4937
4561 INTOFF; 4938 INTOFF;
4562 saveifs = ifsfirst; 4939 setstackmark(&smark);
4563 savelastp = ifslastp; 4940 dest = expdest;
4564 saveargbackq = argbackq; 4941 startloc = dest - (char *)stackblock();
4565 saveherefd = herefd; 4942 grabstackstr(dest);
4566 herefd = -1;
4567 if ((ex = setjmp(jmploc.loc))) {
4568 goto err1;
4569 }
4570 savehandler = handler;
4571 handler = &jmploc;
4572 INTON;
4573 p = grabstackstr(dest);
4574 evalbackcmd(cmd, (struct backcmd *) &in); 4943 evalbackcmd(cmd, (struct backcmd *) &in);
4575 ungrabstackstr(p, dest); 4944 popstackmark(&smark);
4576 err1:
4577 INTOFF;
4578 ifsfirst = saveifs;
4579 ifslastp = savelastp;
4580 argbackq = saveargbackq;
4581 herefd = saveherefd;
4582 if (ex) {
4583 goto err2;
4584 }
4585 4945
4586 p = in.buf; 4946 p = in.buf;
4587 lastc = '\0'; 4947 i = in.nleft;
4948 if (i == 0)
4949 goto read;
4588 for (;;) { 4950 for (;;) {
4589 if (--in.nleft < 0) { 4951 memtodest(p, i, syntax, quotes);
4590 if (in.fd < 0) 4952read:
4591 break; 4953 if (in.fd < 0)
4592 i = safe_read(in.fd, buf, sizeof buf); 4954 break;
4593 TRACE(("expbackq: read returns %d\n", i)); 4955 i = safe_read(in.fd, buf, sizeof buf);
4594 if (i <= 0) 4956 TRACE(("expbackq: read returns %d\n", i));
4595 break; 4957 if (i <= 0)
4596 p = buf; 4958 break;
4597 in.nleft = i - 1; 4959 p = buf;
4598 }
4599 lastc = *p++;
4600 if (lastc != '\0') {
4601 if (quotes && SIT(lastc, syntax) == CCTL)
4602 STPUTC(CTLESC, dest);
4603 STPUTC(lastc, dest);
4604 }
4605 } 4960 }
4606 4961
4962 if (in.buf)
4963 ckfree(in.buf);
4964 if (in.fd >= 0) {
4965 close(in.fd);
4966 back_exitstatus = waitforjob(in.jp);
4967 }
4968 INTON;
4969
4607 /* Eat all trailing newlines */ 4970 /* Eat all trailing newlines */
4608 for (; dest > stackblock() && dest[-1] == '\n';) 4971 dest = expdest;
4972 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4609 STUNPUTC(dest); 4973 STUNPUTC(dest);
4974 expdest = dest;
4610 4975
4611 err2:
4612 if (in.fd >= 0)
4613 close(in.fd);
4614 free(in.buf);
4615 if (in.jp)
4616 exitstatus = waitforjob(in.jp);
4617 handler = savehandler;
4618 if (ex) {
4619 longjmp(handler->loc, 1);
4620 }
4621 if (quoted == 0) 4976 if (quoted == 0)
4622 recordregion(startloc, dest - stackblock(), 0); 4977 recordregion(startloc, dest - (char *)stackblock(), 0);
4623 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 4978 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4624 (dest - stackblock()) - startloc, 4979 (dest - (char *)stackblock()) - startloc,
4625 (dest - stackblock()) - startloc, stackblock() + startloc)); 4980 (dest - (char *)stackblock()) - startloc,
4626 expdest = dest; 4981 stackblock() + startloc));
4627 INTON;
4628} 4982}
4629 4983
4630static int 4984
4631subevalvar(char *p, char *str, int strloc, int subtype, int startloc, 4985static char *
4632 int varflags, int quotes) 4986scanleft(
4987 char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4988 int zero
4989) {
4990 char *loc;
4991 char *loc2;
4992 char c;
4993
4994 loc = startp;
4995 loc2 = rmesc;
4996 do {
4997 int match;
4998 const char *s = loc2;
4999 c = *loc2;
5000 if (zero) {
5001 *loc2 = '\0';
5002 s = rmesc;
5003 }
5004 match = pmatch(str, s);
5005 *loc2 = c;
5006 if (match)
5007 return loc;
5008 if (quotes && *loc == CTLESC)
5009 loc++;
5010 loc++;
5011 loc2++;
5012 } while (c);
5013 return 0;
5014}
5015
5016
5017static char *
5018scanright(
5019 char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5020 int zero
5021) {
5022 int esc = 0;
5023 char *loc;
5024 char *loc2;
5025
5026 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5027 int match;
5028 char c = *loc2;
5029 const char *s = loc2;
5030 if (zero) {
5031 *loc2 = '\0';
5032 s = rmesc;
5033 }
5034 match = pmatch(str, s);
5035 *loc2 = c;
5036 if (match)
5037 return loc;
5038 loc--;
5039 if (quotes) {
5040 if (--esc < 0) {
5041 esc = esclen(startp, loc);
5042 }
5043 if (esc % 2) {
5044 esc--;
5045 loc--;
5046 }
5047 }
5048 }
5049 return 0;
5050}
5051
5052static const char *
5053subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
4633{ 5054{
4634 char *startp; 5055 char *startp;
4635 char *loc = NULL; 5056 char *loc;
4636 char *q;
4637 int c = 0;
4638 int saveherefd = herefd; 5057 int saveherefd = herefd;
4639 struct nodelist *saveargbackq = argbackq; 5058 struct nodelist *saveargbackq = argbackq;
4640 int amount; 5059 int amount;
5060 char *rmesc, *rmescend;
5061 int zero;
5062 char *(*scan)(char *, char *, char *, char *, int , int);
4641 5063
4642 herefd = -1; 5064 herefd = -1;
4643 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); 5065 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4644 STACKSTRNUL(expdest); 5066 STPUTC('\0', expdest);
4645 herefd = saveherefd; 5067 herefd = saveherefd;
4646 argbackq = saveargbackq; 5068 argbackq = saveargbackq;
4647 startp = stackblock() + startloc; 5069 startp = stackblock() + startloc;
4648 if (str == NULL)
4649 str = stackblock() + strloc;
4650 5070
4651 switch (subtype) { 5071 switch (subtype) {
4652 case VSASSIGN: 5072 case VSASSIGN:
4653 setvar(str, startp, 0); 5073 setvar(str, startp, 0);
4654 amount = startp - expdest; 5074 amount = startp - expdest;
4655 STADJUST(amount, expdest); 5075 STADJUST(amount, expdest);
4656 varflags &= ~VSNUL; 5076 return startp;
4657 if (c != 0)
4658 *loc = c;
4659 return 1;
4660 5077
4661 case VSQUESTION: 5078 case VSQUESTION:
4662 if (*p != CTLENDVAR) { 5079 varunset(p, str, startp, varflags);
4663 out2fmt(snlfmt, startp);
4664 error((char *) NULL);
4665 }
4666 error("%.*s: parameter %snot set", p - str - 1,
4667 str, (varflags & VSNUL) ? "null or " : nullstr);
4668 /* NOTREACHED */ 5080 /* NOTREACHED */
5081 }
4669 5082
4670 case VSTRIMLEFT: 5083 subtype -= VSTRIMRIGHT;
4671 for (loc = startp; loc < str; loc++) { 5084#ifdef DEBUG
4672 c = *loc; 5085 if (subtype < 0 || subtype > 3)
4673 *loc = '\0'; 5086 abort();
4674 if (patmatch2(str, startp, quotes)) 5087#endif
4675 goto recordleft; 5088
4676 *loc = c; 5089 rmesc = startp;
4677 if (quotes && *loc == CTLESC) 5090 rmescend = stackblock() + strloc;
4678 loc++; 5091 if (quotes) {
5092 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5093 if (rmesc != startp) {
5094 rmescend = expdest;
5095 startp = stackblock() + startloc;
4679 } 5096 }
4680 return 0; 5097 }
5098 rmescend--;
5099 str = stackblock() + strloc;
5100 preglob(str, varflags & VSQUOTE, 0);
4681 5101
4682 case VSTRIMLEFTMAX: 5102 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
4683 for (loc = str - 1; loc >= startp;) { 5103 zero = subtype >> 1;
4684 c = *loc; 5104 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
4685 *loc = '\0'; 5105 scan = (subtype & 1) ^ zero ? scanleft : scanright;
4686 if (patmatch2(str, startp, quotes)) 5106
4687 goto recordleft; 5107 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
4688 *loc = c; 5108 if (loc) {
4689 loc--; 5109 if (zero) {
4690 if (quotes && loc > startp && *(loc - 1) == CTLESC) { 5110 memmove(startp, loc, str - loc);
4691 for (q = startp; q < loc; q++) 5111 loc = startp + (str - loc) - 1;
4692 if (*q == CTLESC)
4693 q++;
4694 if (q > loc)
4695 loc--;
4696 }
4697 } 5112 }
4698 return 0; 5113 *loc = '\0';
5114 amount = loc - expdest;
5115 STADJUST(amount, expdest);
5116 }
5117 return loc;
5118}
4699 5119
4700 case VSTRIMRIGHT: 5120
4701 for (loc = str - 1; loc >= startp;) { 5121/*
4702 if (patmatch2(str, loc, quotes)) 5122 * Expand a variable, and return a pointer to the next character in the
4703 goto recordright; 5123 * input string.
4704 loc--; 5124 */
4705 if (quotes && loc > startp && *(loc - 1) == CTLESC) { 5125static char *
4706 for (q = startp; q < loc; q++) 5126evalvar(char *p, int flag)
4707 if (*q == CTLESC) 5127{
4708 q++; 5128 int subtype;
4709 if (q > loc) 5129 int varflags;
4710 loc--; 5130 char *var;
5131 int patloc;
5132 int c;
5133 int set;
5134 int startloc;
5135 size_t varlen;
5136 int easy;
5137 int quotes;
5138 int quoted;
5139
5140 quotes = flag & (EXP_FULL | EXP_CASE);
5141 varflags = *p++;
5142 subtype = varflags & VSTYPE;
5143 quoted = varflags & VSQUOTE;
5144 var = p;
5145 easy = (!quoted || (*var == '@' && shellparam.nparam));
5146 varlen = 0;
5147 startloc = expdest - (char *)stackblock();
5148 p = strchr(p, '=') + 1;
5149
5150 if (!is_name(*var)) {
5151 set = varisset(var, varflags & VSNUL);
5152 set--;
5153 if (subtype == VSPLUS)
5154 goto vsplus;
5155 if (++set) {
5156 varvalue(var, quoted, flag);
5157 if (subtype == VSLENGTH) {
5158 varlen =
5159 expdest - (char *)stackblock() -
5160 startloc;
5161 STADJUST(-varlen, expdest);
5162 goto vslen;
4711 } 5163 }
4712 } 5164 }
4713 return 0; 5165 } else {
5166 const char *val;
5167again:
5168 /* jump here after setting a variable with ${var=text} */
5169 val = lookupvar(var);
5170 set = !val || ((varflags & VSNUL) && !*val);
5171 if (subtype == VSPLUS)
5172 goto vsplus;
5173 if (--set) {
5174 varlen = strlen(val);
5175 if (subtype == VSLENGTH)
5176 goto vslen;
5177 memtodest(
5178 val, varlen, quoted ? DQSYNTAX : BASESYNTAX,
5179 quotes
5180 );
5181 }
5182 }
4714 5183
4715 case VSTRIMRIGHTMAX: 5184
4716 for (loc = startp; loc < str - 1; loc++) { 5185 if (subtype == VSMINUS) {
4717 if (patmatch2(str, loc, quotes)) 5186vsplus:
4718 goto recordright; 5187 if (!set) {
4719 if (quotes && *loc == CTLESC) 5188 argstr(
4720 loc++; 5189 p, flag | EXP_TILDE |
5190 (quoted ? EXP_QWORD : EXP_WORD)
5191 );
5192 goto end;
4721 } 5193 }
4722 return 0; 5194 if (easy)
5195 goto record;
5196 goto end;
5197 }
5198
5199 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5200 if (!set) {
5201 if (subevalvar(p, var, 0, subtype, startloc,
5202 varflags, 0)) {
5203 varflags &= ~VSNUL;
5204 /*
5205 * Remove any recorded regions beyond
5206 * start of variable
5207 */
5208 removerecordregions(startloc);
5209 goto again;
5210 }
5211 goto end;
5212 }
5213 if (easy)
5214 goto record;
5215 goto end;
5216 }
5217
5218 if (!set && uflag)
5219 varunset(p, var, 0, 0);
5220
5221 if (subtype == VSLENGTH) {
5222vslen:
5223 cvtnum(varlen);
5224 goto record;
5225 }
5226
5227 if (subtype == VSNORMAL) {
5228 if (!easy)
5229 goto end;
5230record:
5231 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5232 goto end;
5233 }
4723 5234
4724#ifdef DEBUG 5235#ifdef DEBUG
5236 switch (subtype) {
5237 case VSTRIMLEFT:
5238 case VSTRIMLEFTMAX:
5239 case VSTRIMRIGHT:
5240 case VSTRIMRIGHTMAX:
5241 break;
4725 default: 5242 default:
4726 abort(); 5243 abort();
4727#endif
4728 } 5244 }
5245#endif
4729 5246
4730 recordleft: 5247 if (set) {
4731 *loc = c; 5248 /*
4732 amount = ((str - 1) - (loc - startp)) - expdest; 5249 * Terminate the string and start recording the pattern
4733 STADJUST(amount, expdest); 5250 * right after it
4734 while (loc != str - 1) 5251 */
4735 *startp++ = *loc++; 5252 STPUTC('\0', expdest);
4736 return 1; 5253 patloc = expdest - (char *)stackblock();
5254 if (subevalvar(p, NULL, patloc, subtype,
5255 startloc, varflags, quotes) == 0) {
5256 int amount = expdest - (
5257 (char *)stackblock() + patloc - 1
5258 );
5259 STADJUST(-amount, expdest);
5260 }
5261 /* Remove any recorded regions beyond start of variable */
5262 removerecordregions(startloc);
5263 goto record;
5264 }
4737 5265
4738 recordright: 5266end:
4739 amount = loc - expdest; 5267 if (subtype != VSNORMAL) { /* skip to end of alternative */
4740 STADJUST(amount, expdest); 5268 int nesting = 1;
4741 STPUTC('\0', expdest); 5269 for (;;) {
4742 STADJUST(-1, expdest); 5270 if ((c = *p++) == CTLESC)
4743 return 1; 5271 p++;
5272 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5273 if (set)
5274 argbackq = argbackq->next;
5275 } else if (c == CTLVAR) {
5276 if ((*p++ & VSTYPE) != VSNORMAL)
5277 nesting++;
5278 } else if (c == CTLENDVAR) {
5279 if (--nesting == 0)
5280 break;
5281 }
5282 }
5283 }
5284 return p;
4744} 5285}
4745 5286
4746 5287
5288
4747/* 5289/*
4748 * Test whether a specialized variable is set. 5290 * Test whether a specialized variable is set.
4749 */ 5291 */
4750 5292
4751static int varisset(char *name, int nulok) 5293static int
5294varisset(char *name, int nulok)
4752{ 5295{
4753 if (*name == '!') 5296 if (*name == '!')
4754 return backgndpid != -1; 5297 return backgndpid != 0;
4755 else if (*name == '@' || *name == '*') { 5298 else if (*name == '@' || *name == '*') {
4756 if (*shellparam.p == NULL) 5299 if (*shellparam.p == NULL)
4757 return 0; 5300 return 0;
@@ -4782,24 +5325,45 @@ static int varisset(char *name, int nulok)
4782 return 1; 5325 return 1;
4783} 5326}
4784 5327
5328
5329
4785/* 5330/*
4786 * Put a string on the stack. 5331 * Put a string on the stack.
4787 */ 5332 */
4788 5333
4789static void strtodest(const char *p, int syntax, int quotes) 5334static void
4790{ 5335memtodest(const char *p, size_t len, int syntax, int quotes) {
4791 while (*p) { 5336 char *q = expdest;
4792 if (quotes && SIT(*p, syntax) == CCTL) 5337
4793 STPUTC(CTLESC, expdest); 5338 q = makestrspace(len * 2, q);
4794 STPUTC(*p++, expdest); 5339
5340 while (len--) {
5341 int c = *p++;
5342 if (!c)
5343 continue;
5344 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5345 USTPUTC(CTLESC, q);
5346 USTPUTC(c, q);
4795 } 5347 }
5348
5349 expdest = q;
5350}
5351
5352
5353static void
5354strtodest(const char *p, int syntax, int quotes)
5355{
5356 memtodest(p, strlen(p), syntax, quotes);
4796} 5357}
4797 5358
5359
5360
4798/* 5361/*
4799 * Add the value of a specialized variable to the stack string. 5362 * Add the value of a specialized variable to the stack string.
4800 */ 5363 */
4801 5364
4802static void varvalue(char *name, int quoted, int flags) 5365static void
5366varvalue(char *name, int quoted, int flags)
4803{ 5367{
4804 int num; 5368 int num;
4805 char *p; 5369 char *p;
@@ -4817,20 +5381,20 @@ static void varvalue(char *name, int quoted, int flags)
4817 num = rootpid; 5381 num = rootpid;
4818 goto numvar; 5382 goto numvar;
4819 case '?': 5383 case '?':
4820 num = oexitstatus; 5384 num = exitstatus;
4821 goto numvar; 5385 goto numvar;
4822 case '#': 5386 case '#':
4823 num = shellparam.nparam; 5387 num = shellparam.nparam;
4824 goto numvar; 5388 goto numvar;
4825 case '!': 5389 case '!':
4826 num = backgndpid; 5390 num = backgndpid;
4827 numvar: 5391numvar:
4828 expdest = cvtnum(num, expdest); 5392 cvtnum(num);
4829 break; 5393 break;
4830 case '-': 5394 case '-':
4831 for (i = 0; i < NOPTS; i++) { 5395 for (i = 0 ; i < NOPTS ; i++) {
4832 if (optent_val(i)) 5396 if (optlist[i])
4833 STPUTC(optent_letter(optlist[i]), expdest); 5397 STPUTC(optletters(i), expdest);
4834 } 5398 }
4835 break; 5399 break;
4836 case '@': 5400 case '@':
@@ -4840,17 +5404,19 @@ static void varvalue(char *name, int quoted, int flags)
4840 } 5404 }
4841 /* fall through */ 5405 /* fall through */
4842 case '*': 5406 case '*':
4843 sep = ifsset()? ifsval()[0] : ' '; 5407 sep = ifsset() ? ifsval()[0] : ' ';
4844 if (quotes) { 5408 if (quotes) {
4845 sepq = SIT(sep, syntax) == CCTL; 5409 sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK);
4846 } 5410 }
4847 param: 5411param:
4848 for (ap = shellparam.p; (p = *ap++) != NULL;) { 5412 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
4849 strtodest(p, syntax, quotes); 5413 strtodest(p, syntax, quotes);
4850 if (*ap && sep) { 5414 if (*ap && sep) {
5415 p = expdest;
4851 if (sepq) 5416 if (sepq)
4852 STPUTC(CTLESC, expdest); 5417 STPUTC(CTLESC, p);
4853 STPUTC(sep, expdest); 5418 STPUTC(sep, p);
5419 expdest = p;
4854 } 5420 }
4855 } 5421 }
4856 break; 5422 break;
@@ -4867,12 +5433,14 @@ static void varvalue(char *name, int quoted, int flags)
4867} 5433}
4868 5434
4869 5435
5436
4870/* 5437/*
4871 * Record the fact that we have to scan this region of the 5438 * Record the fact that we have to scan this region of the
4872 * string for IFS characters. 5439 * string for IFS characters.
4873 */ 5440 */
4874 5441
4875static void recordregion(int start, int end, int nulonly) 5442static void
5443recordregion(int start, int end, int nulonly)
4876{ 5444{
4877 struct ifsregion *ifsp; 5445 struct ifsregion *ifsp;
4878 5446
@@ -4880,7 +5448,7 @@ static void recordregion(int start, int end, int nulonly)
4880 ifsp = &ifsfirst; 5448 ifsp = &ifsfirst;
4881 } else { 5449 } else {
4882 INTOFF; 5450 INTOFF;
4883 ifsp = (struct ifsregion *) xmalloc(sizeof(struct ifsregion)); 5451 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
4884 ifsp->next = NULL; 5452 ifsp->next = NULL;
4885 ifslastp->next = ifsp; 5453 ifslastp->next = ifsp;
4886 INTON; 5454 INTON;
@@ -4898,7 +5466,8 @@ static void recordregion(int start, int end, int nulonly)
4898 * strings to the argument list. The regions of the string to be 5466 * strings to the argument list. The regions of the string to be
4899 * searched for IFS characters have been stored by recordregion. 5467 * searched for IFS characters have been stored by recordregion.
4900 */ 5468 */
4901static void ifsbreakup(char *string, struct arglist *arglist) 5469static void
5470ifsbreakup(char *string, struct arglist *arglist)
4902{ 5471{
4903 struct ifsregion *ifsp; 5472 struct ifsregion *ifsp;
4904 struct strlist *sp; 5473 struct strlist *sp;
@@ -4911,10 +5480,10 @@ static void ifsbreakup(char *string, struct arglist *arglist)
4911 5480
4912 5481
4913 start = string; 5482 start = string;
4914 ifsspc = 0;
4915 nulonly = 0;
4916 realifs = ifsset()? ifsval() : defifs;
4917 if (ifslastp != NULL) { 5483 if (ifslastp != NULL) {
5484 ifsspc = 0;
5485 nulonly = 0;
5486 realifs = ifsset() ? ifsval() : defifs;
4918 ifsp = &ifsfirst; 5487 ifsp = &ifsfirst;
4919 do { 5488 do {
4920 p = string + ifsp->begoff; 5489 p = string + ifsp->begoff;
@@ -4935,7 +5504,7 @@ static void ifsbreakup(char *string, struct arglist *arglist)
4935 continue; 5504 continue;
4936 } 5505 }
4937 *q = '\0'; 5506 *q = '\0';
4938 sp = (struct strlist *) stalloc(sizeof *sp); 5507 sp = (struct strlist *)stalloc(sizeof *sp);
4939 sp->text = start; 5508 sp->text = start;
4940 *arglist->lastp = sp; 5509 *arglist->lastp = sp;
4941 arglist->lastp = &sp->next; 5510 arglist->lastp = &sp->next;
@@ -4948,7 +5517,7 @@ static void ifsbreakup(char *string, struct arglist *arglist)
4948 q = p; 5517 q = p;
4949 if (*p == CTLESC) 5518 if (*p == CTLESC)
4950 p++; 5519 p++;
4951 if (strchr(ifs, *p) == NULL) { 5520 if (strchr(ifs, *p) == NULL ) {
4952 p = q; 5521 p = q;
4953 break; 5522 break;
4954 } else if (strchr(defifs, *p) == NULL) { 5523 } else if (strchr(defifs, *p) == NULL) {
@@ -4968,84 +5537,83 @@ static void ifsbreakup(char *string, struct arglist *arglist)
4968 p++; 5537 p++;
4969 } 5538 }
4970 } while ((ifsp = ifsp->next) != NULL); 5539 } while ((ifsp = ifsp->next) != NULL);
4971 if (!(*start || (!ifsspc && start > string && nulonly))) { 5540 if (nulonly)
4972 return; 5541 goto add;
4973 }
4974 } 5542 }
4975 5543
4976 sp = (struct strlist *) stalloc(sizeof *sp); 5544 if (!*start)
5545 return;
5546
5547add:
5548 sp = (struct strlist *)stalloc(sizeof *sp);
4977 sp->text = start; 5549 sp->text = start;
4978 *arglist->lastp = sp; 5550 *arglist->lastp = sp;
4979 arglist->lastp = &sp->next; 5551 arglist->lastp = &sp->next;
4980} 5552}
4981 5553
4982static void ifsfree(void) 5554static void
5555ifsfree(void)
4983{ 5556{
4984 while (ifsfirst.next != NULL) { 5557 struct ifsregion *p;
4985 struct ifsregion *ifsp;
4986 5558
4987 INTOFF; 5559 INTOFF;
4988 ifsp = ifsfirst.next->next; 5560 p = ifsfirst.next;
4989 free(ifsfirst.next); 5561 do {
4990 ifsfirst.next = ifsp; 5562 struct ifsregion *ifsp;
4991 INTON; 5563 ifsp = p->next;
4992 } 5564 ckfree(p);
5565 p = ifsp;
5566 } while (p);
4993 ifslastp = NULL; 5567 ifslastp = NULL;
4994 ifsfirst.next = NULL; 5568 ifsfirst.next = NULL;
5569 INTON;
4995} 5570}
4996 5571
4997/*
4998 * Add a file name to the list.
4999 */
5000
5001static void addfname(const char *name)
5002{
5003 struct strlist *sp;
5004 size_t len = strlen(name) + 1;
5005 5572
5006 sp = (struct strlist *) stalloc(sizeof *sp);
5007 sp->text = memcpy(stalloc(len), name, len);
5008 *exparg.lastp = sp;
5009 exparg.lastp = &sp->next;
5010}
5011 5573
5012/* 5574/*
5013 * Expand shell metacharacters. At this point, the only control characters 5575 * Expand shell metacharacters. At this point, the only control characters
5014 * should be escapes. The results are stored in the list exparg. 5576 * should be escapes. The results are stored in the list exparg.
5015 */ 5577 */
5016 5578
5017#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) 5579static void
5018static void expandmeta(struct strlist *str, int flag) 5580expandmeta(str, flag)
5581 struct strlist *str;
5582 int flag;
5019{ 5583{
5020 const char *p;
5021 glob_t pglob;
5022
5023 /* TODO - EXP_REDIR */ 5584 /* TODO - EXP_REDIR */
5024 5585
5025 while (str) { 5586 while (str) {
5587 const char *p;
5588 glob_t pglob;
5589 int i;
5590
5026 if (fflag) 5591 if (fflag)
5027 goto nometa; 5592 goto nometa;
5028 p = preglob(str->text);
5029 INTOFF; 5593 INTOFF;
5030 switch (glob(p, 0, 0, &pglob)) { 5594 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5595 i = glob(p, GLOB_NOMAGIC, 0, &pglob);
5596 if (p != str->text)
5597 ckfree(p);
5598 switch (i) {
5031 case 0: 5599 case 0:
5032 if (pglob.gl_pathv[1] == 0 && !strcmp(p, pglob.gl_pathv[0])) 5600 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5033 goto nometa2; 5601 goto nometa2;
5034 addglob(&pglob); 5602 addglob(&pglob);
5035 globfree(&pglob); 5603 globfree(&pglob);
5036 INTON; 5604 INTON;
5037 break; 5605 break;
5038 case GLOB_NOMATCH: 5606 case GLOB_NOMATCH:
5039 nometa2: 5607nometa2:
5040 globfree(&pglob); 5608 globfree(&pglob);
5041 INTON; 5609 INTON;
5042 nometa: 5610nometa:
5043 *exparg.lastp = str; 5611 *exparg.lastp = str;
5044 rmescapes(str->text); 5612 rmescapes(str->text);
5045 exparg.lastp = &str->next; 5613 exparg.lastp = &str->next;
5046 break; 5614 break;
5047 default: /* GLOB_NOSPACE */ 5615 default: /* GLOB_NOSPACE */
5048 error("Out of space"); 5616 error(bb_msg_memory_exhausted);
5049 } 5617 }
5050 str = str->next; 5618 str = str->next;
5051 } 5619 }
@@ -5056,7 +5624,9 @@ static void expandmeta(struct strlist *str, int flag)
5056 * Add the result of glob(3) to the list. 5624 * Add the result of glob(3) to the list.
5057 */ 5625 */
5058 5626
5059static void addglob(const glob_t * pglob) 5627static void
5628addglob(pglob)
5629 const glob_t *pglob;
5060{ 5630{
5061 char **p = pglob->gl_pathv; 5631 char **p = pglob->gl_pathv;
5062 5632
@@ -5066,414 +5636,45 @@ static void addglob(const glob_t * pglob)
5066} 5636}
5067 5637
5068 5638
5069#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
5070static char *expdir;
5071
5072
5073static void expandmeta(struct strlist *str, int flag)
5074{
5075 char *p;
5076 struct strlist **savelastp;
5077 struct strlist *sp;
5078 char c;
5079
5080 /* TODO - EXP_REDIR */
5081
5082 while (str) {
5083 if (fflag)
5084 goto nometa;
5085 p = str->text;
5086 for (;;) { /* fast check for meta chars */
5087 if ((c = *p++) == '\0')
5088 goto nometa;
5089 if (c == '*' || c == '?' || c == '[' || c == '!')
5090 break;
5091 }
5092 savelastp = exparg.lastp;
5093 INTOFF;
5094 if (expdir == NULL) {
5095 int i = strlen(str->text);
5096
5097 expdir = xmalloc(i < 2048 ? 2048 : i); /* XXX */
5098 }
5099
5100 expmeta(expdir, str->text);
5101 free(expdir);
5102 expdir = NULL;
5103 INTON;
5104 if (exparg.lastp == savelastp) {
5105 /*
5106 * no matches
5107 */
5108 nometa:
5109 *exparg.lastp = str;
5110 rmescapes(str->text);
5111 exparg.lastp = &str->next;
5112 } else {
5113 *exparg.lastp = NULL;
5114 *savelastp = sp = expsort(*savelastp);
5115 while (sp->next != NULL)
5116 sp = sp->next;
5117 exparg.lastp = &sp->next;
5118 }
5119 str = str->next;
5120 }
5121}
5122
5123
5124/* 5639/*
5125 * Do metacharacter (i.e. *, ?, [...]) expansion. 5640 * Add a file name to the list.
5126 */
5127
5128static void expmeta(char *enddir, char *name)
5129{
5130 char *p;
5131 const char *cp;
5132 char *q;
5133 char *start;
5134 char *endname;
5135 int metaflag;
5136 struct stat statb;
5137 DIR *dirp;
5138 struct dirent *dp;
5139 int atend;
5140 int matchdot;
5141
5142 metaflag = 0;
5143 start = name;
5144 for (p = name;; p++) {
5145 if (*p == '*' || *p == '?')
5146 metaflag = 1;
5147 else if (*p == '[') {
5148 q = p + 1;
5149 if (*q == '!')
5150 q++;
5151 for (;;) {
5152 while (*q == CTLQUOTEMARK)
5153 q++;
5154 if (*q == CTLESC)
5155 q++;
5156 if (*q == '/' || *q == '\0')
5157 break;
5158 if (*++q == ']') {
5159 metaflag = 1;
5160 break;
5161 }
5162 }
5163 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
5164 metaflag = 1;
5165 } else if (*p == '\0')
5166 break;
5167 else if (*p == CTLQUOTEMARK)
5168 continue;
5169 else if (*p == CTLESC)
5170 p++;
5171 if (*p == '/') {
5172 if (metaflag)
5173 break;
5174 start = p + 1;
5175 }
5176 }
5177 if (metaflag == 0) { /* we've reached the end of the file name */
5178 if (enddir != expdir)
5179 metaflag++;
5180 for (p = name;; p++) {
5181 if (*p == CTLQUOTEMARK)
5182 continue;
5183 if (*p == CTLESC)
5184 p++;
5185 *enddir++ = *p;
5186 if (*p == '\0')
5187 break;
5188 }
5189 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5190 addfname(expdir);
5191 return;
5192 }
5193 endname = p;
5194 if (start != name) {
5195 p = name;
5196 while (p < start) {
5197 while (*p == CTLQUOTEMARK)
5198 p++;
5199 if (*p == CTLESC)
5200 p++;
5201 *enddir++ = *p++;
5202 }
5203 }
5204 if (enddir == expdir) {
5205 cp = ".";
5206 } else if (enddir == expdir + 1 && *expdir == '/') {
5207 cp = "/";
5208 } else {
5209 cp = expdir;
5210 enddir[-1] = '\0';
5211 }
5212 if ((dirp = opendir(cp)) == NULL)
5213 return;
5214 if (enddir != expdir)
5215 enddir[-1] = '/';
5216 if (*endname == 0) {
5217 atend = 1;
5218 } else {
5219 atend = 0;
5220 *endname++ = '\0';
5221 }
5222 matchdot = 0;
5223 p = start;
5224 while (*p == CTLQUOTEMARK)
5225 p++;
5226 if (*p == CTLESC)
5227 p++;
5228 if (*p == '.')
5229 matchdot++;
5230 while (!int_pending() && (dp = readdir(dirp)) != NULL) {
5231 if (dp->d_name[0] == '.' && !matchdot)
5232 continue;
5233 if (patmatch(start, dp->d_name, 0)) {
5234 if (atend) {
5235 strcpy(enddir, dp->d_name);
5236 addfname(expdir);
5237 } else {
5238 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
5239 continue;
5240 p[-1] = '/';
5241 expmeta(p, endname);
5242 }
5243 }
5244 }
5245 closedir(dirp);
5246 if (!atend)
5247 endname[-1] = '/';
5248}
5249#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
5250
5251
5252
5253#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5254/*
5255 * Sort the results of file name expansion. It calculates the number of
5256 * strings to sort and then calls msort (short for merge sort) to do the
5257 * work.
5258 */ 5641 */
5259 5642
5260static struct strlist *expsort(struct strlist *str) 5643static void
5644addfname(char *name)
5261{ 5645{
5262 int len;
5263 struct strlist *sp; 5646 struct strlist *sp;
5264 5647
5265 len = 0; 5648 sp = (struct strlist *)stalloc(sizeof *sp);
5266 for (sp = str; sp; sp = sp->next) 5649 sp->text = sstrdup(name);
5267 len++; 5650 *exparg.lastp = sp;
5268 return msort(str, len); 5651 exparg.lastp = &sp->next;
5269}
5270
5271
5272static struct strlist *msort(struct strlist *list, int len)
5273{
5274 struct strlist *p, *q = NULL;
5275 struct strlist **lpp;
5276 int half;
5277 int n;
5278
5279 if (len <= 1)
5280 return list;
5281 half = len >> 1;
5282 p = list;
5283 for (n = half; --n >= 0;) {
5284 q = p;
5285 p = p->next;
5286 }
5287 q->next = NULL; /* terminate first half of list */
5288 q = msort(list, half); /* sort first half of list */
5289 p = msort(p, len - half); /* sort second half */
5290 lpp = &list;
5291 for (;;) {
5292 if (strcmp(p->text, q->text) < 0) {
5293 *lpp = p;
5294 lpp = &p->next;
5295 if ((p = *lpp) == NULL) {
5296 *lpp = q;
5297 break;
5298 }
5299 } else {
5300 *lpp = q;
5301 lpp = &q->next;
5302 if ((q = *lpp) == NULL) {
5303 *lpp = p;
5304 break;
5305 }
5306 }
5307 }
5308 return list;
5309} 5652}
5310#endif
5311
5312 5653
5313 5654
5314/* 5655/*
5315 * Returns true if the pattern matches the string. 5656 * Returns true if the pattern matches the string.
5316 */ 5657 */
5317 5658
5318#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) 5659static inline int
5319/* squoted: string might have quote chars */ 5660patmatch(char *pattern, const char *string)
5320static int patmatch(char *pattern, char *string, int squoted)
5321{
5322 const char *p;
5323 char *q;
5324
5325 p = preglob(pattern);
5326 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5327
5328 return !fnmatch(p, q, 0);
5329}
5330
5331
5332static int patmatch2(char *pattern, char *string, int squoted)
5333{ 5661{
5334 char *p; 5662 return pmatch(preglob(pattern, 0, 0), string);
5335 int res;
5336
5337 sstrnleft--;
5338 p = grabstackstr(expdest);
5339 res = patmatch(pattern, string, squoted);
5340 ungrabstackstr(p, expdest);
5341 return res;
5342}
5343#else
5344static int patmatch(char *pattern, char *string, int squoted)
5345{
5346 return pmatch(pattern, string, squoted);
5347}
5348
5349
5350static int pmatch(char *pattern, char *string, int squoted)
5351{
5352 char *p, *q;
5353 char c;
5354
5355 p = pattern;
5356 q = string;
5357 for (;;) {
5358 switch (c = *p++) {
5359 case '\0':
5360 goto breakloop;
5361 case CTLESC:
5362 if (squoted && *q == CTLESC)
5363 q++;
5364 if (*q++ != *p++)
5365 return 0;
5366 break;
5367 case CTLQUOTEMARK:
5368 continue;
5369 case '?':
5370 if (squoted && *q == CTLESC)
5371 q++;
5372 if (*q++ == '\0')
5373 return 0;
5374 break;
5375 case '*':
5376 c = *p;
5377 while (c == CTLQUOTEMARK || c == '*')
5378 c = *++p;
5379 if (c != CTLESC && c != CTLQUOTEMARK &&
5380 c != '?' && c != '*' && c != '[') {
5381 while (*q != c) {
5382 if (squoted && *q == CTLESC && q[1] == c)
5383 break;
5384 if (*q == '\0')
5385 return 0;
5386 if (squoted && *q == CTLESC)
5387 q++;
5388 q++;
5389 }
5390 }
5391 do {
5392 if (pmatch(p, q, squoted))
5393 return 1;
5394 if (squoted && *q == CTLESC)
5395 q++;
5396 } while (*q++ != '\0');
5397 return 0;
5398 case '[':{
5399 char *endp;
5400 int invert, found;
5401 char chr;
5402
5403 endp = p;
5404 if (*endp == '!')
5405 endp++;
5406 for (;;) {
5407 while (*endp == CTLQUOTEMARK)
5408 endp++;
5409 if (*endp == '\0')
5410 goto dft; /* no matching ] */
5411 if (*endp == CTLESC)
5412 endp++;
5413 if (*++endp == ']')
5414 break;
5415 }
5416 invert = 0;
5417 if (*p == '!') {
5418 invert++;
5419 p++;
5420 }
5421 found = 0;
5422 chr = *q++;
5423 if (squoted && chr == CTLESC)
5424 chr = *q++;
5425 if (chr == '\0')
5426 return 0;
5427 c = *p++;
5428 do {
5429 if (c == CTLQUOTEMARK)
5430 continue;
5431 if (c == CTLESC)
5432 c = *p++;
5433 if (*p == '-' && p[1] != ']') {
5434 p++;
5435 while (*p == CTLQUOTEMARK)
5436 p++;
5437 if (*p == CTLESC)
5438 p++;
5439 if (chr >= c && chr <= *p)
5440 found = 1;
5441 p++;
5442 } else {
5443 if (chr == c)
5444 found = 1;
5445 }
5446 } while ((c = *p++) != ']');
5447 if (found == invert)
5448 return 0;
5449 break;
5450 }
5451 dft: default:
5452 if (squoted && *q == CTLESC)
5453 q++;
5454 if (*q++ != c)
5455 return 0;
5456 break;
5457 }
5458 }
5459 breakloop:
5460 if (*q != '\0')
5461 return 0;
5462 return 1;
5463} 5663}
5464#endif
5465
5466 5664
5467 5665
5468/* 5666/*
5469 * Remove any CTLESC characters from a string. 5667 * Remove any CTLESC characters from a string.
5470 */ 5668 */
5471 5669
5472#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) 5670static char *
5473static char *_rmescapes(char *str, int flag) 5671_rmescapes(char *str, int flag)
5474{ 5672{
5475 char *p, *q, *r; 5673 char *p, *q, *r;
5476 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; 5674 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5675 unsigned inquotes;
5676 int notescaped;
5677 int globbing;
5477 5678
5478 p = strpbrk(str, qchars); 5679 p = strpbrk(str, qchars);
5479 if (!p) { 5680 if (!p) {
@@ -5483,52 +5684,52 @@ static char *_rmescapes(char *str, int flag)
5483 r = str; 5684 r = str;
5484 if (flag & RMESCAPE_ALLOC) { 5685 if (flag & RMESCAPE_ALLOC) {
5485 size_t len = p - str; 5686 size_t len = p - str;
5687 size_t fulllen = len + strlen(p) + 1;
5486 5688
5487 q = r = stalloc(strlen(p) + len + 1); 5689 if (flag & RMESCAPE_GROW) {
5690 r = makestrspace(fulllen, expdest);
5691 } else if (flag & RMESCAPE_HEAP) {
5692 r = ckmalloc(fulllen);
5693 } else {
5694 r = stalloc(fulllen);
5695 }
5696 q = r;
5488 if (len > 0) { 5697 if (len > 0) {
5489 memcpy(q, str, len); 5698 q = mempcpy(q, str, len);
5490 q += len;
5491 } 5699 }
5492 } 5700 }
5701 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5702 globbing = flag & RMESCAPE_GLOB;
5703 notescaped = globbing;
5493 while (*p) { 5704 while (*p) {
5494 if (*p == CTLQUOTEMARK) { 5705 if (*p == CTLQUOTEMARK) {
5706 inquotes = ~inquotes;
5495 p++; 5707 p++;
5708 notescaped = globbing;
5496 continue; 5709 continue;
5497 } 5710 }
5711 if (*p == '\\') {
5712 /* naked back slash */
5713 notescaped = 0;
5714 goto copy;
5715 }
5498 if (*p == CTLESC) { 5716 if (*p == CTLESC) {
5499 p++; 5717 p++;
5500 if (flag & RMESCAPE_GLOB && *p != '/') { 5718 if (notescaped && inquotes && *p != '/') {
5501 *q++ = '\\'; 5719 *q++ = '\\';
5502 } 5720 }
5503 } 5721 }
5722 notescaped = globbing;
5723copy:
5504 *q++ = *p++; 5724 *q++ = *p++;
5505 } 5725 }
5506 *q = '\0'; 5726 *q = '\0';
5507 return r; 5727 if (flag & RMESCAPE_GROW) {
5508} 5728 expdest = r;
5509#else 5729 STADJUST(q - r + 1, expdest);
5510static void rmescapes(char *str)
5511{
5512 char *p, *q;
5513
5514 p = str;
5515 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5516 if (*p++ == '\0')
5517 return;
5518 } 5730 }
5519 q = p; 5731 return r;
5520 while (*p) {
5521 if (*p == CTLQUOTEMARK) {
5522 p++;
5523 continue;
5524 }
5525 if (*p == CTLESC)
5526 p++;
5527 *q++ = *p++;
5528 }
5529 *q = '\0';
5530} 5732}
5531#endif
5532 5733
5533 5734
5534 5735
@@ -5536,20 +5737,19 @@ static void rmescapes(char *str)
5536 * See if a pattern matches in a case statement. 5737 * See if a pattern matches in a case statement.
5537 */ 5738 */
5538 5739
5539static int casematch(union node *pattern, const char *val) 5740int
5741casematch(union node *pattern, char *val)
5540{ 5742{
5541 struct stackmark smark; 5743 struct stackmark smark;
5542 int result; 5744 int result;
5543 char *p;
5544 5745
5545 setstackmark(&smark); 5746 setstackmark(&smark);
5546 argbackq = pattern->narg.backquote; 5747 argbackq = pattern->narg.backquote;
5547 STARTSTACKSTR(expdest); 5748 STARTSTACKSTR(expdest);
5548 ifslastp = NULL; 5749 ifslastp = NULL;
5549 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 5750 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5550 STPUTC('\0', expdest); 5751 STACKSTRNUL(expdest);
5551 p = grabstackstr(expdest); 5752 result = patmatch(stackblock(), val);
5552 result = patmatch(p, (char *) val, 0);
5553 popstackmark(&smark); 5753 popstackmark(&smark);
5554 return result; 5754 return result;
5555} 5755}
@@ -5558,141 +5758,101 @@ static int casematch(union node *pattern, const char *val)
5558 * Our own itoa(). 5758 * Our own itoa().
5559 */ 5759 */
5560 5760
5561static char *cvtnum(int num, char *buf) 5761static int
5762cvtnum(long num)
5562{ 5763{
5563 int len; 5764 int len;
5564 5765
5565 CHECKSTRSPACE(32, buf); 5766 expdest = makestrspace(32, expdest);
5566 len = sprintf(buf, "%d", num); 5767 len = fmtstr(expdest, 32, "%ld", num);
5567 STADJUST(len, buf); 5768 STADJUST(len, expdest);
5568 return buf; 5769 return len;
5569} 5770}
5570 5771
5571/* 5772static void
5572 * Editline and history functions (and glue). 5773varunset(const char *end, const char *var, const char *umsg, int varflags)
5573 */
5574static int histcmd(int argc, char **argv)
5575{ 5774{
5576 error("not compiled with history support"); 5775 const char *msg;
5577 /* NOTREACHED */ 5776 const char *tail;
5578}
5579
5580
5581struct redirtab {
5582 struct redirtab *next;
5583 short renamed[10]; /* Current ash support only 0-9 descriptors */
5584 /* char on arm (and others) can't be negative */
5585};
5586 5777
5587static struct redirtab *redirlist; 5778 tail = nullstr;
5588 5779 msg = "parameter not set";
5589extern char **environ; 5780 if (umsg) {
5781 if (*end == CTLENDVAR) {
5782 if (varflags & VSNUL)
5783 tail = " or null";
5784 } else
5785 msg = umsg;
5786 }
5787 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5788}
5789/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5590 5790
5591 5791
5592 5792
5593/* 5793/*
5594 * Initialization code. 5794 * This file implements the input routines used by the parser.
5595 */ 5795 */
5596 5796
5597static void init(void) 5797#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5598{ 5798#define IBUFSIZ (BUFSIZ + 1)
5599
5600 /* from cd.c: */
5601 {
5602 curdir = nullstr;
5603 setpwd(0, 0);
5604 }
5605
5606 /* from input.c: */
5607 {
5608 basepf.nextc = basepf.buf = basebuf;
5609 }
5610
5611 /* from var.c: */
5612 {
5613 char **envp;
5614 char ppid[32];
5615
5616 initvar();
5617 for (envp = environ; *envp; envp++) {
5618 if (strchr(*envp, '=')) {
5619 setvareq(*envp, VEXPORT | VTEXTFIXED);
5620 }
5621 }
5622
5623 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
5624 setvar("PPID", ppid, 0);
5625 }
5626}
5627
5628 5799
5800static void pushfile(void);
5629 5801
5630/* 5802/*
5631 * This routine is called when an error or an interrupt occurs in an 5803 * Read a line from the script.
5632 * interactive shell and control is returned to the main command loop.
5633 */ 5804 */
5634 5805
5635/* 1 == check for aliases, 2 == also check for assignments */ 5806static inline char *
5636static int checkalias; /* also used in no alias mode for check assignments */ 5807pfgets(char *line, int len)
5637
5638static void reset(void)
5639{ 5808{
5809 char *p = line;
5810 int nleft = len;
5811 int c;
5640 5812
5641 /* from eval.c: */ 5813 while (--nleft > 0) {
5642 { 5814 c = pgetc2();
5643 evalskip = 0; 5815 if (c == PEOF) {
5644 loopnest = 0; 5816 if (p == line)
5645 funcnest = 0; 5817 return NULL;
5646 } 5818 break;
5647 5819 }
5648 /* from input.c: */ 5820 *p++ = c;
5649 { 5821 if (c == '\n')
5650 parselleft = parsenleft = 0; /* clear input buffer */ 5822 break;
5651 popallfiles();
5652 }
5653
5654 /* from parser.c: */
5655 {
5656 tokpushback = 0;
5657 checkkwd = 0;
5658 checkalias = 0;
5659 }
5660
5661 /* from redir.c: */
5662 {
5663 while (redirlist)
5664 popredir();
5665 } 5823 }
5666 5824 *p = '\0';
5825 return line;
5667} 5826}
5668 5827
5669 5828
5670
5671/* 5829/*
5672 * This file implements the input routines used by the parser. 5830 * Read a character from the script, returning PEOF on end of file.
5831 * Nul characters in the input are silently discarded.
5673 */ 5832 */
5674 5833
5675#ifdef CONFIG_FEATURE_COMMAND_EDITING 5834#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5676static const char *cmdedit_prompt; 5835
5677static inline void putprompt(const char *s) 5836#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5837#define pgetc_macro() pgetc()
5838static int
5839pgetc(void)
5678{ 5840{
5679 cmdedit_prompt = s; 5841 return pgetc_as_macro();
5680} 5842}
5681#else 5843#else
5682static inline void putprompt(const char *s) 5844#define pgetc_macro() pgetc_as_macro()
5845static int
5846pgetc(void)
5683{ 5847{
5684 out2str(s); 5848 return pgetc_macro();
5685} 5849}
5686#endif 5850#endif
5687 5851
5688#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5689
5690
5691 5852
5692/* 5853/*
5693 * Same as pgetc(), but ignores PEOA. 5854 * Same as pgetc(), but ignores PEOA.
5694 */ 5855 */
5695
5696#ifdef CONFIG_ASH_ALIAS 5856#ifdef CONFIG_ASH_ALIAS
5697static int pgetc2(void) 5857static int pgetc2(void)
5698{ 5858{
@@ -5710,45 +5870,41 @@ static inline int pgetc2(void)
5710} 5870}
5711#endif 5871#endif
5712 5872
5713/*
5714 * Read a line from the script.
5715 */
5716 5873
5717static inline char *pfgets(char *line, int len) 5874#ifdef CONFIG_FEATURE_COMMAND_EDITING
5875static const char *cmdedit_prompt;
5876static inline void putprompt(const char *s)
5718{ 5877{
5719 char *p = line; 5878 cmdedit_prompt = s;
5720 int nleft = len; 5879}
5721 int c; 5880#else
5722 5881static inline void putprompt(const char *s)
5723 while (--nleft > 0) { 5882{
5724 c = pgetc2(); 5883 out2str(s);
5725 if (c == PEOF) {
5726 if (p == line)
5727 return NULL;
5728 break;
5729 }
5730 *p++ = c;
5731 if (c == '\n')
5732 break;
5733 }
5734 *p = '\0';
5735 return line;
5736} 5884}
5885#endif
5737 5886
5738static inline int preadfd(void) 5887static inline int
5888preadfd(void)
5739{ 5889{
5740 int nr; 5890 int nr;
5741 char *buf = parsefile->buf; 5891 char *buf = parsefile->buf;
5742
5743 parsenextc = buf; 5892 parsenextc = buf;
5744 5893
5745 retry: 5894retry:
5746#ifdef CONFIG_FEATURE_COMMAND_EDITING 5895#ifdef CONFIG_FEATURE_COMMAND_EDITING
5747 { 5896 if (!iflag || parsefile->fd)
5748 if (!iflag || parsefile->fd) 5897 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5749 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 5898 else {
5750 else { 5899 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
5751 nr = cmdedit_read_input((char *) cmdedit_prompt, buf); 5900 if(nr == 0) {
5901 /* Ctrl+C presend */
5902 raise(SIGINT);
5903 goto retry;
5904 }
5905 if(nr < 0) {
5906 /* Ctrl+D presend */
5907 nr = 0;
5752 } 5908 }
5753 } 5909 }
5754#else 5910#else
@@ -5758,9 +5914,8 @@ static inline int preadfd(void)
5758 if (nr < 0) { 5914 if (nr < 0) {
5759 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 5915 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5760 int flags = fcntl(0, F_GETFL, 0); 5916 int flags = fcntl(0, F_GETFL, 0);
5761
5762 if (flags >= 0 && flags & O_NONBLOCK) { 5917 if (flags >= 0 && flags & O_NONBLOCK) {
5763 flags &= ~O_NONBLOCK; 5918 flags &=~ O_NONBLOCK;
5764 if (fcntl(0, F_SETFL, flags) >= 0) { 5919 if (fcntl(0, F_SETFL, flags) >= 0) {
5765 out2str("sh: turning off NDELAY mode\n"); 5920 out2str("sh: turning off NDELAY mode\n");
5766 goto retry; 5921 goto retry;
@@ -5771,38 +5926,6 @@ static inline int preadfd(void)
5771 return nr; 5926 return nr;
5772} 5927}
5773 5928
5774static void popstring(void)
5775{
5776 struct strpush *sp = parsefile->strpush;
5777
5778 INTOFF;
5779#ifdef CONFIG_ASH_ALIAS
5780 if (sp->ap) {
5781 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5782 if (!checkalias) {
5783 checkalias = 1;
5784 }
5785 }
5786 if (sp->string != sp->ap->val) {
5787 free(sp->string);
5788 }
5789
5790 sp->ap->flag &= ~ALIASINUSE;
5791 if (sp->ap->flag & ALIASDEAD) {
5792 unalias(sp->ap->name);
5793 }
5794 }
5795#endif
5796 parsenextc = sp->prevstring;
5797 parsenleft = sp->prevnleft;
5798/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5799 parsefile->strpush = sp->prev;
5800 if (sp != &(parsefile->basestrpush))
5801 free(sp);
5802 INTON;
5803}
5804
5805
5806/* 5929/*
5807 * Refill the input buffer and return the next input character: 5930 * Refill the input buffer and return the next input character:
5808 * 5931 *
@@ -5813,7 +5936,8 @@ static void popstring(void)
5813 * 4) Process input up to the next newline, deleting nul characters. 5936 * 4) Process input up to the next newline, deleting nul characters.
5814 */ 5937 */
5815 5938
5816static int preadbuffer(void) 5939int
5940preadbuffer(void)
5817{ 5941{
5818 char *p, *q; 5942 char *p, *q;
5819 int more; 5943 int more;
@@ -5834,7 +5958,7 @@ static int preadbuffer(void)
5834 return PEOF; 5958 return PEOF;
5835 flushall(); 5959 flushall();
5836 5960
5837 again: 5961again:
5838 if (parselleft <= 0) { 5962 if (parselleft <= 0) {
5839 if ((parselleft = preadfd()) <= 0) { 5963 if ((parselleft = preadfd()) <= 0) {
5840 parselleft = parsenleft = EOF_NLEFT; 5964 parselleft = parsenleft = EOF_NLEFT;
@@ -5848,18 +5972,18 @@ static int preadbuffer(void)
5848 for (more = 1; more;) { 5972 for (more = 1; more;) {
5849 switch (*p) { 5973 switch (*p) {
5850 case '\0': 5974 case '\0':
5851 p++; /* Skip nul */ 5975 p++; /* Skip nul */
5852 goto check; 5976 goto check;
5853 5977
5854
5855 case '\n': 5978 case '\n':
5856 parsenleft = q - parsenextc; 5979 parsenleft = q - parsenextc;
5857 more = 0; /* Stop processing here */ 5980 more = 0; /* Stop processing here */
5858 break; 5981 break;
5982
5859 } 5983 }
5860 5984
5861 *q++ = *p++; 5985 *q++ = *p++;
5862 check: 5986check:
5863 if (--parselleft <= 0 && more) { 5987 if (--parselleft <= 0 && more) {
5864 parsenleft = q - parsenextc - 1; 5988 parsenleft = q - parsenextc - 1;
5865 if (parsenleft < 0) 5989 if (parsenleft < 0)
@@ -5873,6 +5997,7 @@ static int preadbuffer(void)
5873 5997
5874 if (vflag) { 5998 if (vflag) {
5875 out2str(parsenextc); 5999 out2str(parsenextc);
6000 flushout(stderr);
5876 } 6001 }
5877 6002
5878 *q = savec; 6003 *q = savec;
@@ -5880,19 +6005,33 @@ static int preadbuffer(void)
5880 return *parsenextc++; 6005 return *parsenextc++;
5881} 6006}
5882 6007
6008/*
6009 * Undo the last call to pgetc. Only one character may be pushed back.
6010 * PEOF may be pushed back.
6011 */
6012
6013void
6014pungetc(void)
6015{
6016 parsenleft++;
6017 parsenextc--;
6018}
5883 6019
5884/* 6020/*
5885 * Push a string back onto the input at this current parsefile level. 6021 * Push a string back onto the input at this current parsefile level.
5886 * We handle aliases this way. 6022 * We handle aliases this way.
5887 */ 6023 */
5888static void pushstring(char *s, int len, void *ap) 6024void
6025pushstring(char *s, void *ap)
5889{ 6026{
5890 struct strpush *sp; 6027 struct strpush *sp;
6028 size_t len;
5891 6029
6030 len = strlen(s);
5892 INTOFF; 6031 INTOFF;
5893/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 6032/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
5894 if (parsefile->strpush) { 6033 if (parsefile->strpush) {
5895 sp = xmalloc(sizeof(struct strpush)); 6034 sp = ckmalloc(sizeof (struct strpush));
5896 sp->prev = parsefile->strpush; 6035 sp->prev = parsefile->strpush;
5897 parsefile->strpush = sp; 6036 parsefile->strpush = sp;
5898 } else 6037 } else
@@ -5900,9 +6039,9 @@ static void pushstring(char *s, int len, void *ap)
5900 sp->prevstring = parsenextc; 6039 sp->prevstring = parsenextc;
5901 sp->prevnleft = parsenleft; 6040 sp->prevnleft = parsenleft;
5902#ifdef CONFIG_ASH_ALIAS 6041#ifdef CONFIG_ASH_ALIAS
5903 sp->ap = (struct alias *) ap; 6042 sp->ap = (struct alias *)ap;
5904 if (ap) { 6043 if (ap) {
5905 ((struct alias *) ap)->flag |= ALIASINUSE; 6044 ((struct alias *)ap)->flag |= ALIASINUSE;
5906 sp->string = s; 6045 sp->string = s;
5907 } 6046 }
5908#endif 6047#endif
@@ -5911,12 +6050,88 @@ static void pushstring(char *s, int len, void *ap)
5911 INTON; 6050 INTON;
5912} 6051}
5913 6052
6053void
6054popstring(void)
6055{
6056 struct strpush *sp = parsefile->strpush;
6057
6058 INTOFF;
6059#ifdef CONFIG_ASH_ALIAS
6060 if (sp->ap) {
6061 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6062 checkkwd |= CHKALIAS;
6063 }
6064 if (sp->string != sp->ap->val) {
6065 ckfree(sp->string);
6066 }
6067 sp->ap->flag &= ~ALIASINUSE;
6068 if (sp->ap->flag & ALIASDEAD) {
6069 unalias(sp->ap->name);
6070 }
6071 }
6072#endif
6073 parsenextc = sp->prevstring;
6074 parsenleft = sp->prevnleft;
6075/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6076 parsefile->strpush = sp->prev;
6077 if (sp != &(parsefile->basestrpush))
6078 ckfree(sp);
6079 INTON;
6080}
6081
6082/*
6083 * Set the input to take input from a file. If push is set, push the
6084 * old input onto the stack first.
6085 */
6086
6087void
6088setinputfile(const char *fname, int push)
6089{
6090 int fd;
6091 int fd2;
6092
6093 INTOFF;
6094 if ((fd = open(fname, O_RDONLY)) < 0)
6095 error("Can't open %s", fname);
6096 if (fd < 10) {
6097 fd2 = copyfd(fd, 10);
6098 close(fd);
6099 if (fd2 < 0)
6100 error("Out of file descriptors");
6101 fd = fd2;
6102 }
6103 setinputfd(fd, push);
6104 INTON;
6105}
6106
6107
6108/*
6109 * Like setinputfile, but takes an open file descriptor. Call this with
6110 * interrupts off.
6111 */
6112
6113static void
6114setinputfd(int fd, int push)
6115{
6116 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6117 if (push) {
6118 pushfile();
6119 parsefile->buf = 0;
6120 }
6121 parsefile->fd = fd;
6122 if (parsefile->buf == NULL)
6123 parsefile->buf = ckmalloc(IBUFSIZ);
6124 parselleft = parsenleft = 0;
6125 plinno = 1;
6126}
6127
5914 6128
5915/* 6129/*
5916 * Like setinputfile, but takes input from a string. 6130 * Like setinputfile, but takes input from a string.
5917 */ 6131 */
5918 6132
5919static void setinputstring(char *string) 6133static void
6134setinputstring(char *string)
5920{ 6135{
5921 INTOFF; 6136 INTOFF;
5922 pushfile(); 6137 pushfile();
@@ -5934,7 +6149,8 @@ static void setinputstring(char *string)
5934 * adds a new entry to the stack and popfile restores the previous level. 6149 * adds a new entry to the stack and popfile restores the previous level.
5935 */ 6150 */
5936 6151
5937static void pushfile(void) 6152static void
6153pushfile(void)
5938{ 6154{
5939 struct parsefile *pf; 6155 struct parsefile *pf;
5940 6156
@@ -5942,7 +6158,7 @@ static void pushfile(void)
5942 parsefile->lleft = parselleft; 6158 parsefile->lleft = parselleft;
5943 parsefile->nextc = parsenextc; 6159 parsefile->nextc = parsenextc;
5944 parsefile->linno = plinno; 6160 parsefile->linno = plinno;
5945 pf = (struct parsefile *) xmalloc(sizeof(struct parsefile)); 6161 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
5946 pf->prev = parsefile; 6162 pf->prev = parsefile;
5947 pf->fd = -1; 6163 pf->fd = -1;
5948 pf->strpush = NULL; 6164 pf->strpush = NULL;
@@ -5950,75 +6166,221 @@ static void pushfile(void)
5950 parsefile = pf; 6166 parsefile = pf;
5951} 6167}
5952 6168
5953#ifdef CONFIG_ASH_JOB_CONTROL 6169
5954static void restartjob(struct job *); 6170static void
5955#endif 6171popfile(void)
5956static void freejob(struct job *); 6172{
5957static struct job *getjob(const char *); 6173 struct parsefile *pf = parsefile;
5958static int dowait(int, struct job *); 6174
6175 INTOFF;
6176 if (pf->fd >= 0)
6177 close(pf->fd);
6178 if (pf->buf)
6179 ckfree(pf->buf);
6180 while (pf->strpush)
6181 popstring();
6182 parsefile = pf->prev;
6183 ckfree(pf);
6184 parsenleft = parsefile->nleft;
6185 parselleft = parsefile->lleft;
6186 parsenextc = parsefile->nextc;
6187 plinno = parsefile->linno;
6188 INTON;
6189}
5959 6190
5960 6191
5961/* 6192/*
5962 * We keep track of whether or not fd0 has been redirected. This is for 6193 * Return to top level.
5963 * background commands, where we want to redirect fd0 to /dev/null only 6194 */
5964 * if it hasn't already been redirected.
5965*/
5966static int fd0_redirected = 0;
5967 6195
5968/* Return true if fd 0 has already been redirected at least once. */ 6196static void
5969static inline int fd0_redirected_p(void) 6197popallfiles(void)
5970{ 6198{
5971 return fd0_redirected != 0; 6199 while (parsefile != &basepf)
6200 popfile();
5972} 6201}
5973 6202
5974static void dupredirect(const union node *, int, int fd1dup);
5975 6203
5976#ifdef CONFIG_ASH_JOB_CONTROL 6204
6205/*
6206 * Close the file(s) that the shell is reading commands from. Called
6207 * after a fork is done.
6208 */
6209
6210static void
6211closescript(void)
6212{
6213 popallfiles();
6214 if (parsefile->fd > 0) {
6215 close(parsefile->fd);
6216 parsefile->fd = 0;
6217 }
6218}
6219/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6220
6221
6222/* mode flags for set_curjob */
6223#define CUR_DELETE 2
6224#define CUR_RUNNING 1
6225#define CUR_STOPPED 0
6226
6227/* mode flags for dowait */
6228#define DOWAIT_NORMAL 0
6229#define DOWAIT_BLOCK 1
6230
6231/* array of jobs */
6232static struct job *jobtab;
6233/* size of array */
6234static unsigned njobs;
6235#if JOBS
6236/* pgrp of shell on invocation */
6237static int initialpgrp;
6238static int ttyfd = -1;
6239#endif
6240/* current job */
6241static struct job *curjob;
6242/* number of presumed living untracked jobs */
6243static int jobless;
6244
6245static void set_curjob(struct job *, unsigned);
6246#if JOBS
6247static int restartjob(struct job *, int);
6248static void xtcsetpgrp(int, pid_t);
6249static char *commandtext(union node *);
6250static void cmdlist(union node *, int);
6251static void cmdtxt(union node *);
6252static void cmdputs(const char *);
6253static void showpipe(struct job *, FILE *);
6254#endif
6255static int sprint_status(char *, int, int);
6256static void freejob(struct job *);
6257static struct job *getjob(const char *, int);
6258static struct job *growjobtab(void);
6259static void forkchild(struct job *, union node *, int);
6260static void forkparent(struct job *, union node *, int, pid_t);
6261static int dowait(int, struct job *);
6262static int getstatus(struct job *);
6263
6264static void
6265set_curjob(struct job *jp, unsigned mode)
6266{
6267 struct job *jp1;
6268 struct job **jpp, **curp;
6269
6270 /* first remove from list */
6271 jpp = curp = &curjob;
6272 do {
6273 jp1 = *jpp;
6274 if (jp1 == jp)
6275 break;
6276 jpp = &jp1->prev_job;
6277 } while (1);
6278 *jpp = jp1->prev_job;
6279
6280 /* Then re-insert in correct position */
6281 jpp = curp;
6282 switch (mode) {
6283 default:
6284#ifdef DEBUG
6285 abort();
6286#endif
6287 case CUR_DELETE:
6288 /* job being deleted */
6289 break;
6290 case CUR_RUNNING:
6291 /* newly created job or backgrounded job,
6292 put after all stopped jobs. */
6293 do {
6294 jp1 = *jpp;
6295#ifdef JOBS
6296 if (!jp1 || jp1->state != JOBSTOPPED)
6297#endif
6298 break;
6299 jpp = &jp1->prev_job;
6300 } while (1);
6301 /* FALLTHROUGH */
6302#ifdef JOBS
6303 case CUR_STOPPED:
6304#endif
6305 /* newly stopped job - becomes curjob */
6306 jp->prev_job = *jpp;
6307 *jpp = jp;
6308 break;
6309 }
6310}
6311
6312#if JOBS
5977/* 6313/*
5978 * Turn job control on and off. 6314 * Turn job control on and off.
5979 * 6315 *
5980 * Note: This code assumes that the third arg to ioctl is a character 6316 * Note: This code assumes that the third arg to ioctl is a character
5981 * pointer, which is true on Berkeley systems but not System V. Since 6317 * pointer, which is true on Berkeley systems but not System V. Since
5982 * System V doesn't have job control yet, this isn't a problem now. 6318 * System V doesn't have job control yet, this isn't a problem now.
6319 *
6320 * Called with interrupts off.
5983 */ 6321 */
5984 6322
5985 6323void
5986 6324setjobctl(int on)
5987static void setjobctl(int enable)
5988{ 6325{
5989 if (enable == jobctl || rootshell == 0) 6326 int fd;
6327 int pgrp;
6328
6329 if (on == jobctl || rootshell == 0)
5990 return; 6330 return;
5991 if (enable) { 6331 if (on) {
5992 do { /* while we are in the background */ 6332 int ofd;
5993 initialpgrp = tcgetpgrp(2); 6333 ofd = fd = open(_PATH_TTY, O_RDWR);
5994 if (initialpgrp < 0) { 6334 if (fd < 0) {
5995 out2str("sh: can't access tty; job control turned off\n"); 6335 fd += 3;
5996 mflag = 0; 6336 while (!isatty(fd) && --fd >= 0)
5997 return; 6337 ;
6338 }
6339 fd = fcntl(fd, F_DUPFD, 10);
6340 close(ofd);
6341 if (fd < 0)
6342 goto out;
6343 fcntl(fd, F_SETFD, FD_CLOEXEC);
6344 do { /* while we are in the background */
6345 if ((pgrp = tcgetpgrp(fd)) < 0) {
6346out:
6347 sh_warnx("can't access tty; job control turned off");
6348 mflag = on = 0;
6349 goto close;
5998 } 6350 }
5999 if (initialpgrp == getpgrp()) 6351 if (pgrp == getpgrp())
6000 break; 6352 break;
6001 killpg(0, SIGTTIN); 6353 killpg(0, SIGTTIN);
6002 } while (1); 6354 } while (1);
6355 initialpgrp = pgrp;
6356
6003 setsignal(SIGTSTP); 6357 setsignal(SIGTSTP);
6004 setsignal(SIGTTOU); 6358 setsignal(SIGTTOU);
6005 setsignal(SIGTTIN); 6359 setsignal(SIGTTIN);
6006 setpgid(0, rootpid); 6360 pgrp = rootpid;
6007 tcsetpgrp(2, rootpid); 6361 setpgid(0, pgrp);
6008 } else { /* turning job control off */ 6362 xtcsetpgrp(fd, pgrp);
6009 setpgid(0, initialpgrp); 6363 } else {
6010 tcsetpgrp(2, initialpgrp); 6364 /* turning job control off */
6365 fd = ttyfd;
6366 pgrp = initialpgrp;
6367 xtcsetpgrp(fd, pgrp);
6368 setpgid(0, pgrp);
6011 setsignal(SIGTSTP); 6369 setsignal(SIGTSTP);
6012 setsignal(SIGTTOU); 6370 setsignal(SIGTTOU);
6013 setsignal(SIGTTIN); 6371 setsignal(SIGTTIN);
6372close:
6373 close(fd);
6374 fd = -1;
6014 } 6375 }
6015 jobctl = enable; 6376 ttyfd = fd;
6377 jobctl = on;
6016} 6378}
6017#endif
6018
6019 6379
6020#ifdef CONFIG_ASH_JOB_CONTROL 6380static int
6021static int killcmd(int argc, char **argv) 6381killcmd(argc, argv)
6382 int argc;
6383 char **argv;
6022{ 6384{
6023 int signo = -1; 6385 int signo = -1;
6024 int list = 0; 6386 int list = 0;
@@ -6027,135 +6389,283 @@ static int killcmd(int argc, char **argv)
6027 struct job *jp; 6389 struct job *jp;
6028 6390
6029 if (argc <= 1) { 6391 if (argc <= 1) {
6030 usage: 6392usage:
6031 error 6393 error(
6032 ("Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n" 6394"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6033 "kill -l [exitstatus]"); 6395"kill -l [exitstatus]"
6396 );
6034 } 6397 }
6035 6398
6036 if (*argv[1] == '-') { 6399 if (**++argv == '-') {
6037 signo = decode_signal(argv[1] + 1, 1); 6400 signo = decode_signal(*argv + 1, 1);
6038 if (signo < 0) { 6401 if (signo < 0) {
6039 int c; 6402 int c;
6040 6403
6041 while ((c = nextopt("ls:")) != '\0') 6404 while ((c = nextopt("ls:")) != '\0')
6042 switch (c) { 6405 switch (c) {
6406 default:
6407#ifdef DEBUG
6408 abort();
6409#endif
6043 case 'l': 6410 case 'l':
6044 list = 1; 6411 list = 1;
6045 break; 6412 break;
6046 case 's': 6413 case 's':
6047 signo = decode_signal(optionarg, 1); 6414 signo = decode_signal(optionarg, 1);
6048 if (signo < 0) { 6415 if (signo < 0) {
6049 error("invalid signal number or name: %s", optionarg); 6416 error(
6417 "invalid signal number or name: %s",
6418 optionarg
6419 );
6050 } 6420 }
6051 break; 6421 break;
6052#ifdef DEBUG
6053 default:
6054 error("nextopt returned character code 0%o", c);
6055#endif
6056 } 6422 }
6423 argv = argptr;
6057 } else 6424 } else
6058 argptr++; 6425 argv++;
6059 } 6426 }
6060 6427
6061 if (!list && signo < 0) 6428 if (!list && signo < 0)
6062 signo = SIGTERM; 6429 signo = SIGTERM;
6063 6430
6064 if ((signo < 0 || !*argptr) ^ list) { 6431 if ((signo < 0 || !*argv) ^ list) {
6065 goto usage; 6432 goto usage;
6066 } 6433 }
6067 6434
6068 if (list) { 6435 if (list) {
6069 const char *name; 6436 const char *name;
6070 6437
6071 if (!*argptr) { 6438 if (!*argv) {
6072 out1str("0\n");
6073 for (i = 1; i < NSIG; i++) { 6439 for (i = 1; i < NSIG; i++) {
6074 name = u_signal_names(0, &i, 1); 6440 name = u_signal_names(0, &i, 1);
6075 if (name) 6441 if (name)
6076 puts(name); 6442 out1fmt(snlfmt, name);
6077 } 6443 }
6078 return 0; 6444 return 0;
6079 } 6445 }
6080 name = u_signal_names(*argptr, &signo, -1); 6446 name = u_signal_names(*argptr, &signo, -1);
6081 if (name) 6447 if (name)
6082 puts(name); 6448 out1fmt(snlfmt, name);
6083 else 6449 else
6084 error("invalid signal number or exit status: %s", *argptr); 6450 error("invalid signal number or exit status: %s", *argptr);
6085 return 0; 6451 return 0;
6086 } 6452 }
6087 6453
6454 i = 0;
6088 do { 6455 do {
6089 if (**argptr == '%') { 6456 if (**argv == '%') {
6090 jp = getjob(*argptr); 6457 jp = getjob(*argv, 0);
6091 if (jp->jobctl == 0)
6092 error("job %s not created under job control", *argptr);
6093 pid = -jp->ps[0].pid; 6458 pid = -jp->ps[0].pid;
6094 } else 6459 } else
6095 pid = atoi(*argptr); 6460 pid = number(*argv);
6096 if (kill(pid, signo) != 0) 6461 if (kill(pid, signo) != 0) {
6097 error("%s: %m", *argptr); 6462 sh_warnx("%m\n");
6098 } while (*++argptr); 6463 i = 1;
6464 }
6465 } while (*++argv);
6099 6466
6100 return 0; 6467 return i;
6101} 6468}
6469#endif /* JOBS */
6102 6470
6103static int fgcmd(int argc, char **argv) 6471#if defined(JOBS) || defined(DEBUG)
6472static int
6473jobno(const struct job *jp)
6104{ 6474{
6105 struct job *jp; 6475 return jp - jobtab + 1;
6106 int pgrp;
6107 int status;
6108
6109 jp = getjob(argv[1]);
6110 if (jp->jobctl == 0)
6111 error("job not created under job control");
6112 pgrp = jp->ps[0].pid;
6113 ioctl(2, TIOCSPGRP, (char *) &pgrp);
6114 restartjob(jp);
6115 status = waitforjob(jp);
6116 return status;
6117} 6476}
6477#endif
6118 6478
6119 6479#ifdef JOBS
6120static int bgcmd(int argc, char **argv) 6480static int
6481fgcmd(int argc, char **argv)
6121{ 6482{
6122 struct job *jp; 6483 struct job *jp;
6484 FILE *out;
6485 int mode;
6486 int retval;
6123 6487
6488 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6489 nextopt(nullstr);
6490 argv = argptr;
6491 out = stdout;
6124 do { 6492 do {
6125 jp = getjob(*++argv); 6493 jp = getjob(*argv, 1);
6126 if (jp->jobctl == 0) 6494 if (mode == FORK_BG) {
6127 error("job not created under job control"); 6495 set_curjob(jp, CUR_RUNNING);
6128 restartjob(jp); 6496 fprintf(out, "[%d] ", jobno(jp));
6129 } while (--argc > 1); 6497 }
6130 return 0; 6498 outstr(jp->ps->cmd, out);
6499 showpipe(jp, out);
6500 retval = restartjob(jp, mode);
6501 } while (*argv && *++argv);
6502 return retval;
6131} 6503}
6132 6504
6505static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6506
6133 6507
6134static void restartjob(struct job *jp) 6508static int
6509restartjob(struct job *jp, int mode)
6135{ 6510{
6136 struct procstat *ps; 6511 struct procstat *ps;
6137 int i; 6512 int i;
6513 int status;
6514 pid_t pgid;
6138 6515
6139 if (jp->state == JOBDONE)
6140 return;
6141 INTOFF; 6516 INTOFF;
6142 killpg(jp->ps[0].pid, SIGCONT); 6517 if (jp->state == JOBDONE)
6143 for (ps = jp->ps, i = jp->nprocs; --i >= 0; ps++) { 6518 goto out;
6519 jp->state = JOBRUNNING;
6520 pgid = jp->ps->pid;
6521 if (mode == FORK_FG)
6522 xtcsetpgrp(ttyfd, pgid);
6523 killpg(pgid, SIGCONT);
6524 ps = jp->ps;
6525 i = jp->nprocs;
6526 do {
6144 if (WIFSTOPPED(ps->status)) { 6527 if (WIFSTOPPED(ps->status)) {
6145 ps->status = -1; 6528 ps->status = -1;
6146 jp->state = 0;
6147 } 6529 }
6148 } 6530 } while (ps++, --i);
6531out:
6532 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6149 INTON; 6533 INTON;
6534 return status;
6150} 6535}
6151#endif 6536#endif
6152 6537
6153static void showjobs(int change); 6538static int
6539sprint_status(char *s, int status, int sigonly)
6540{
6541 int col;
6542 int st;
6154 6543
6544 col = 0;
6545 st = WEXITSTATUS(status);
6546 if (!WIFEXITED(status)) {
6547 st = WSTOPSIG(status);
6548#if JOBS
6549 if (!WIFSTOPPED(status))
6550 st = WTERMSIG(status);
6551#endif
6552 if (sigonly) {
6553 if (st == SIGINT || st == SIGPIPE)
6554 goto out;
6555 if (WIFSTOPPED(status))
6556 goto out;
6557 }
6558 st &= 0x7f;
6559 col = fmtstr(s, 32, u_signal_names(NULL, &st, 0));
6560 if (WCOREDUMP(status)) {
6561 col += fmtstr(s + col, 16, " (core dumped)");
6562 }
6563 } else if (!sigonly) {
6564 if (st)
6565 col = fmtstr(s, 16, "Done(%d)", st);
6566 else
6567 col = fmtstr(s, 16, "Done");
6568 }
6155 6569
6156static int jobscmd(int argc, char **argv) 6570out:
6571 return col;
6572}
6573
6574#if JOBS
6575static void
6576showjob(FILE *out, struct job *jp, int mode)
6157{ 6577{
6158 showjobs(0); 6578 struct procstat *ps;
6579 struct procstat *psend;
6580 int col;
6581 int indent;
6582 char s[80];
6583
6584 ps = jp->ps;
6585
6586 if (mode & SHOW_PGID) {
6587 /* just output process (group) id of pipeline */
6588 fprintf(out, "%d\n", ps->pid);
6589 return;
6590 }
6591
6592 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6593 indent = col;
6594
6595 if (jp == curjob)
6596 s[col - 2] = '+';
6597 else if (curjob && jp == curjob->prev_job)
6598 s[col - 2] = '-';
6599
6600 if (mode & SHOW_PID)
6601 col += fmtstr(s + col, 16, "%d ", ps->pid);
6602
6603 psend = ps + jp->nprocs;
6604
6605 if (jp->state == JOBRUNNING) {
6606 scopy("Running", s + col);
6607 col += strlen("Running");
6608 } else {
6609 int status = psend[-1].status;
6610#if JOBS
6611 if (jp->state == JOBSTOPPED)
6612 status = jp->stopstatus;
6613#endif
6614 col += sprint_status(s + col, status, 0);
6615 }
6616
6617 goto start;
6618
6619 do {
6620 /* for each process */
6621 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6622
6623start:
6624 fprintf(
6625 out, "%s%*c%s",
6626 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6627 );
6628 if (!(mode & SHOW_PID)) {
6629 showpipe(jp, out);
6630 break;
6631 }
6632 if (++ps == psend) {
6633 outcslow('\n', out);
6634 break;
6635 }
6636 } while (1);
6637
6638 jp->changed = 0;
6639
6640 if (jp->state == JOBDONE) {
6641 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6642 freejob(jp);
6643 }
6644}
6645
6646
6647static int
6648jobscmd(int argc, char **argv)
6649{
6650 int mode, m;
6651 FILE *out;
6652
6653 mode = 0;
6654 while ((m = nextopt("lp")))
6655 if (m == 'l')
6656 mode = SHOW_PID;
6657 else
6658 mode = SHOW_PGID;
6659
6660 out = stdout;
6661 argv = argptr;
6662 if (*argv)
6663 do
6664 showjob(out, getjob(*argv,0), mode);
6665 while (*++argv);
6666 else
6667 showjobs(out, mode);
6668
6159 return 0; 6669 return 0;
6160} 6670}
6161 6671
@@ -6163,146 +6673,107 @@ static int jobscmd(int argc, char **argv)
6163/* 6673/*
6164 * Print a list of jobs. If "change" is nonzero, only print jobs whose 6674 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6165 * statuses have changed since the last call to showjobs. 6675 * statuses have changed since the last call to showjobs.
6166 *
6167 * If the shell is interrupted in the process of creating a job, the
6168 * result may be a job structure containing zero processes. Such structures
6169 * will be freed here.
6170 */ 6676 */
6171 6677
6172static void showjobs(int change) 6678static void
6679showjobs(FILE *out, int mode)
6173{ 6680{
6174 int jobno;
6175 int procno;
6176 int i;
6177 struct job *jp; 6681 struct job *jp;
6178 struct procstat *ps;
6179 int col;
6180 char s[64];
6181 6682
6182 TRACE(("showjobs(%d) called\n", change)); 6683 TRACE(("showjobs(%x) called\n", mode));
6183 while (dowait(0, (struct job *) NULL) > 0); 6684
6184 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { 6685 /* If not even one one job changed, there is nothing to do */
6185 if (!jp->used) 6686 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6186 continue; 6687 continue;
6187 if (jp->nprocs == 0) { 6688
6188 freejob(jp); 6689 for (jp = curjob; jp; jp = jp->prev_job) {
6189 continue; 6690 if (!(mode & SHOW_CHANGED) || jp->changed)
6190 } 6691 showjob(out, jp, mode);
6191 if (change && !jp->changed)
6192 continue;
6193 procno = jp->nprocs;
6194 for (ps = jp->ps;; ps++) { /* for each process */
6195 if (ps == jp->ps)
6196 snprintf(s, 64, "[%d] %ld ", jobno, (long) ps->pid);
6197 else
6198 snprintf(s, 64, " %ld ", (long) ps->pid);
6199 out1str(s);
6200 col = strlen(s);
6201 s[0] = '\0';
6202 if (ps->status == -1) {
6203 /* don't print anything */
6204 } else if (WIFEXITED(ps->status)) {
6205 snprintf(s, 64, "Exit %d", WEXITSTATUS(ps->status));
6206 } else {
6207#ifdef CONFIG_ASH_JOB_CONTROL
6208 if (WIFSTOPPED(ps->status))
6209 i = WSTOPSIG(ps->status);
6210 else /* WIFSIGNALED(ps->status) */
6211#endif
6212 i = WTERMSIG(ps->status);
6213 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
6214 strcpy(s, sys_siglist[i & 0x7F]);
6215 else
6216 snprintf(s, 64, "Signal %d", i & 0x7F);
6217 if (WCOREDUMP(ps->status))
6218 strcat(s, " (core dumped)");
6219 }
6220 out1str(s);
6221 col += strlen(s);
6222 printf("%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ', ps->cmd);
6223 if (--procno <= 0)
6224 break;
6225 }
6226 jp->changed = 0;
6227 if (jp->state == JOBDONE) {
6228 freejob(jp);
6229 }
6230 } 6692 }
6231} 6693}
6232 6694#endif /* JOBS */
6233 6695
6234/* 6696/*
6235 * Mark a job structure as unused. 6697 * Mark a job structure as unused.
6236 */ 6698 */
6237 6699
6238static void freejob(struct job *jp) 6700static void
6701freejob(struct job *jp)
6239{ 6702{
6240 const struct procstat *ps; 6703 struct procstat *ps;
6241 int i; 6704 int i;
6242 6705
6243 INTOFF; 6706 INTOFF;
6244 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { 6707 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6245 if (ps->cmd != nullstr) 6708 if (ps->cmd != nullstr)
6246 free(ps->cmd); 6709 ckfree(ps->cmd);
6247 } 6710 }
6248 if (jp->ps != &jp->ps0) 6711 if (jp->ps != &jp->ps0)
6249 free(jp->ps); 6712 ckfree(jp->ps);
6250 jp->used = 0; 6713 jp->used = 0;
6251#ifdef CONFIG_ASH_JOB_CONTROL 6714 set_curjob(jp, CUR_DELETE);
6252 if (curjob == jp - jobtab + 1)
6253 curjob = 0;
6254#endif
6255 INTON; 6715 INTON;
6256} 6716}
6257 6717
6258 6718
6259 6719static int
6260static int waitcmd(int argc, char **argv) 6720waitcmd(int argc, char **argv)
6261{ 6721{
6262 struct job *job; 6722 struct job *job;
6263 int status, retval; 6723 int retval;
6264 struct job *jp; 6724 struct job *jp;
6265 6725
6266 if (--argc > 0) { 6726 EXSIGON();
6267 start: 6727
6268 job = getjob(*++argv); 6728 nextopt(nullstr);
6269 } else { 6729 retval = 0;
6270 job = NULL; 6730
6271 } 6731 argv = argptr;
6272 for (;;) { /* loop until process terminated or stopped */ 6732 if (!*argv) {
6273 if (job != NULL) { 6733 /* wait for all jobs */
6274 if (job->state) { 6734 for (;;) {
6275 status = job->ps[job->nprocs - 1].status; 6735 jp = curjob;
6276 if (!iflag) 6736 while (1) {
6277 freejob(job); 6737 if (!jp) {
6278 if (--argc) { 6738 /* no running procs */
6279 goto start; 6739 goto out;
6280 }
6281 if (WIFEXITED(status))
6282 retval = WEXITSTATUS(status);
6283#ifdef CONFIG_ASH_JOB_CONTROL
6284 else if (WIFSTOPPED(status))
6285 retval = WSTOPSIG(status) + 128;
6286#endif
6287 else {
6288 /* XXX: limits number of signals */
6289 retval = WTERMSIG(status) + 128;
6290 }
6291 return retval;
6292 }
6293 } else {
6294 for (jp = jobtab;; jp++) {
6295 if (jp >= jobtab + njobs) { /* no running procs */
6296 return 0;
6297 } 6740 }
6298 if (jp->used && jp->state == 0) 6741 if (jp->state == JOBRUNNING)
6299 break; 6742 break;
6743 jp->waited = 1;
6744 jp = jp->prev_job;
6300 } 6745 }
6301 } 6746 dowait(DOWAIT_BLOCK, 0);
6302 if (dowait(2, 0) < 0 && errno == EINTR) {
6303 return 129;
6304 } 6747 }
6305 } 6748 }
6749
6750 retval = 127;
6751 do {
6752 if (**argv != '%') {
6753 pid_t pid = number(*argv);
6754 job = curjob;
6755 goto start;
6756 do {
6757 if (job->ps[job->nprocs - 1].pid == pid)
6758 break;
6759 job = job->prev_job;
6760start:
6761 if (!job)
6762 goto repeat;
6763 } while (1);
6764 } else
6765 job = getjob(*argv, 0);
6766 /* loop until process terminated or stopped */
6767 while (job->state == JOBRUNNING)
6768 dowait(DOWAIT_BLOCK, 0);
6769 job->waited = 1;
6770 retval = getstatus(job);
6771repeat:
6772 ;
6773 } while (*++argv);
6774
6775out:
6776 return retval;
6306} 6777}
6307 6778
6308 6779
@@ -6311,112 +6782,177 @@ static int waitcmd(int argc, char **argv)
6311 * Convert a job name to a job structure. 6782 * Convert a job name to a job structure.
6312 */ 6783 */
6313 6784
6314static struct job *getjob(const char *name) 6785static struct job *
6786getjob(const char *name, int getctl)
6315{ 6787{
6316 int jobno;
6317 struct job *jp; 6788 struct job *jp;
6318 int pid; 6789 struct job *found;
6319 int i; 6790 const char *err_msg = "No such job: %s";
6791 unsigned num;
6792 int c;
6793 const char *p;
6794 char *(*match)(const char *, const char *);
6320 6795
6321 if (name == NULL) { 6796 jp = curjob;
6322#ifdef CONFIG_ASH_JOB_CONTROL 6797 p = name;
6323 currentjob: 6798 if (!p)
6324 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) 6799 goto currentjob;
6325 error("No current job"); 6800
6326 return &jobtab[jobno - 1]; 6801 if (*p != '%')
6327#else 6802 goto err;
6328 error("No current job"); 6803
6329#endif 6804 c = *++p;
6330 } else if (name[0] == '%') { 6805 if (!c)
6331 if (is_digit(name[1])) { 6806 goto currentjob;
6332 jobno = number(name + 1); 6807
6333 if (jobno > 0 && jobno <= njobs && jobtab[jobno - 1].used != 0) 6808 if (!p[1]) {
6334 return &jobtab[jobno - 1]; 6809 if (c == '+' || c == '%') {
6335#ifdef CONFIG_ASH_JOB_CONTROL 6810currentjob:
6336 } else if (name[1] == '%' && name[2] == '\0') { 6811 err_msg = "No current job";
6337 goto currentjob; 6812 goto check;
6338#endif 6813 } else if (c == '-') {
6339 } else { 6814 if (jp)
6340 struct job *found = NULL; 6815 jp = jp->prev_job;
6341 6816 err_msg = "No previous job";
6342 for (jp = jobtab, i = njobs; --i >= 0; jp++) { 6817check:
6343 if (jp->used && jp->nprocs > 0 6818 if (!jp)
6344 && prefix(name + 1, jp->ps[0].cmd)) { 6819 goto err;
6345 if (found) 6820 goto gotit;
6346 error("%s: ambiguous", name);
6347 found = jp;
6348 }
6349 }
6350 if (found)
6351 return found;
6352 } 6821 }
6353 } else if (is_number(name, &pid)) { 6822 }
6354 for (jp = jobtab, i = njobs; --i >= 0; jp++) { 6823
6355 if (jp->used && jp->nprocs > 0 6824 if (is_number(p)) {
6356 && jp->ps[jp->nprocs - 1].pid == pid) 6825 num = atoi(p);
6357 return jp; 6826 if (num < njobs) {
6827 jp = jobtab + num - 1;
6828 if (jp->used)
6829 goto gotit;
6830 goto err;
6358 } 6831 }
6359 } 6832 }
6360 error("No such job: %s", name); 6833
6361 /* NOTREACHED */ 6834 match = prefix;
6835 if (*p == '?') {
6836 match = strstr;
6837 p++;
6838 }
6839
6840 found = 0;
6841 while (1) {
6842 if (!jp)
6843 goto err;
6844 if (match(jp->ps[0].cmd, p)) {
6845 if (found)
6846 goto err;
6847 found = jp;
6848 err_msg = "%s: ambiguous";
6849 }
6850 jp = jp->prev_job;
6851 }
6852
6853gotit:
6854#if JOBS
6855 err_msg = "job %s not created under job control";
6856 if (getctl && jp->jobctl == 0)
6857 goto err;
6858#endif
6859 return jp;
6860err:
6861 error(err_msg, name);
6362} 6862}
6363 6863
6364 6864
6365 6865
6366/* 6866/*
6367 * Return a new job structure, 6867 * Return a new job structure.
6868 * Called with interrupts off.
6368 */ 6869 */
6369 6870
6370static struct job *makejob(const union node *node, int nprocs) 6871static struct job *
6872makejob(union node *node, int nprocs)
6371{ 6873{
6372 int i; 6874 int i;
6373 struct job *jp; 6875 struct job *jp;
6374 6876
6375 for (i = njobs, jp = jobtab;; jp++) { 6877 for (i = njobs, jp = jobtab ; ; jp++) {
6376 if (--i < 0) { 6878 if (--i < 0) {
6377 INTOFF; 6879 jp = growjobtab();
6378 if (njobs == 0) {
6379 jobtab = xmalloc(4 * sizeof jobtab[0]);
6380 } else {
6381 jp = xmalloc((njobs + 4) * sizeof jobtab[0]);
6382 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6383 /* Relocate `ps' pointers */
6384 for (i = 0; i < njobs; i++)
6385 if (jp[i].ps == &jobtab[i].ps0)
6386 jp[i].ps = &jp[i].ps0;
6387 free(jobtab);
6388 jobtab = jp;
6389 }
6390 jp = jobtab + njobs;
6391 for (i = 4; --i >= 0; jobtab[njobs++].used = 0);
6392 INTON;
6393 break; 6880 break;
6394 } 6881 }
6395 if (jp->used == 0) 6882 if (jp->used == 0)
6396 break; 6883 break;
6884 if (jp->state != JOBDONE || !jp->waited)
6885 continue;
6886#if JOBS
6887 if (jobctl)
6888 continue;
6889#endif
6890 freejob(jp);
6891 break;
6397 } 6892 }
6398 INTOFF; 6893 memset(jp, 0, sizeof(*jp));
6399 jp->state = 0; 6894#if JOBS
6400 jp->used = 1; 6895 if (jobctl)
6401 jp->changed = 0; 6896 jp->jobctl = 1;
6402 jp->nprocs = 0;
6403#ifdef CONFIG_ASH_JOB_CONTROL
6404 jp->jobctl = jobctl;
6405#endif 6897#endif
6898 jp->prev_job = curjob;
6899 curjob = jp;
6900 jp->used = 1;
6901 jp->ps = &jp->ps0;
6406 if (nprocs > 1) { 6902 if (nprocs > 1) {
6407 jp->ps = xmalloc(nprocs * sizeof(struct procstat)); 6903 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6408 } else {
6409 jp->ps = &jp->ps0;
6410 } 6904 }
6411 INTON; 6905 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6412 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long) node, nprocs, 6906 jobno(jp)));
6413 jp - jobtab + 1)); 6907 return jp;
6908}
6909
6910static struct job *
6911growjobtab(void)
6912{
6913 size_t len;
6914 ptrdiff_t offset;
6915 struct job *jp, *jq;
6916
6917 len = njobs * sizeof(*jp);
6918 jq = jobtab;
6919 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
6920
6921 offset = (char *)jp - (char *)jq;
6922 if (offset) {
6923 /* Relocate pointers */
6924 size_t l = len;
6925
6926 jq = (struct job *)((char *)jq + l);
6927 while (l) {
6928 l -= sizeof(*jp);
6929 jq--;
6930#define joff(p) ((struct job *)((char *)(p) + l))
6931#define jmove(p) (p) = (void *)((char *)(p) + offset)
6932 if (likely(joff(jp)->ps == &jq->ps0))
6933 jmove(joff(jp)->ps);
6934 if (joff(jp)->prev_job)
6935 jmove(joff(jp)->prev_job);
6936 }
6937 if (curjob)
6938 jmove(curjob);
6939#undef joff
6940#undef jmove
6941 }
6942
6943 njobs += 4;
6944 jobtab = jp;
6945 jp = (struct job *)((char *)jp + len);
6946 jq = jp + 3;
6947 do {
6948 jq->used = 0;
6949 } while (--jq >= jp);
6414 return jp; 6950 return jp;
6415} 6951}
6416 6952
6417 6953
6418/* 6954/*
6419 * Fork of a subshell. If we are doing job control, give the subshell its 6955 * Fork off a subshell. If we are doing job control, give the subshell its
6420 * own process group. Jp is a job structure that the job is to be added to. 6956 * own process group. Jp is a job structure that the job is to be added to.
6421 * N is the command that will be evaluated by the child. Both jp and n may 6957 * N is the command that will be evaluated by the child. Both jp and n may
6422 * be NULL. The mode parameter can be one of the following: 6958 * be NULL. The mode parameter can be one of the following:
@@ -6428,103 +6964,114 @@ static struct job *makejob(const union node *node, int nprocs)
6428 * When job control is turned off, background processes have their standard 6964 * When job control is turned off, background processes have their standard
6429 * input redirected to /dev/null (except for the second and later processes 6965 * input redirected to /dev/null (except for the second and later processes
6430 * in a pipeline). 6966 * in a pipeline).
6967 *
6968 * Called with interrupts off.
6431 */ 6969 */
6432 6970
6433 6971static inline void
6434 6972forkchild(struct job *jp, union node *n, int mode)
6435static int forkshell(struct job *jp, const union node *n, int mode)
6436{ 6973{
6437 int pid; 6974 int wasroot;
6438 6975
6439#ifdef CONFIG_ASH_JOB_CONTROL 6976 TRACE(("Child shell %d\n", getpid()));
6440 int pgrp; 6977 wasroot = rootshell;
6441#endif 6978 rootshell = 0;
6442 const char *devnull = _PATH_DEVNULL;
6443 const char *nullerr = "Can't open %s";
6444 6979
6445 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long) n, 6980 closescript();
6446 mode)); 6981 clear_traps();
6447 INTOFF; 6982#if JOBS
6448 pid = fork(); 6983 /* do job control only in root shell */
6449 if (pid == -1) { 6984 jobctl = 0;
6450 TRACE(("Fork failed, errno=%d\n", errno)); 6985 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
6451 INTON; 6986 pid_t pgrp;
6452 error("Cannot fork");
6453 }
6454 if (pid == 0) {
6455 struct job *p;
6456 int wasroot;
6457 int i;
6458 6987
6459 TRACE(("Child shell %d\n", getpid())); 6988 if (jp->nprocs == 0)
6460 wasroot = rootshell; 6989 pgrp = getpid();
6461 rootshell = 0; 6990 else
6462 closescript(); 6991 pgrp = jp->ps[0].pid;
6463 INTON; 6992 /* This can fail because we are doing it in the parent also */
6464 clear_traps(); 6993 (void)setpgid(0, pgrp);
6465#ifdef CONFIG_ASH_JOB_CONTROL 6994 if (mode == FORK_FG)
6466 jobctl = 0; /* do job control only in root shell */ 6995 xtcsetpgrp(ttyfd, pgrp);
6467 if (wasroot && mode != FORK_NOJOB && mflag) { 6996 setsignal(SIGTSTP);
6468 if (jp == NULL || jp->nprocs == 0) 6997 setsignal(SIGTTOU);
6469 pgrp = getpid(); 6998 } else
6470 else
6471 pgrp = jp->ps[0].pid;
6472 setpgid(0, pgrp);
6473 if (mode == FORK_FG) {
6474 /*** this causes superfluous TIOCSPGRPS ***/
6475 if (tcsetpgrp(2, pgrp) < 0)
6476 error("tcsetpgrp failed, errno=%d", errno);
6477 }
6478 setsignal(SIGTSTP);
6479 setsignal(SIGTTOU);
6480 } else if (mode == FORK_BG) {
6481#else
6482 if (mode == FORK_BG) {
6483#endif 6999#endif
6484 ignoresig(SIGINT); 7000 if (mode == FORK_BG) {
6485 ignoresig(SIGQUIT); 7001 ignoresig(SIGINT);
6486 if ((jp == NULL || jp->nprocs == 0) && !fd0_redirected_p()) { 7002 ignoresig(SIGQUIT);
6487 close(0); 7003 if (jp->nprocs == 0) {
6488 if (open(devnull, O_RDONLY) != 0) 7004 close(0);
6489 error(nullerr, devnull); 7005 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
6490 } 7006 error("Can't open %s", _PATH_DEVNULL);
6491 }
6492 for (i = njobs, p = jobtab; --i >= 0; p++)
6493 if (p->used)
6494 freejob(p);
6495 if (wasroot && iflag) {
6496 setsignal(SIGINT);
6497 setsignal(SIGQUIT);
6498 setsignal(SIGTERM);
6499 } 7007 }
6500 return pid;
6501 } 7008 }
6502#ifdef CONFIG_ASH_JOB_CONTROL 7009 if (wasroot && iflag) {
6503 if (rootshell && mode != FORK_NOJOB && mflag) { 7010 setsignal(SIGINT);
6504 if (jp == NULL || jp->nprocs == 0) 7011 setsignal(SIGQUIT);
7012 setsignal(SIGTERM);
7013 }
7014 for (jp = curjob; jp; jp = jp->prev_job)
7015 freejob(jp);
7016 jobless = 0;
7017}
7018
7019static inline void
7020forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7021{
7022 TRACE(("In parent shell: child = %d\n", pid));
7023 if (!jp) {
7024 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7025 jobless++;
7026 return;
7027 }
7028#if JOBS
7029 if (mode != FORK_NOJOB && jp->jobctl) {
7030 int pgrp;
7031
7032 if (jp->nprocs == 0)
6505 pgrp = pid; 7033 pgrp = pid;
6506 else 7034 else
6507 pgrp = jp->ps[0].pid; 7035 pgrp = jp->ps[0].pid;
6508 setpgid(pid, pgrp); 7036 /* This can fail because we are doing it in the child also */
7037 (void)setpgid(pid, pgrp);
6509 } 7038 }
6510#endif 7039#endif
6511 if (mode == FORK_BG) 7040 if (mode == FORK_BG) {
6512 backgndpid = pid; /* set $! */ 7041 backgndpid = pid; /* set $! */
7042 set_curjob(jp, CUR_RUNNING);
7043 }
6513 if (jp) { 7044 if (jp) {
6514 struct procstat *ps = &jp->ps[jp->nprocs++]; 7045 struct procstat *ps = &jp->ps[jp->nprocs++];
6515
6516 ps->pid = pid; 7046 ps->pid = pid;
6517 ps->status = -1; 7047 ps->status = -1;
6518 ps->cmd = nullstr; 7048 ps->cmd = nullstr;
6519 if (iflag && rootshell && n) 7049#if JOBS
7050 if (jobctl && n)
6520 ps->cmd = commandtext(n); 7051 ps->cmd = commandtext(n);
7052#endif
6521 } 7053 }
6522 INTON;
6523 TRACE(("In parent shell: child = %d\n", pid));
6524 return pid;
6525} 7054}
6526 7055
7056static int
7057forkshell(struct job *jp, union node *n, int mode)
7058{
7059 int pid;
6527 7060
7061 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7062 pid = fork();
7063 if (pid < 0) {
7064 TRACE(("Fork failed, errno=%d", errno));
7065 if (jp)
7066 freejob(jp);
7067 error("Cannot fork");
7068 }
7069 if (pid == 0)
7070 forkchild(jp, n, mode);
7071 else
7072 forkparent(jp, n, mode, pid);
7073 return pid;
7074}
6528 7075
6529/* 7076/*
6530 * Wait for job to finish. 7077 * Wait for job to finish.
@@ -6543,65 +7090,41 @@ static int forkshell(struct job *jp, const union node *n, int mode)
6543 * exit on interrupt; unless these processes terminate themselves by 7090 * exit on interrupt; unless these processes terminate themselves by
6544 * sending a signal to themselves (instead of calling exit) they will 7091 * sending a signal to themselves (instead of calling exit) they will
6545 * confuse this approach. 7092 * confuse this approach.
7093 *
7094 * Called with interrupts off.
6546 */ 7095 */
6547 7096
6548static int waitforjob(struct job *jp) 7097int
7098waitforjob(struct job *jp)
6549{ 7099{
6550#ifdef CONFIG_ASH_JOB_CONTROL
6551 int mypgrp = getpgrp();
6552#endif
6553 int status;
6554 int st; 7100 int st;
6555 7101
6556 INTOFF; 7102 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
6557 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1)); 7103 while (jp->state == JOBRUNNING) {
6558 while (jp->state == 0) { 7104 dowait(DOWAIT_BLOCK, jp);
6559 dowait(1, jp);
6560 } 7105 }
6561#ifdef CONFIG_ASH_JOB_CONTROL 7106 st = getstatus(jp);
6562 if (jp->jobctl) { 7107#if JOBS
6563 if (tcsetpgrp(2, mypgrp) < 0)
6564 error("tcsetpgrp failed, errno=%d\n", errno);
6565 }
6566 if (jp->state == JOBSTOPPED)
6567 curjob = jp - jobtab + 1;
6568#endif
6569 status = jp->ps[jp->nprocs - 1].status;
6570 /* convert to 8 bits */
6571 if (WIFEXITED(status))
6572 st = WEXITSTATUS(status);
6573#ifdef CONFIG_ASH_JOB_CONTROL
6574 else if (WIFSTOPPED(status))
6575 st = WSTOPSIG(status) + 128;
6576#endif
6577 else
6578 st = WTERMSIG(status) + 128;
6579#ifdef CONFIG_ASH_JOB_CONTROL
6580 if (jp->jobctl) { 7108 if (jp->jobctl) {
7109 xtcsetpgrp(ttyfd, rootpid);
6581 /* 7110 /*
6582 * This is truly gross. 7111 * This is truly gross.
6583 * If we're doing job control, then we did a TIOCSPGRP which 7112 * If we're doing job control, then we did a TIOCSPGRP which
6584 * caused us (the shell) to no longer be in the controlling 7113 * caused us (the shell) to no longer be in the controlling
6585 * session -- so we wouldn't have seen any ^C/SIGINT. So, we 7114 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6586 * intuit from the subprocess exit status whether a SIGINT 7115 * intuit from the subprocess exit status whether a SIGINT
6587 * occured, and if so interrupt ourselves. Yuck. - mycroft 7116 * occurred, and if so interrupt ourselves. Yuck. - mycroft
6588 */ 7117 */
6589 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) 7118 if (jp->sigint)
6590 raise(SIGINT); 7119 raise(SIGINT);
6591 } 7120 }
6592 if (jp->state == JOBDONE) 7121 if (jp->state == JOBDONE)
6593#endif 7122#endif
6594 freejob(jp); 7123 freejob(jp);
6595 INTON;
6596 return st; 7124 return st;
6597} 7125}
6598 7126
6599 7127
6600
6601/*
6602 * Wait for a process to terminate.
6603 */
6604
6605/* 7128/*
6606 * Do a wait system call. If job control is compiled in, we accept 7129 * Do a wait system call. If job control is compiled in, we accept
6607 * stopped processes. If block is zero, we return a value of zero 7130 * stopped processes. If block is zero, we return a value of zero
@@ -6624,635 +7147,554 @@ static int waitforjob(struct job *jp)
6624 * then checking to see whether it was called. If there are any 7147 * then checking to see whether it was called. If there are any
6625 * children to be waited for, it will be. 7148 * children to be waited for, it will be.
6626 * 7149 *
7150 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7151 * waits at all. In this case, the user will not be informed when
7152 * a background process until the next time she runs a real program
7153 * (as opposed to running a builtin command or just typing return),
7154 * and the jobs command may give out of date information.
6627 */ 7155 */
6628 7156
6629static inline int waitproc(int block, int *status) 7157static inline int
7158waitproc(int block, int *status)
6630{ 7159{
6631 int flags; 7160 int flags = 0;
6632 7161
6633 flags = 0; 7162#if JOBS
6634#ifdef CONFIG_ASH_JOB_CONTROL
6635 if (jobctl) 7163 if (jobctl)
6636 flags |= WUNTRACED; 7164 flags |= WUNTRACED;
6637#endif 7165#endif
6638 if (block == 0) 7166 if (block == 0)
6639 flags |= WNOHANG; 7167 flags |= WNOHANG;
6640 return wait3(status, flags, (struct rusage *) NULL); 7168 return wait3(status, flags, (struct rusage *)NULL);
6641} 7169}
6642 7170
6643static int dowait(int block, struct job *job) 7171/*
7172 * Wait for a process to terminate.
7173 */
7174
7175static int
7176dowait(int block, struct job *job)
6644{ 7177{
6645 int pid; 7178 int pid;
6646 int status; 7179 int status;
6647 struct procstat *sp;
6648 struct job *jp; 7180 struct job *jp;
6649 struct job *thisjob; 7181 struct job *thisjob;
6650 int done; 7182 int state;
6651 int stopped;
6652 int core;
6653 int sig;
6654 7183
6655 TRACE(("dowait(%d) called\n", block)); 7184 TRACE(("dowait(%d) called\n", block));
6656 do { 7185 pid = waitproc(block, &status);
6657 pid = waitproc(block, &status); 7186 TRACE(("wait returns pid %d, status=%d\n", pid, status));
6658 TRACE(("wait returns %d, status=%d\n", pid, status));
6659 } while (!(block & 2) && pid == -1 && errno == EINTR);
6660 if (pid <= 0) 7187 if (pid <= 0)
6661 return pid; 7188 return pid;
6662 INTOFF; 7189 INTOFF;
6663 thisjob = NULL; 7190 thisjob = NULL;
6664 for (jp = jobtab; jp < jobtab + njobs; jp++) { 7191 for (jp = curjob; jp; jp = jp->prev_job) {
6665 if (jp->used) { 7192 struct procstat *sp;
6666 done = 1; 7193 struct procstat *spend;
6667 stopped = 1; 7194 if (jp->state == JOBDONE)
6668 for (sp = jp->ps; sp < jp->ps + jp->nprocs; sp++) { 7195 continue;
6669 if (sp->pid == -1) 7196 state = JOBDONE;
6670 continue; 7197 spend = jp->ps + jp->nprocs;
6671 if (sp->pid == pid) { 7198 sp = jp->ps;
6672 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", 7199 do {
6673 pid, sp->status, status)); 7200 if (sp->pid == pid) {
6674 sp->status = status; 7201 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
6675 thisjob = jp; 7202 sp->status = status;
6676 } 7203 thisjob = jp;
6677 if (sp->status == -1) 7204 }
6678 stopped = 0; 7205 if (sp->status == -1)
6679 else if (WIFSTOPPED(sp->status)) 7206 state = JOBRUNNING;
6680 done = 0; 7207#ifdef JOBS
7208 if (state == JOBRUNNING)
7209 continue;
7210 if (WIFSTOPPED(sp->status)) {
7211 jp->stopstatus = sp->status;
7212 state = JOBSTOPPED;
6681 } 7213 }
6682 if (stopped) { /* stopped or done */
6683 int state = done ? JOBDONE : JOBSTOPPED;
6684
6685 if (jp->state != state) {
6686 TRACE(("Job %d: changing state from %d to %d\n",
6687 jp - jobtab + 1, jp->state, state));
6688 jp->state = state;
6689#ifdef CONFIG_ASH_JOB_CONTROL
6690 if (done && curjob == jp - jobtab + 1)
6691 curjob = 0; /* no current job */
6692#endif 7214#endif
6693 } 7215 } while (++sp < spend);
7216 if (thisjob)
7217 goto gotjob;
7218 }
7219#ifdef JOBS
7220 if (!WIFSTOPPED(status))
7221#endif
7222
7223 jobless--;
7224 goto out;
7225
7226gotjob:
7227 if (state != JOBRUNNING) {
7228 thisjob->changed = 1;
7229
7230 if (thisjob->state != state) {
7231 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7232 thisjob->state = state;
7233#ifdef JOBS
7234 if (state == JOBSTOPPED) {
7235 set_curjob(thisjob, CUR_STOPPED);
6694 } 7236 }
7237#endif
6695 } 7238 }
6696 } 7239 }
7240
7241out:
6697 INTON; 7242 INTON;
6698 if (!rootshell || !iflag || (job && thisjob == job)) {
6699 core = WCOREDUMP(status);
6700#ifdef CONFIG_ASH_JOB_CONTROL
6701 if (WIFSTOPPED(status))
6702 sig = WSTOPSIG(status);
6703 else
6704#endif
6705 if (WIFEXITED(status))
6706 sig = 0;
6707 else
6708 sig = WTERMSIG(status);
6709 7243
6710 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) { 7244 if (thisjob && thisjob == job) {
6711 if (thisjob != job) 7245 char s[48 + 1];
6712 out2fmt("%d: ", pid); 7246 int len;
6713#ifdef CONFIG_ASH_JOB_CONTROL 7247
6714 if (sig == SIGTSTP && rootshell && iflag) 7248 len = sprint_status(s, status, 1);
6715 out2fmt("%%%ld ", (long) (job - jobtab + 1)); 7249 if (len) {
6716#endif 7250 s[len] = '\n';
6717 if (sig < NSIG && sys_siglist[sig]) 7251 s[len + 1] = 0;
6718 out2str(sys_siglist[sig]); 7252 out2str(s);
6719 else
6720 out2fmt("Signal %d", sig);
6721 if (core)
6722 out2str(" - core dumped");
6723 out2c('\n');
6724 } else {
6725 TRACE(("Not printing status: status=%d, sig=%d\n", status, sig));
6726 } 7253 }
6727 } else {
6728 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell,
6729 job));
6730 if (thisjob)
6731 thisjob->changed = 1;
6732 } 7254 }
6733 return pid; 7255 return pid;
6734} 7256}
6735 7257
6736 7258
6737 7259
6738
6739/* 7260/*
6740 * return 1 if there are stopped jobs, otherwise 0 7261 * return 1 if there are stopped jobs, otherwise 0
6741 */ 7262 */
6742static int stoppedjobs(void) 7263int
7264stoppedjobs(void)
6743{ 7265{
6744 int jobno;
6745 struct job *jp; 7266 struct job *jp;
7267 int retval;
6746 7268
7269 retval = 0;
6747 if (job_warning) 7270 if (job_warning)
6748 return (0); 7271 goto out;
6749 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { 7272 jp = curjob;
6750 if (jp->used == 0) 7273 if (jp && jp->state == JOBSTOPPED) {
6751 continue; 7274 out2str("You have stopped jobs.\n");
6752 if (jp->state == JOBSTOPPED) { 7275 job_warning = 2;
6753 out2str("You have stopped jobs.\n"); 7276 retval++;
6754 job_warning = 2;
6755 return (1);
6756 }
6757 } 7277 }
6758 7278
6759 return (0); 7279out:
7280 return retval;
6760} 7281}
6761 7282
6762/* 7283/*
6763 * Return a string identifying a command (to be printed by the 7284 * Return a string identifying a command (to be printed by the
6764 * jobs command. 7285 * jobs command).
6765 */ 7286 */
6766 7287
7288#if JOBS
6767static char *cmdnextc; 7289static char *cmdnextc;
6768static int cmdnleft;
6769 7290
6770#define MAXCMDTEXT 200 7291static char *
6771 7292commandtext(union node *n)
6772static void cmdputs(const char *s)
6773{ 7293{
6774 const char *p; 7294 char *name;
6775 char *q;
6776 char c;
6777 int subtype = 0;
6778 7295
6779 if (cmdnleft <= 0) 7296 STARTSTACKSTR(cmdnextc);
6780 return; 7297 cmdtxt(n);
6781 p = s; 7298 name = stackblock();
6782 q = cmdnextc; 7299 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
6783 while ((c = *p++) != '\0') { 7300 name, cmdnextc, cmdnextc));
6784 if (c == CTLESC) 7301 return savestr(name);
6785 *q++ = *p++;
6786 else if (c == CTLVAR) {
6787 *q++ = '$';
6788 if (--cmdnleft > 0)
6789 *q++ = '{';
6790 subtype = *p++;
6791 } else if (c == '=' && subtype != 0) {
6792 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6793 subtype = 0;
6794 } else if (c == CTLENDVAR) {
6795 *q++ = '}';
6796 } else if (c == CTLBACKQ || c == CTLBACKQ + CTLQUOTE)
6797 cmdnleft++; /* ignore it */
6798 else
6799 *q++ = c;
6800 if (--cmdnleft <= 0) {
6801 *q++ = '.';
6802 *q++ = '.';
6803 *q++ = '.';
6804 break;
6805 }
6806 }
6807 cmdnextc = q;
6808} 7302}
6809 7303
6810#define CMDTXT_TABLE 7304static void
6811#ifdef CMDTXT_TABLE 7305cmdtxt(union node *n)
6812/*
6813 * To collect a lot of redundant code in cmdtxt() case statements, we
6814 * implement a mini language here. Each type of node struct has an
6815 * associated instruction sequence that operates on its members via
6816 * their offsets. The instruction are pack in unsigned chars with
6817 * format IIDDDDDE where the bits are
6818 * I : part of the instruction opcode, which are
6819 * 00 : member is a pointer to another node -- process it recursively
6820 * 40 : member is a pointer to a char string -- output it
6821 * 80 : output the string whose index is stored in the data field
6822 * CC : flag signaling that this case needs external processing
6823 * D : data - either the (shifted) index of a fixed string to output or
6824 * the actual offset of the member to operate on in the struct
6825 * (since we assume bit 0 is set, the offset is not shifted)
6826 * E : flag signaling end of instruction sequence
6827 *
6828 * WARNING: In order to handle larger offsets for 64bit archs, this code
6829 * assumes that no offset can be an odd number and stores the
6830 * end-of-instructions flag in bit 0.
6831 */
6832
6833#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
6834#define CMDTXT_CHARPTR 0x40
6835#define CMDTXT_STRING 0x80
6836#define CMDTXT_SPECIAL 0xC0
6837#define CMDTXT_OFFSETMASK 0x3E
6838
6839static const char *const cmdtxt_strings[] = {
6840 /* 0 1 2 3 4 5 6 7 */
6841 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
6842 /* 8 9 10 11 12 13 */
6843 "while ", "; do ", "; done", "until ", "for ", " in ...",
6844 /* 14 15 16 17 */
6845 "case ", "???", "() ...", "<<..."
6846};
6847
6848static const char *const redir_strings[] = {
6849 ">", "<", "<>", ">>", ">|", ">&", "<&"
6850};
6851
6852static const unsigned char cmdtxt_ops[] = {
6853#define CMDTXT_NSEMI 0
6854 offsetof(union node, nbinary.ch1),
6855 0 | CMDTXT_STRING,
6856 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
6857#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
6858#define CMDTXT_NPIPE (CMDTXT_NCMD)
6859#define CMDTXT_NCASE (CMDTXT_NCMD)
6860#define CMDTXT_NTO (CMDTXT_NCMD)
6861#define CMDTXT_NFROM (CMDTXT_NCMD)
6862#define CMDTXT_NFROMTO (CMDTXT_NCMD)
6863#define CMDTXT_NAPPEND (CMDTXT_NCMD)
6864#define CMDTXT_NTOOV (CMDTXT_NCMD)
6865#define CMDTXT_NTOFD (CMDTXT_NCMD)
6866#define CMDTXT_NFROMFD (CMDTXT_NCMD)
6867 CMDTXT_SPECIAL,
6868#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
6869#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
6870 offsetof(union node, nredir.n) | CMDTXT_NOMORE,
6871#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
6872 (1 * 2) | CMDTXT_STRING,
6873 offsetof(union node, nredir.n),
6874 (2 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6875#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
6876 offsetof(union node, nbinary.ch1),
6877 (3 * 2) | CMDTXT_STRING,
6878 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
6879#define CMDTXT_NOR (CMDTXT_NAND + 3)
6880 offsetof(union node, nbinary.ch1),
6881 (4 * 2) | CMDTXT_STRING,
6882 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
6883#define CMDTXT_NIF (CMDTXT_NOR + 3)
6884 (5 * 2) | CMDTXT_STRING,
6885 offsetof(union node, nif.test),
6886 (6 * 2) | CMDTXT_STRING,
6887 offsetof(union node, nif.ifpart),
6888 (7 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6889#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
6890 (8 * 2) | CMDTXT_STRING,
6891 offsetof(union node, nbinary.ch1),
6892 (9 * 2) | CMDTXT_STRING,
6893 offsetof(union node, nbinary.ch2),
6894 (10 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6895#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
6896 (11 * 2) | CMDTXT_STRING,
6897 offsetof(union node, nbinary.ch1),
6898 (9 * 2) | CMDTXT_STRING,
6899 offsetof(union node, nbinary.ch2),
6900 (10 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6901#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
6902 (12 * 2) | CMDTXT_STRING,
6903 offsetof(union node, nfor.var) | CMDTXT_CHARPTR,
6904 (13 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6905#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
6906#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
6907 (15 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6908#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
6909 offsetof(union node, narg.text) | CMDTXT_CHARPTR,
6910 (16 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6911#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
6912 offsetof(union node, narg.text) | CMDTXT_CHARPTR | CMDTXT_NOMORE,
6913#define CMDTXT_NHERE (CMDTXT_NARG + 1)
6914#define CMDTXT_NXHERE (CMDTXT_NHERE)
6915 (17 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6916};
6917
6918#if CMDTXT_NXHERE != 36
6919#error CMDTXT_NXHERE
6920#endif
6921
6922static const unsigned char cmdtxt_ops_index[26] = {
6923 CMDTXT_NSEMI,
6924 CMDTXT_NCMD,
6925 CMDTXT_NPIPE,
6926 CMDTXT_NREDIR,
6927 CMDTXT_NBACKGND,
6928 CMDTXT_NSUBSHELL,
6929 CMDTXT_NAND,
6930 CMDTXT_NOR,
6931 CMDTXT_NIF,
6932 CMDTXT_NWHILE,
6933 CMDTXT_NUNTIL,
6934 CMDTXT_NFOR,
6935 CMDTXT_NCASE,
6936 CMDTXT_NCLIST,
6937 CMDTXT_NDEFUN,
6938 CMDTXT_NARG,
6939 CMDTXT_NTO,
6940 CMDTXT_NFROM,
6941 CMDTXT_NFROMTO,
6942 CMDTXT_NAPPEND,
6943 CMDTXT_NTOOV,
6944 CMDTXT_NTOFD,
6945 CMDTXT_NFROMFD,
6946 CMDTXT_NHERE,
6947 CMDTXT_NXHERE,
6948 CMDTXT_NNOT,
6949};
6950
6951static void cmdtxt(const union node *n)
6952{
6953 const char *p;
6954
6955 if (n == NULL)
6956 return;
6957
6958 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
6959 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
6960 do {
6961 if (*p & CMDTXT_STRING) { /* output fixed string */
6962 cmdputs(cmdtxt_strings
6963 [((int) (*p & CMDTXT_OFFSETMASK) >> 1)]);
6964 } else {
6965 const char *pf = ((const char *) n)
6966 + ((int) (*p & CMDTXT_OFFSETMASK));
6967
6968 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
6969 cmdputs(*((const char **) pf));
6970 } else { /* output field */
6971 cmdtxt(*((const union node **) pf));
6972 }
6973 }
6974 } while (!(*p++ & CMDTXT_NOMORE));
6975 } else if (n->type == NCMD) {
6976 union node *np;
6977
6978 for (np = n->ncmd.args; np; np = np->narg.next) {
6979 cmdtxt(np);
6980 if (np->narg.next)
6981 cmdputs(spcstr);
6982 }
6983 for (np = n->ncmd.redirect; np; np = np->nfile.next) {
6984 cmdputs(spcstr);
6985 cmdtxt(np);
6986 }
6987 } else if (n->type == NPIPE) {
6988 struct nodelist *lp;
6989
6990 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
6991 cmdtxt(lp->n);
6992 if (lp->next)
6993 cmdputs(" | ");
6994 }
6995 } else if (n->type == NCASE) {
6996 cmdputs(cmdtxt_strings[14]);
6997 cmdputs(n->ncase.expr->narg.text);
6998 cmdputs(cmdtxt_strings[13]);
6999 } else {
7000#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7001#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7002#endif
7003 char s[2];
7004
7005#ifdef DEBUG
7006 assert((n->type >= NTO) && (n->type <= NFROMFD));
7007#endif
7008
7009 p = redir_strings[n->type - NTO];
7010 if (n->nfile.fd != ('>' == *p)) {
7011 s[0] = n->nfile.fd + '0';
7012 s[1] = '\0';
7013 cmdputs(s);
7014 }
7015 cmdputs(p);
7016 if (n->type >= NTOFD) {
7017 s[0] = n->ndup.dupfd + '0';
7018 s[1] = '\0';
7019 cmdputs(s);
7020 } else {
7021 cmdtxt(n->nfile.fname);
7022 }
7023 }
7024}
7025#else /* CMDTXT_TABLE */
7026static void cmdtxt(const union node *n)
7027{ 7306{
7028 union node *np; 7307 union node *np;
7029 struct nodelist *lp; 7308 struct nodelist *lp;
7030 const char *p; 7309 const char *p;
7031 int i;
7032 char s[2]; 7310 char s[2];
7033 7311
7034 if (n == NULL)
7035 return;
7036 switch (n->type) { 7312 switch (n->type) {
7037 case NSEMI: 7313 default:
7038 cmdtxt(n->nbinary.ch1); 7314#if DEBUG
7039 cmdputs("; "); 7315 abort();
7040 cmdtxt(n->nbinary.ch2); 7316#endif
7041 break;
7042 case NAND:
7043 cmdtxt(n->nbinary.ch1);
7044 cmdputs(" && ");
7045 cmdtxt(n->nbinary.ch2);
7046 break;
7047 case NOR:
7048 cmdtxt(n->nbinary.ch1);
7049 cmdputs(" || ");
7050 cmdtxt(n->nbinary.ch2);
7051 break;
7052 case NPIPE: 7317 case NPIPE:
7053 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 7318 lp = n->npipe.cmdlist;
7319 for (;;) {
7054 cmdtxt(lp->n); 7320 cmdtxt(lp->n);
7055 if (lp->next) 7321 lp = lp->next;
7056 cmdputs(" | "); 7322 if (!lp)
7323 break;
7324 cmdputs(" | ");
7057 } 7325 }
7058 break; 7326 break;
7059 case NSUBSHELL: 7327 case NSEMI:
7060 cmdputs("("); 7328 p = "; ";
7061 cmdtxt(n->nredir.n); 7329 goto binop;
7062 cmdputs(")"); 7330 case NAND:
7063 break; 7331 p = " && ";
7332 goto binop;
7333 case NOR:
7334 p = " || ";
7335binop:
7336 cmdtxt(n->nbinary.ch1);
7337 cmdputs(p);
7338 n = n->nbinary.ch2;
7339 goto donode;
7064 case NREDIR: 7340 case NREDIR:
7065 case NBACKGND: 7341 case NBACKGND:
7066 cmdtxt(n->nredir.n); 7342 n = n->nredir.n;
7343 goto donode;
7344 case NNOT:
7345 cmdputs("!");
7346 n = n->nnot.com;
7347donode:
7348 cmdtxt(n);
7067 break; 7349 break;
7068 case NIF: 7350 case NIF:
7069 cmdputs("if "); 7351 cmdputs("if ");
7070 cmdtxt(n->nif.test); 7352 cmdtxt(n->nif.test);
7071 cmdputs("; then "); 7353 cmdputs("; then ");
7072 cmdtxt(n->nif.ifpart); 7354 n = n->nif.ifpart;
7073 cmdputs("..."); 7355 if (n->nif.elsepart) {
7074 break; 7356 cmdtxt(n);
7357 cmdputs("; else ");
7358 n = n->nif.elsepart;
7359 }
7360 p = "; fi";
7361 goto dotail;
7362 case NSUBSHELL:
7363 cmdputs("(");
7364 n = n->nredir.n;
7365 p = ")";
7366 goto dotail;
7075 case NWHILE: 7367 case NWHILE:
7076 cmdputs("while "); 7368 p = "while ";
7077 goto until; 7369 goto until;
7078 case NUNTIL: 7370 case NUNTIL:
7079 cmdputs("until "); 7371 p = "until ";
7080 until: 7372until:
7373 cmdputs(p);
7081 cmdtxt(n->nbinary.ch1); 7374 cmdtxt(n->nbinary.ch1);
7375 n = n->nbinary.ch2;
7376 p = "; done";
7377dodo:
7082 cmdputs("; do "); 7378 cmdputs("; do ");
7083 cmdtxt(n->nbinary.ch2); 7379dotail:
7084 cmdputs("; done"); 7380 cmdtxt(n);
7085 break; 7381 goto dotail2;
7086 case NFOR: 7382 case NFOR:
7087 cmdputs("for "); 7383 cmdputs("for ");
7088 cmdputs(n->nfor.var); 7384 cmdputs(n->nfor.var);
7089 cmdputs(" in ..."); 7385 cmdputs(" in ");
7090 break; 7386 cmdlist(n->nfor.args, 1);
7091 case NCASE: 7387 n = n->nfor.body;
7092 cmdputs("case "); 7388 p = "; done";
7093 cmdputs(n->ncase.expr->narg.text); 7389 goto dodo;
7094 cmdputs(" in ...");
7095 break;
7096 case NDEFUN: 7390 case NDEFUN:
7097 cmdputs(n->narg.text); 7391 cmdputs(n->narg.text);
7098 cmdputs("() ..."); 7392 p = "() { ... }";
7099 break; 7393 goto dotail2;
7100 case NCMD: 7394 case NCMD:
7101 for (np = n->ncmd.args; np; np = np->narg.next) { 7395 cmdlist(n->ncmd.args, 1);
7102 cmdtxt(np); 7396 cmdlist(n->ncmd.redirect, 0);
7103 if (np->narg.next)
7104 cmdputs(spcstr);
7105 }
7106 for (np = n->ncmd.redirect; np; np = np->nfile.next) {
7107 cmdputs(spcstr);
7108 cmdtxt(np);
7109 }
7110 break; 7397 break;
7111 case NARG: 7398 case NARG:
7112 cmdputs(n->narg.text); 7399 p = n->narg.text;
7400dotail2:
7401 cmdputs(p);
7113 break; 7402 break;
7403 case NHERE:
7404 case NXHERE:
7405 p = "<<...";
7406 goto dotail2;
7407 case NCASE:
7408 cmdputs("case ");
7409 cmdputs(n->ncase.expr->narg.text);
7410 cmdputs(" in ");
7411 for (np = n->ncase.cases; np; np = np->nclist.next) {
7412 cmdtxt(np->nclist.pattern);
7413 cmdputs(") ");
7414 cmdtxt(np->nclist.body);
7415 cmdputs(";; ");
7416 }
7417 p = "esac";
7418 goto dotail2;
7114 case NTO: 7419 case NTO:
7115 p = ">"; 7420 p = ">";
7116 i = 1; 7421 goto redir;
7422 case NCLOBBER:
7423 p = ">|";
7117 goto redir; 7424 goto redir;
7118 case NAPPEND: 7425 case NAPPEND:
7119 p = ">>"; 7426 p = ">>";
7120 i = 1;
7121 goto redir; 7427 goto redir;
7122 case NTOFD: 7428 case NTOFD:
7123 p = ">&"; 7429 p = ">&";
7124 i = 1;
7125 goto redir;
7126 case NTOOV:
7127 p = ">|";
7128 i = 1;
7129 goto redir; 7430 goto redir;
7130 case NFROM: 7431 case NFROM:
7131 p = "<"; 7432 p = "<";
7132 i = 0;
7133 goto redir; 7433 goto redir;
7134 case NFROMFD: 7434 case NFROMFD:
7135 p = "<&"; 7435 p = "<&";
7136 i = 0;
7137 goto redir; 7436 goto redir;
7138 case NFROMTO: 7437 case NFROMTO:
7139 p = "<>"; 7438 p = "<>";
7140 i = 0; 7439redir:
7141 goto redir; 7440 s[0] = n->nfile.fd + '0';
7142 redir: 7441 s[1] = '\0';
7143 if (n->nfile.fd != i) { 7442 cmdputs(s);
7144 s[0] = n->nfile.fd + '0';
7145 s[1] = '\0';
7146 cmdputs(s);
7147 }
7148 cmdputs(p); 7443 cmdputs(p);
7149 if (n->type == NTOFD || n->type == NFROMFD) { 7444 if (n->type == NTOFD || n->type == NFROMFD) {
7150 s[0] = n->ndup.dupfd + '0'; 7445 s[0] = n->ndup.dupfd + '0';
7151 s[1] = '\0'; 7446 p = s;
7152 cmdputs(s); 7447 goto dotail2;
7153 } else { 7448 } else {
7154 cmdtxt(n->nfile.fname); 7449 n = n->nfile.fname;
7450 goto donode;
7155 } 7451 }
7156 break;
7157 case NHERE:
7158 case NXHERE:
7159 cmdputs("<<...");
7160 break;
7161 default:
7162 cmdputs("???");
7163 break;
7164 } 7452 }
7165} 7453}
7166#endif /* CMDTXT_TABLE */
7167 7454
7168static char *commandtext(const union node *n) 7455static void
7456cmdlist(union node *np, int sep)
7169{ 7457{
7170 char *name; 7458 for (; np; np = np->narg.next) {
7459 if (!sep)
7460 cmdputs(spcstr);
7461 cmdtxt(np);
7462 if (sep && np->narg.next)
7463 cmdputs(spcstr);
7464 }
7465}
7171 7466
7172 cmdnextc = name = xmalloc(MAXCMDTEXT); 7467
7173 cmdnleft = MAXCMDTEXT - 4; 7468static void
7174 cmdtxt(n); 7469cmdputs(const char *s)
7175 *cmdnextc = '\0'; 7470{
7176 return name; 7471 const char *p, *str;
7472 char c, cc[2] = " ";
7473 char *nextc;
7474 int subtype = 0;
7475 int quoted = 0;
7476 static const char *const vstype[16] = {
7477 nullstr, "}", "-", "+", "?", "=",
7478 "#", "##", "%", "%%"
7479 };
7480
7481 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7482 p = s;
7483 while ((c = *p++) != 0) {
7484 str = 0;
7485 switch (c) {
7486 case CTLESC:
7487 c = *p++;
7488 break;
7489 case CTLVAR:
7490 subtype = *p++;
7491 if ((subtype & VSTYPE) == VSLENGTH)
7492 str = "${#";
7493 else
7494 str = "${";
7495 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7496 quoted ^= 1;
7497 c = '"';
7498 } else
7499 goto dostr;
7500 break;
7501 case CTLENDVAR:
7502 quoted >>= 1;
7503 subtype = 0;
7504 if (quoted & 1) {
7505 str = "\"}";
7506 goto dostr;
7507 }
7508 c = '}';
7509 break;
7510 case CTLBACKQ:
7511 str = "$(...)";
7512 goto dostr;
7513 case CTLBACKQ+CTLQUOTE:
7514 str = "\"$(...)\"";
7515 goto dostr;
7516#ifdef CONFIG_ASH_MATH_SUPPORT
7517 case CTLARI:
7518 str = "$((";
7519 goto dostr;
7520 case CTLENDARI:
7521 str = "))";
7522 goto dostr;
7523#endif
7524 case CTLQUOTEMARK:
7525 quoted ^= 1;
7526 c = '"';
7527 break;
7528 case '=':
7529 if (subtype == 0)
7530 break;
7531 str = vstype[subtype & VSTYPE];
7532 if (subtype & VSNUL)
7533 c = ':';
7534 else
7535 c = *str++;
7536 if (c != '}')
7537 quoted <<= 1;
7538 break;
7539 case '\'':
7540 case '\\':
7541 case '"':
7542 case '$':
7543 /* These can only happen inside quotes */
7544 cc[0] = c;
7545 str = cc;
7546 c = '\\';
7547 break;
7548 default:
7549 break;
7550 }
7551 USTPUTC(c, nextc);
7552 if (!str)
7553 continue;
7554dostr:
7555 while ((c = *str++)) {
7556 USTPUTC(c, nextc);
7557 }
7558 }
7559 if (quoted & 1) {
7560 USTPUTC('"', nextc);
7561 }
7562 *nextc = 0;
7563 cmdnextc = nextc;
7177} 7564}
7178 7565
7179 7566
7567static void
7568showpipe(struct job *jp, FILE *out)
7569{
7570 struct procstat *sp;
7571 struct procstat *spend;
7572
7573 spend = jp->ps + jp->nprocs;
7574 for (sp = jp->ps + 1; sp < spend; sp++)
7575 fprintf(out, " | %s", sp->cmd);
7576 outcslow('\n', out);
7577 flushall();
7578}
7579
7580static void
7581xtcsetpgrp(int fd, pid_t pgrp)
7582{
7583 if (tcsetpgrp(fd, pgrp))
7584 error("Cannot set tty process group (%m)");
7585}
7586#endif /* JOBS */
7587
7588static int
7589getstatus(struct job *job) {
7590 int status;
7591 int retval;
7592
7593 status = job->ps[job->nprocs - 1].status;
7594 retval = WEXITSTATUS(status);
7595 if (!WIFEXITED(status)) {
7596#if JOBS
7597 retval = WSTOPSIG(status);
7598 if (!WIFSTOPPED(status))
7599#endif
7600 {
7601 /* XXX: limits number of signals */
7602 retval = WTERMSIG(status);
7603#if JOBS
7604 if (retval == SIGINT)
7605 job->sigint = 1;
7606#endif
7607 }
7608 retval += 128;
7609 }
7610 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7611 jobno(job), job->nprocs, status, retval));
7612 return retval;
7613}
7614
7180#ifdef CONFIG_ASH_MAIL 7615#ifdef CONFIG_ASH_MAIL
7616/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7181 7617
7182/* 7618/*
7183 * Routines to check for mail. 7619 * Routines to check for mail. (Perhaps make part of main.c?)
7184 */ 7620 */
7185 7621
7186
7187#define MAXMBOXES 10 7622#define MAXMBOXES 10
7188 7623
7189 7624/* times of mailboxes */
7190static int nmboxes; /* number of mailboxes */ 7625static time_t mailtime[MAXMBOXES];
7191static time_t mailtime[MAXMBOXES]; /* times of mailboxes */ 7626/* Set if MAIL or MAILPATH is changed. */
7627static int mail_var_path_changed;
7192 7628
7193 7629
7194 7630
7195/* 7631/*
7196 * Print appropriate message(s) if mail has arrived. If the argument is 7632 * Print appropriate message(s) if mail has arrived.
7197 * nozero, then the value of MAIL has changed, so we just update the 7633 * If mail_var_path_changed is set,
7198 * values. 7634 * then the value of MAIL has mail_var_path_changed,
7635 * so we just update the values.
7199 */ 7636 */
7200 7637
7201static void chkmail(int silent) 7638static void
7639chkmail(void)
7202{ 7640{
7203 int i;
7204 const char *mpath; 7641 const char *mpath;
7205 char *p; 7642 char *p;
7206 char *q; 7643 char *q;
7644 time_t *mtp;
7207 struct stackmark smark; 7645 struct stackmark smark;
7208 struct stat statb; 7646 struct stat statb;
7209 7647
7210 if (silent)
7211 nmboxes = 10;
7212 if (nmboxes == 0)
7213 return;
7214 setstackmark(&smark); 7648 setstackmark(&smark);
7215 mpath = mpathset()? mpathval() : mailval(); 7649 mpath = mpathset() ? mpathval() : mailval();
7216 for (i = 0; i < nmboxes; i++) { 7650 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7217 p = padvance(&mpath, nullstr); 7651 p = padvance(&mpath, nullstr);
7218 if (p == NULL) 7652 if (p == NULL)
7219 break; 7653 break;
7220 if (*p == '\0') 7654 if (*p == '\0')
7221 continue; 7655 continue;
7222 for (q = p; *q; q++); 7656 for (q = p ; *q ; q++);
7223#ifdef DEBUG 7657#ifdef DEBUG
7224 if (q[-1] != '/') 7658 if (q[-1] != '/')
7225 abort(); 7659 abort();
7226#endif 7660#endif
7227 q[-1] = '\0'; /* delete trailing '/' */ 7661 q[-1] = '\0'; /* delete trailing '/' */
7228 if (stat(p, &statb) < 0) 7662 if (stat(p, &statb) < 0) {
7229 statb.st_size = 0; 7663 *mtp = 0;
7230 if (statb.st_size > mailtime[i] && !silent) { 7664 continue;
7231 out2fmt(snlfmt, pathopt ? pathopt : "you have mail"); 7665 }
7666 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7667 fprintf(
7668 stderr, snlfmt,
7669 pathopt ? pathopt : "you have mail"
7670 );
7232 } 7671 }
7233 mailtime[i] = statb.st_size; 7672 *mtp = statb.st_mtime;
7234 } 7673 }
7235 nmboxes = i; 7674 mail_var_path_changed = 0;
7236 popstackmark(&smark); 7675 popstackmark(&smark);
7237} 7676}
7238 7677
7239#endif /* CONFIG_ASH_MAIL */
7240 7678
7241#define PROFILE 0 7679static void
7680changemail(const char *val)
7681{
7682 mail_var_path_changed++;
7683}
7684
7685#endif /* CONFIG_ASH_MAIL */
7686
7687/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7688
7242 7689
7243#if PROFILE 7690#if PROFILE
7244static short profile_buf[16384]; 7691static short profile_buf[16384];
7245extern int etext(); 7692extern int etext();
7246#endif 7693#endif
7247 7694
7248static int isloginsh = 0; 7695static int isloginsh;
7249 7696
7250static void read_profile(const char *); 7697static void read_profile(const char *);
7251static void cmdloop(int);
7252static void options(int);
7253static void setoption(int, int);
7254static void procargs(int, char **);
7255
7256 7698
7257/* 7699/*
7258 * Main routine. We initialize things, parse the arguments, execute 7700 * Main routine. We initialize things, parse the arguments, execute
@@ -7262,56 +7704,52 @@ static void procargs(int, char **);
7262 * is used to figure out how far we had gotten. 7704 * is used to figure out how far we had gotten.
7263 */ 7705 */
7264 7706
7265int ash_main(int argc, char **argv) 7707int
7708ash_main(int argc, char **argv)
7266{ 7709{
7710 char *shinit;
7711 volatile int state;
7267 struct jmploc jmploc; 7712 struct jmploc jmploc;
7268 struct stackmark smark; 7713 struct stackmark smark;
7269 volatile int state;
7270 const char *shinit;
7271 7714
7272 BLTINCMD = find_builtin("builtin"); 7715#ifdef __GLIBC__
7273 EXECCMD = find_builtin("exec"); 7716 dash_errno = __errno_location();
7274 EVALCMD = find_builtin("eval");
7275
7276#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
7277 unsetenv("PS1");
7278 unsetenv("PS2");
7279#endif 7717#endif
7280 7718
7281#if PROFILE 7719#if PROFILE
7282 monitor(4, etext, profile_buf, sizeof profile_buf, 50); 7720 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7283#endif 7721#endif
7284#if defined(linux) || defined(__GNU__)
7285 signal(SIGCHLD, SIG_DFL);
7286#endif
7287 state = 0; 7722 state = 0;
7288 if (setjmp(jmploc.loc)) { 7723 if (setjmp(jmploc.loc)) {
7289 INTOFF; 7724 int status;
7290 /* 7725 int e;
7291 * When a shell procedure is executed, we raise the 7726
7292 * exception EXSHELLPROC to clean up before executing
7293 * the shell procedure.
7294 */
7295 if (exception == EXSHELLPROC) {
7296 rootpid = getpid();
7297 rootshell = 1;
7298 minusc = NULL;
7299 state = 3;
7300 } else {
7301 if (exception == EXEXEC) {
7302 exitstatus = exerrno;
7303 } else if (exception == EXERROR) {
7304 exitstatus = 2;
7305 }
7306 if (state == 0 || iflag == 0 || !rootshell)
7307 exitshell(exitstatus);
7308 }
7309 reset(); 7727 reset();
7310 if (exception == EXINT) { 7728
7311 out2c('\n'); 7729 e = exception;
7730 switch (exception) {
7731 case EXEXEC:
7732 status = exerrno;
7733 break;
7734
7735 case EXERROR:
7736 status = 2;
7737 break;
7738
7739 default:
7740 status = exitstatus;
7741 break;
7742 }
7743 exitstatus = status;
7744
7745 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7746 exitshell();
7747
7748 if (e == EXINT ) {
7749 outcslow('\n', stderr);
7312 } 7750 }
7313 popstackmark(&smark); 7751 popstackmark(&smark);
7314 FORCEINTON; /* enable interrupts */ 7752 FORCEINTON; /* enable interrupts */
7315 if (state == 1) 7753 if (state == 1)
7316 goto state1; 7754 goto state1;
7317 else if (state == 2) 7755 else if (state == 2)
@@ -7324,8 +7762,7 @@ int ash_main(int argc, char **argv)
7324 handler = &jmploc; 7762 handler = &jmploc;
7325#ifdef DEBUG 7763#ifdef DEBUG
7326 opentrace(); 7764 opentrace();
7327 trputs("Shell args: "); 7765 trputs("Shell args: "); trargs(argv);
7328 trargs(argv);
7329#endif 7766#endif
7330 rootpid = getpid(); 7767 rootpid = getpid();
7331 rootshell = 1; 7768 rootshell = 1;
@@ -7351,45 +7788,29 @@ int ash_main(int argc, char **argv)
7351 if (isloginsh) { 7788 if (isloginsh) {
7352 state = 1; 7789 state = 1;
7353 read_profile("/etc/profile"); 7790 read_profile("/etc/profile");
7354 state1: 7791state1:
7355 state = 2; 7792 state = 2;
7356 read_profile(".profile"); 7793 read_profile(".profile");
7357 } 7794 }
7358 state2: 7795state2:
7359 state = 3; 7796 state = 3;
7797 if (
7360#ifndef linux 7798#ifndef linux
7361 if (getuid() == geteuid() && getgid() == getegid()) { 7799 getuid() == geteuid() && getgid() == getegid() &&
7362#endif 7800#endif
7801 iflag
7802 ) {
7363 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 7803 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7364 state = 3;
7365 read_profile(shinit); 7804 read_profile(shinit);
7366 } 7805 }
7367#ifndef linux
7368 } 7806 }
7369#endif 7807state3:
7370 state3:
7371 state = 4; 7808 state = 4;
7372 if (sflag == 0 || minusc) {
7373 static const char sigs[] = {
7374 SIGINT, SIGQUIT, SIGHUP,
7375#ifdef SIGTSTP
7376 SIGTSTP,
7377#endif
7378 SIGPIPE
7379 };
7380
7381#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])))
7382 int i;
7383
7384 for (i = 0; i < SIGSSIZE; i++)
7385 setsignal(sigs[i]);
7386 }
7387
7388 if (minusc) 7809 if (minusc)
7389 evalstring(minusc, 0); 7810 evalstring(minusc, 0);
7390 7811
7391 if (sflag || minusc == NULL) { 7812 if (sflag || minusc == NULL) {
7392 state4: /* XXX ??? - why isn't this before the "if" statement */ 7813state4: /* XXX ??? - why isn't this before the "if" statement */
7393#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 7814#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7394 if ( iflag ) { 7815 if ( iflag ) {
7395 const char *hp = lookupvar("HISTFILE"); 7816 const char *hp = lookupvar("HISTFILE");
@@ -7403,7 +7824,13 @@ int ash_main(int argc, char **argv)
7403#if PROFILE 7824#if PROFILE
7404 monitor(0); 7825 monitor(0);
7405#endif 7826#endif
7406 exitshell(exitstatus); 7827#if GPROF
7828 {
7829 extern void _mcleanup(void);
7830 _mcleanup();
7831 }
7832#endif
7833 exitshell();
7407 /* NOTREACHED */ 7834 /* NOTREACHED */
7408} 7835}
7409 7836
@@ -7413,7 +7840,8 @@ int ash_main(int argc, char **argv)
7413 * loop; it turns on prompting if the shell is interactive. 7840 * loop; it turns on prompting if the shell is interactive.
7414 */ 7841 */
7415 7842
7416static void cmdloop(int top) 7843static void
7844cmdloop(int top)
7417{ 7845{
7418 union node *n; 7846 union node *n;
7419 struct stackmark smark; 7847 struct stackmark smark;
@@ -7425,14 +7853,16 @@ static void cmdloop(int top)
7425 for (;;) { 7853 for (;;) {
7426 if (pendingsigs) 7854 if (pendingsigs)
7427 dotrap(); 7855 dotrap();
7856#if JOBS
7857 if (jobctl)
7858 showjobs(stderr, SHOW_CHANGED);
7859#endif
7428 inter = 0; 7860 inter = 0;
7429 if (iflag && top) { 7861 if (iflag && top) {
7430 inter++; 7862 inter++;
7431 showjobs(1);
7432#ifdef CONFIG_ASH_MAIL 7863#ifdef CONFIG_ASH_MAIL
7433 chkmail(0); 7864 chkmail();
7434#endif 7865#endif
7435 flushall();
7436 } 7866 }
7437 n = parsecmd(inter); 7867 n = parsecmd(inter);
7438 /* showtree(n); DEBUG */ 7868 /* showtree(n); DEBUG */
@@ -7466,11 +7896,12 @@ static void cmdloop(int top)
7466 * Read /etc/profile or .profile. Return on error. 7896 * Read /etc/profile or .profile. Return on error.
7467 */ 7897 */
7468 7898
7469static void read_profile(const char *name) 7899static void
7900read_profile(const char *name)
7470{ 7901{
7471 int fd; 7902 int fd;
7472 int xflag_save; 7903 int xflag_set = 0;
7473 int vflag_save; 7904 int vflag_set = 0;
7474 7905
7475 INTOFF; 7906 INTOFF;
7476 if ((fd = open(name, O_RDONLY)) >= 0) 7907 if ((fd = open(name, O_RDONLY)) >= 0)
@@ -7479,15 +7910,19 @@ static void read_profile(const char *name)
7479 if (fd < 0) 7910 if (fd < 0)
7480 return; 7911 return;
7481 /* -q turns off -x and -v just when executing init files */ 7912 /* -q turns off -x and -v just when executing init files */
7482 /* Note: Might do a little redundant work, but reduces code size. */ 7913 if (qflag) {
7483 xflag_save = xflag; 7914 if (xflag)
7484 vflag_save = vflag; 7915 xflag = 0, xflag_set = 1;
7485 if (qflag) { 7916 if (vflag)
7486 vflag = xflag = 0; 7917 vflag = 0, vflag_set = 1;
7487 } 7918 }
7488 cmdloop(0); 7919 cmdloop(0);
7489 xflag = xflag_save; 7920 if (qflag) {
7490 vflag = vflag_save; 7921 if (xflag_set)
7922 xflag = 1;
7923 if (vflag_set)
7924 vflag = 1;
7925 }
7491 popfile(); 7926 popfile();
7492} 7927}
7493 7928
@@ -7497,7 +7932,8 @@ static void read_profile(const char *name)
7497 * Read a file containing shell functions. 7932 * Read a file containing shell functions.
7498 */ 7933 */
7499 7934
7500static void readcmdfile(const char *name) 7935static void
7936readcmdfile(char *name)
7501{ 7937{
7502 int fd; 7938 int fd;
7503 7939
@@ -7512,23 +7948,23 @@ static void readcmdfile(const char *name)
7512} 7948}
7513 7949
7514 7950
7515
7516/* 7951/*
7517 * Take commands from a file. To be compatable we should do a path 7952 * Take commands from a file. To be compatible we should do a path
7518 * search for the file, which is necessary to find sub-commands. 7953 * search for the file, which is necessary to find sub-commands.
7519 */ 7954 */
7520 7955
7521static inline char *find_dot_file(char *mybasename) 7956static inline char *
7957find_dot_file(char *name)
7522{ 7958{
7523 char *fullname; 7959 char *fullname;
7524 const char *path = pathval(); 7960 const char *path = pathval();
7525 struct stat statb; 7961 struct stat statb;
7526 7962
7527 /* don't try this for absolute or relative paths */ 7963 /* don't try this for absolute or relative paths */
7528 if (strchr(mybasename, '/')) 7964 if (strchr(name, '/'))
7529 return mybasename; 7965 return name;
7530 7966
7531 while ((fullname = padvance(&path, mybasename)) != NULL) { 7967 while ((fullname = padvance(&path, name)) != NULL) {
7532 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 7968 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7533 /* 7969 /*
7534 * Don't bother freeing here, since it will 7970 * Don't bother freeing here, since it will
@@ -7540,107 +7976,149 @@ static inline char *find_dot_file(char *mybasename)
7540 } 7976 }
7541 7977
7542 /* not found in the PATH */ 7978 /* not found in the PATH */
7543 error("%s: not found", mybasename); 7979 error(not_found_msg, name);
7544 /* NOTREACHED */ 7980 /* NOTREACHED */
7545} 7981}
7546 7982
7547static int dotcmd(int argc, char **argv) 7983int
7984dotcmd(int argc, char **argv)
7548{ 7985{
7549 struct strlist *sp;
7550 volatile struct shparam saveparam;
7551
7552 exitstatus = 0; 7986 exitstatus = 0;
7553 7987
7554 for (sp = cmdenviron; sp; sp = sp->next) 7988 if (argc >= 2) { /* That's what SVR2 does */
7555 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
7556
7557 if (argc >= 2) { /* That's what SVR2 does */
7558 char *fullname; 7989 char *fullname;
7559 struct stackmark smark; 7990 struct stackmark smark;
7560 7991
7561 setstackmark(&smark); 7992 setstackmark(&smark);
7562 fullname = find_dot_file(argv[1]); 7993 fullname = find_dot_file(argv[1]);
7563
7564 if (argc > 2) {
7565 saveparam = shellparam;
7566 shellparam.malloc = 0;
7567 shellparam.nparam = argc - 2;
7568 shellparam.p = argv + 2;
7569 };
7570
7571 setinputfile(fullname, 1); 7994 setinputfile(fullname, 1);
7572 commandname = fullname; 7995 commandname = fullname;
7573 cmdloop(0); 7996 cmdloop(0);
7574 popfile(); 7997 popfile();
7575
7576 if (argc > 2) {
7577 freeparam(&shellparam);
7578 shellparam = saveparam;
7579 };
7580
7581 popstackmark(&smark); 7998 popstackmark(&smark);
7582 } 7999 }
7583 return exitstatus; 8000 return exitstatus;
7584} 8001}
7585 8002
7586 8003
7587static int exitcmd(int argc, char **argv) 8004static int
8005exitcmd(int argc, char **argv)
7588{ 8006{
7589 if (stoppedjobs()) 8007 if (stoppedjobs())
7590 return 0; 8008 return 0;
7591
7592 if (argc > 1) 8009 if (argc > 1)
7593 exitstatus = number(argv[1]); 8010 exitstatus = number(argv[1]);
7594 else 8011 exraise(EXEXIT);
7595 exitstatus = oexitstatus;
7596 exitshell(exitstatus);
7597 /* NOTREACHED */ 8012 /* NOTREACHED */
7598} 8013}
7599 8014
7600static pointer stalloc(int nbytes) 8015/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8016
8017/*
8018 * Like malloc, but returns an error when out of space.
8019 */
8020
8021static pointer
8022ckmalloc(size_t nbytes)
8023{
8024 pointer p;
8025
8026 p = malloc(nbytes);
8027 if (p == NULL)
8028 error(bb_msg_memory_exhausted);
8029 return p;
8030}
8031
8032
8033/*
8034 * Same for realloc.
8035 */
8036
8037static pointer
8038ckrealloc(pointer p, size_t nbytes)
8039{
8040 p = realloc(p, nbytes);
8041 if (p == NULL)
8042 error(bb_msg_memory_exhausted);
8043 return p;
8044}
8045
8046
8047/*
8048 * Make a copy of a string in safe storage.
8049 */
8050
8051static char *
8052savestr(const char *s)
8053{
8054 char *p = strdup(s);
8055 if (!p)
8056 error(bb_msg_memory_exhausted);
8057 return p;
8058}
8059
8060
8061/*
8062 * Parse trees for commands are allocated in lifo order, so we use a stack
8063 * to make this more efficient, and also to avoid all sorts of exception
8064 * handling code to handle interrupts in the middle of a parse.
8065 *
8066 * The size 504 was chosen because the Ultrix malloc handles that size
8067 * well.
8068 */
8069
8070
8071static pointer
8072stalloc(size_t nbytes)
7601{ 8073{
7602 char *p; 8074 char *p;
8075 size_t aligned;
7603 8076
7604 nbytes = ALIGN(nbytes); 8077 aligned = SHELL_ALIGN(nbytes);
7605 if (nbytes > stacknleft) { 8078 if (aligned > stacknleft) {
7606 int blocksize; 8079 size_t len;
8080 size_t blocksize;
7607 struct stack_block *sp; 8081 struct stack_block *sp;
7608 8082
7609 blocksize = nbytes; 8083 blocksize = aligned;
7610 if (blocksize < MINSIZE) 8084 if (blocksize < MINSIZE)
7611 blocksize = MINSIZE; 8085 blocksize = MINSIZE;
8086 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8087 if (len < blocksize)
8088 error(bb_msg_memory_exhausted);
7612 INTOFF; 8089 INTOFF;
7613 sp = xmalloc(sizeof(struct stack_block) - MINSIZE + blocksize); 8090 sp = ckmalloc(len);
7614 sp->prev = stackp; 8091 sp->prev = stackp;
7615 stacknxt = sp->space; 8092 stacknxt = sp->space;
7616 stacknleft = blocksize; 8093 stacknleft = blocksize;
8094 sstrend = stacknxt + blocksize;
7617 stackp = sp; 8095 stackp = sp;
7618 INTON; 8096 INTON;
7619 } 8097 }
7620 p = stacknxt; 8098 p = stacknxt;
7621 stacknxt += nbytes; 8099 stacknxt += aligned;
7622 stacknleft -= nbytes; 8100 stacknleft -= aligned;
7623 return p; 8101 return p;
7624} 8102}
7625 8103
7626 8104
7627static void stunalloc(pointer p) 8105void
8106stunalloc(pointer p)
7628{ 8107{
7629#ifdef DEBUG 8108#ifdef DEBUG
7630 if (p == NULL) { /*DEBUG */ 8109 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
7631 write(2, "stunalloc\n", 10); 8110 write(2, "stunalloc\n", 10);
7632 abort(); 8111 abort();
7633 } 8112 }
7634#endif 8113#endif
7635 if (!(stacknxt >= (char *) p && (char *) p >= stackp->space)) { 8114 stacknleft += stacknxt - (char *)p;
7636 p = stackp->space;
7637 }
7638 stacknleft += stacknxt - (char *) p;
7639 stacknxt = p; 8115 stacknxt = p;
7640} 8116}
7641 8117
7642 8118
7643static void setstackmark(struct stackmark *mark) 8119
8120void
8121setstackmark(struct stackmark *mark)
7644{ 8122{
7645 mark->stackp = stackp; 8123 mark->stackp = stackp;
7646 mark->stacknxt = stacknxt; 8124 mark->stacknxt = stacknxt;
@@ -7650,7 +8128,8 @@ static void setstackmark(struct stackmark *mark)
7650} 8128}
7651 8129
7652 8130
7653static void popstackmark(struct stackmark *mark) 8131void
8132popstackmark(struct stackmark *mark)
7654{ 8133{
7655 struct stack_block *sp; 8134 struct stack_block *sp;
7656 8135
@@ -7659,10 +8138,11 @@ static void popstackmark(struct stackmark *mark)
7659 while (stackp != mark->stackp) { 8138 while (stackp != mark->stackp) {
7660 sp = stackp; 8139 sp = stackp;
7661 stackp = sp->prev; 8140 stackp = sp->prev;
7662 free(sp); 8141 ckfree(sp);
7663 } 8142 }
7664 stacknxt = mark->stacknxt; 8143 stacknxt = mark->stacknxt;
7665 stacknleft = mark->stacknleft; 8144 stacknleft = mark->stacknleft;
8145 sstrend = mark->stacknxt + mark->stacknleft;
7666 INTON; 8146 INTON;
7667} 8147}
7668 8148
@@ -7677,62 +8157,69 @@ static void popstackmark(struct stackmark *mark)
7677 * part of the block that has been used. 8157 * part of the block that has been used.
7678 */ 8158 */
7679 8159
7680static void growstackblock(void) 8160void
8161growstackblock(void)
7681{ 8162{
7682 char *p; 8163 size_t newlen;
7683 int newlen = ALIGN(stacknleft * 2 + 100); 8164
7684 char *oldspace = stacknxt; 8165 newlen = stacknleft * 2;
7685 int oldlen = stacknleft; 8166 if (newlen < stacknleft)
7686 struct stack_block *sp; 8167 error(bb_msg_memory_exhausted);
7687 struct stack_block *oldstackp; 8168 if (newlen < 128)
8169 newlen += 128;
7688 8170
7689 if (stacknxt == stackp->space && stackp != &stackbase) { 8171 if (stacknxt == stackp->space && stackp != &stackbase) {
8172 struct stack_block *oldstackp;
8173 struct stackmark *xmark;
8174 struct stack_block *sp;
8175 struct stack_block *prevstackp;
8176 size_t grosslen;
8177
7690 INTOFF; 8178 INTOFF;
7691 oldstackp = stackp; 8179 oldstackp = stackp;
7692 sp = stackp; 8180 sp = stackp;
7693 stackp = sp->prev; 8181 prevstackp = sp->prev;
7694 sp = xrealloc((pointer) sp, 8182 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
7695 sizeof(struct stack_block) - MINSIZE + newlen); 8183 sp = ckrealloc((pointer)sp, grosslen);
7696 sp->prev = stackp; 8184 sp->prev = prevstackp;
7697 stackp = sp; 8185 stackp = sp;
7698 stacknxt = sp->space; 8186 stacknxt = sp->space;
7699 stacknleft = newlen; 8187 stacknleft = newlen;
7700 { 8188 sstrend = sp->space + newlen;
7701 /* Stack marks pointing to the start of the old block 8189
7702 * must be relocated to point to the new block 8190 /*
7703 */ 8191 * Stack marks pointing to the start of the old block
7704 struct stackmark *xmark; 8192 * must be relocated to point to the new block
7705 8193 */
7706 xmark = markp; 8194 xmark = markp;
7707 while (xmark != NULL && xmark->stackp == oldstackp) { 8195 while (xmark != NULL && xmark->stackp == oldstackp) {
7708 xmark->stackp = stackp; 8196 xmark->stackp = stackp;
7709 xmark->stacknxt = stacknxt; 8197 xmark->stacknxt = stacknxt;
7710 xmark->stacknleft = stacknleft; 8198 xmark->stacknleft = stacknleft;
7711 xmark = xmark->marknext; 8199 xmark = xmark->marknext;
7712 }
7713 } 8200 }
7714 INTON; 8201 INTON;
7715 } else { 8202 } else {
7716 p = stalloc(newlen); 8203 char *oldspace = stacknxt;
7717 memcpy(p, oldspace, oldlen); 8204 int oldlen = stacknleft;
7718 stacknxt = p; /* free the space */ 8205 char *p = stalloc(newlen);
7719 stacknleft += newlen; /* we just allocated */ 8206
8207 /* free the space we just allocated */
8208 stacknxt = memcpy(p, oldspace, oldlen);
8209 stacknleft += newlen;
7720 } 8210 }
7721} 8211}
7722 8212
7723 8213static inline void
7724 8214grabstackblock(size_t len)
7725static inline void grabstackblock(int len)
7726{ 8215{
7727 len = ALIGN(len); 8216 len = SHELL_ALIGN(len);
7728 stacknxt += len; 8217 stacknxt += len;
7729 stacknleft -= len; 8218 stacknleft -= len;
7730} 8219}
7731 8220
7732
7733
7734/* 8221/*
7735 * The following routines are somewhat easier to use that the above. 8222 * The following routines are somewhat easier to use than the above.
7736 * The user declares a variable of type STACKSTR, which may be declared 8223 * The user declares a variable of type STACKSTR, which may be declared
7737 * to be a register. The macro STARTSTACKSTR initializes things. Then 8224 * to be a register. The macro STARTSTACKSTR initializes things. Then
7738 * the user uses the macro STPUTC to add characters to the string. In 8225 * the user uses the macro STPUTC to add characters to the string. In
@@ -7749,853 +8236,349 @@ static inline void grabstackblock(int len)
7749 * is space for at least one character. 8236 * is space for at least one character.
7750 */ 8237 */
7751 8238
7752 8239void *
7753static char *growstackstr(void) 8240growstackstr(void)
7754{ 8241{
7755 int len = stackblocksize(); 8242 size_t len = stackblocksize();
7756
7757 if (herefd >= 0 && len >= 1024) { 8243 if (herefd >= 0 && len >= 1024) {
7758 xwrite(herefd, stackblock(), len); 8244 xwrite(herefd, stackblock(), len);
7759 sstrnleft = len - 1;
7760 return stackblock(); 8245 return stackblock();
7761 } 8246 }
7762 growstackblock(); 8247 growstackblock();
7763 sstrnleft = stackblocksize() - len - 1;
7764 return stackblock() + len; 8248 return stackblock() + len;
7765} 8249}
7766 8250
7767
7768/* 8251/*
7769 * Called from CHECKSTRSPACE. 8252 * Called from CHECKSTRSPACE.
7770 */ 8253 */
7771 8254
7772static char *makestrspace(size_t newlen) 8255char *
8256makestrspace(size_t newlen, char *p)
7773{ 8257{
7774 int len = stackblocksize() - sstrnleft; 8258 size_t len = p - stacknxt;
8259 size_t size = stackblocksize();
7775 8260
7776 do { 8261 for (;;) {
8262 size_t nleft;
8263
8264 size = stackblocksize();
8265 nleft = size - len;
8266 if (nleft >= newlen)
8267 break;
7777 growstackblock(); 8268 growstackblock();
7778 sstrnleft = stackblocksize() - len; 8269 }
7779 } while (sstrnleft < newlen);
7780 return stackblock() + len; 8270 return stackblock() + len;
7781} 8271}
7782 8272
7783 8273char *
7784 8274stnputs(const char *s, size_t n, char *p)
7785static void ungrabstackstr(char *s, char *p)
7786{ 8275{
7787 stacknleft += stacknxt - s; 8276 p = makestrspace(n, p);
7788 stacknxt = s; 8277 p = mempcpy(p, s, n);
7789 sstrnleft = stacknleft - (p - s); 8278 return p;
7790} 8279}
7791 8280
7792/* 8281char *
7793 * Miscelaneous builtins. 8282stputs(const char *s, char *p)
7794 */
7795
7796
7797#undef rflag
7798
7799#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
7800typedef long rlim_t;
7801#endif
7802
7803
7804
7805/*
7806 * The read builtin. The -e option causes backslashes to escape the
7807 * following character.
7808 *
7809 * This uses unbuffered input, which may be avoidable in some cases.
7810 */
7811
7812static int readcmd(int argc, char **argv)
7813{ 8283{
7814 char **ap; 8284 return stnputs(s, strlen(s), p);
7815 int backslash;
7816 char c;
7817 int rflag;
7818 char *prompt;
7819 const char *ifs;
7820 char *p;
7821 int startword;
7822 int status;
7823 int i;
7824
7825 rflag = 0;
7826 prompt = NULL;
7827 while ((i = nextopt("p:r")) != '\0') {
7828 if (i == 'p')
7829 prompt = optionarg;
7830 else
7831 rflag = 1;
7832 }
7833 if (prompt && isatty(0)) {
7834 out2str(prompt); /* read without cmdedit */
7835 flushall();
7836 }
7837 if (*(ap = argptr) == NULL)
7838 error("arg count");
7839 if ((ifs = bltinlookup("IFS")) == NULL)
7840 ifs = defifs;
7841 status = 0;
7842 startword = 1;
7843 backslash = 0;
7844 STARTSTACKSTR(p);
7845 for (;;) {
7846 if (read(0, &c, 1) != 1) {
7847 status = 1;
7848 break;
7849 }
7850 if (c == '\0')
7851 continue;
7852 if (backslash) {
7853 backslash = 0;
7854 if (c != '\n')
7855 STPUTC(c, p);
7856 continue;
7857 }
7858 if (!rflag && c == '\\') {
7859 backslash++;
7860 continue;
7861 }
7862 if (c == '\n')
7863 break;
7864 if (startword && *ifs == ' ' && strchr(ifs, c)) {
7865 continue;
7866 }
7867 startword = 0;
7868 if (backslash && c == '\\') {
7869 if (read(0, &c, 1) != 1) {
7870 status = 1;
7871 break;
7872 }
7873 STPUTC(c, p);
7874 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
7875 STACKSTRNUL(p);
7876 setvar(*ap, stackblock(), 0);
7877 ap++;
7878 startword = 1;
7879 STARTSTACKSTR(p);
7880 } else {
7881 STPUTC(c, p);
7882 }
7883 }
7884 STACKSTRNUL(p);
7885 /* Remove trailing blanks */
7886 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
7887 *p = '\0';
7888 setvar(*ap, stackblock(), 0);
7889 while (*++ap != NULL)
7890 setvar(*ap, nullstr, 0);
7891 return status;
7892} 8285}
7893 8286
7894 8287/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
7895
7896static int umaskcmd(int argc, char **argv)
7897{
7898 static const char permuser[3] = "ugo";
7899 static const char permmode[3] = "rwx";
7900 static const short int permmask[] = {
7901 S_IRUSR, S_IWUSR, S_IXUSR,
7902 S_IRGRP, S_IWGRP, S_IXGRP,
7903 S_IROTH, S_IWOTH, S_IXOTH
7904 };
7905
7906 char *ap;
7907 mode_t mask;
7908 int i;
7909 int symbolic_mode = 0;
7910
7911 while (nextopt("S") != '\0') {
7912 symbolic_mode = 1;
7913 }
7914
7915 INTOFF;
7916 mask = umask(0);
7917 umask(mask);
7918 INTON;
7919
7920 if ((ap = *argptr) == NULL) {
7921 if (symbolic_mode) {
7922 char buf[18];
7923 char *p = buf;
7924
7925 for (i = 0; i < 3; i++) {
7926 int j;
7927
7928 *p++ = permuser[i];
7929 *p++ = '=';
7930 for (j = 0; j < 3; j++) {
7931 if ((mask & permmask[3 * i + j]) == 0) {
7932 *p++ = permmode[j];
7933 }
7934 }
7935 *p++ = ',';
7936 }
7937 *--p = 0;
7938 puts(buf);
7939 } else {
7940 printf("%.4o\n", mask);
7941 }
7942 } else {
7943 if (is_digit((unsigned char) *ap)) {
7944 mask = 0;
7945 do {
7946 if (*ap >= '8' || *ap < '0')
7947 error("Illegal number: %s", argv[1]);
7948 mask = (mask << 3) + (*ap - '0');
7949 } while (*++ap != '\0');
7950 umask(mask);
7951 } else {
7952 mask = ~mask & 0777;
7953 if (!bb_parse_mode(ap, &mask)) {
7954 error("Illegal mode: %s", ap);
7955 }
7956 umask(~mask & 0777);
7957 }
7958 }
7959 return 0;
7960}
7961 8288
7962/* 8289/*
7963 * ulimit builtin 8290 * String functions.
7964 * 8291 *
7965 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 8292 * number(s) Convert a string of digits to an integer.
7966 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 8293 * is_number(s) Return true if s is a string of digits.
7967 * ash by J.T. Conklin.
7968 *
7969 * Public domain.
7970 */ 8294 */
7971 8295
7972struct limits {
7973 const char *name;
7974 short cmd;
7975 short factor; /* multiply by to get rlim_{cur,max} values */
7976};
7977
7978static const struct limits limits[] = {
7979#ifdef RLIMIT_CPU
7980 {"time(seconds)", RLIMIT_CPU, 1},
7981#endif
7982#ifdef RLIMIT_FSIZE
7983 {"file(blocks)", RLIMIT_FSIZE, 512},
7984#endif
7985#ifdef RLIMIT_DATA
7986 {"data(kbytes)", RLIMIT_DATA, 1024},
7987#endif
7988#ifdef RLIMIT_STACK
7989 {"stack(kbytes)", RLIMIT_STACK, 1024},
7990#endif
7991#ifdef RLIMIT_CORE
7992 {"coredump(blocks)", RLIMIT_CORE, 512},
7993#endif
7994#ifdef RLIMIT_RSS
7995 {"memory(kbytes)", RLIMIT_RSS, 1024},
7996#endif
7997#ifdef RLIMIT_MEMLOCK
7998 {"locked memory(kbytes)", RLIMIT_MEMLOCK, 1024},
7999#endif
8000#ifdef RLIMIT_NPROC
8001 {"process(processes)", RLIMIT_NPROC, 1},
8002#endif
8003#ifdef RLIMIT_NOFILE
8004 {"nofiles(descriptors)", RLIMIT_NOFILE, 1},
8005#endif
8006#ifdef RLIMIT_VMEM
8007 {"vmemory(kbytes)", RLIMIT_VMEM, 1024},
8008#endif
8009#ifdef RLIMIT_SWAP
8010 {"swap(kbytes)", RLIMIT_SWAP, 1024},
8011#endif
8012 {NULL, 0, 0}
8013};
8014
8015static int ulimitcmd(int argc, char **argv)
8016{
8017 static const char unlimited_string[] = "unlimited";
8018 int c;
8019 rlim_t val = 0;
8020 enum { SOFT = 0x1, HARD = 0x2 } how = SOFT | HARD;
8021 const struct limits *l;
8022 int set, all = 0;
8023 int optc, what;
8024 struct rlimit limit;
8025
8026 what = 'f';
8027
8028 while ((optc = nextopt("HSa"
8029#ifdef RLIMIT_CPU
8030 "t"
8031#endif
8032#ifdef RLIMIT_FSIZE
8033 "f"
8034#endif
8035#ifdef RLIMIT_DATA
8036 "d"
8037#endif
8038#ifdef RLIMIT_STACK
8039 "s"
8040#endif
8041#ifdef RLIMIT_CORE
8042 "c"
8043#endif
8044#ifdef RLIMIT_RSS
8045 "m"
8046#endif
8047#ifdef RLIMIT_MEMLOCK
8048 "l"
8049#endif
8050#ifdef RLIMIT_NPROC
8051 "p"
8052#endif
8053#ifdef RLIMIT_NOFILE
8054 "n"
8055#endif
8056#ifdef RLIMIT_VMEM
8057 "v"
8058#endif
8059#ifdef RLIMIT_SWAP
8060 "w"
8061#endif
8062 )) != '\0') {
8063 if (optc == 'H') {
8064 how = HARD;
8065 } else if (optc == 'S') {
8066 how = SOFT;
8067 } else if (optc == 'a') {
8068 all = 1;
8069 } else {
8070 what = optc;
8071 }
8072 }
8073
8074 for (l = limits; l->name; l++) {
8075 if (l->name[0] == what)
8076 break;
8077 if (l->name[1] == 'w' && what == 'w')
8078 break;
8079 }
8080
8081 set = *argptr ? 1 : 0;
8082 if (set) {
8083 char *p = *argptr;
8084
8085 if (all || argptr[1])
8086 error("too many arguments");
8087 if (strcmp(p, unlimited_string) == 0)
8088 val = RLIM_INFINITY;
8089 else {
8090 val = (rlim_t) 0;
8091
8092 while ((c = *p++) >= '0' && c <= '9') {
8093 val = (val * 10) + (long) (c - '0');
8094 if (val < (rlim_t) 0)
8095 break;
8096 }
8097 if (c)
8098 error("bad number");
8099 val *= l->factor;
8100 }
8101 }
8102
8103 if (all) {
8104 for (l = limits; l->name; l++) {
8105 printf("%-20s ", l->name);
8106 getrlimit(l->cmd, &limit);
8107 OUTPUT_LIMIT:
8108 if (how & SOFT)
8109 val = limit.rlim_cur;
8110 else if (how & HARD)
8111 val = limit.rlim_max;
8112
8113 if (val == RLIM_INFINITY)
8114 puts(unlimited_string);
8115 else {
8116 val /= l->factor;
8117 printf("%lld\n", (long long) val);
8118 }
8119 if (!all) {
8120 break;
8121 }
8122 }
8123 return 0;
8124 }
8125
8126 if (!set) {
8127 goto OUTPUT_LIMIT;
8128 }
8129
8130 getrlimit(l->cmd, &limit);
8131 if (how & HARD)
8132 limit.rlim_max = val;
8133 if (how & SOFT)
8134 limit.rlim_cur = val;
8135 if (setrlimit(l->cmd, &limit) < 0)
8136 error("error setting limit (%m)");
8137 return 0;
8138}
8139
8140/* 8296/*
8141 * prefix -- see if pfx is a prefix of string. 8297 * prefix -- see if pfx is a prefix of string.
8142 */ 8298 */
8143 8299
8144static int prefix(char const *pfx, char const *string) 8300char *
8301prefix(const char *string, const char *pfx)
8145{ 8302{
8146 while (*pfx) { 8303 while (*pfx) {
8147 if (*pfx++ != *string++) 8304 if (*pfx++ != *string++)
8148 return 0; 8305 return 0;
8149 } 8306 }
8150 return 1; 8307 return (char *) string;
8151} 8308}
8152 8309
8310
8153/* 8311/*
8154 * Return true if s is a string of digits, and save munber in intptr 8312 * Convert a string of digits to an integer, printing an error message on
8155 * nagative is bad 8313 * failure.
8156 */ 8314 */
8157 8315
8158static int is_number(const char *p, int *intptr) 8316int
8317number(const char *s)
8159{ 8318{
8160 int ret = 0;
8161 8319
8162 do { 8320 if (! is_number(s))
8163 if (!is_digit(*p)) 8321 error(illnum, s);
8164 return 0; 8322 return atoi(s);
8165 ret *= 10;
8166 ret += digit_val(*p);
8167 p++;
8168 } while (*p != '\0');
8169
8170 *intptr = ret;
8171 return 1;
8172} 8323}
8173 8324
8325
8326
8174/* 8327/*
8175 * Convert a string of digits to an integer, printing an error message on 8328 * Check for a valid number. This should be elsewhere.
8176 * failure.
8177 */ 8329 */
8178 8330
8179static int number(const char *s) 8331int
8332is_number(const char *p)
8180{ 8333{
8181 int i; 8334 do {
8182 8335 if (! is_digit(*p))
8183 if (!is_number(s, &i)) 8336 return 0;
8184 error("Illegal number: %s", s); 8337 } while (*++p != '\0');
8185 return i; 8338 return 1;
8186} 8339}
8187 8340
8341
8188/* 8342/*
8189 * Produce a possibly single quoted string suitable as input to the shell. 8343 * Produce a possibly single quoted string suitable as input to the shell.
8190 * The return string is allocated on the stack. 8344 * The return string is allocated on the stack.
8191 */ 8345 */
8192 8346
8193static char *single_quote(const char *s) 8347char *
8194{ 8348single_quote(const char *s) {
8195 char *p; 8349 char *p;
8196 8350
8197 STARTSTACKSTR(p); 8351 STARTSTACKSTR(p);
8198 8352
8199 do { 8353 do {
8200 char *q = p; 8354 char *q;
8201 size_t len1, len1p, len2, len2p; 8355 size_t len;
8202 8356
8203 len1 = strcspn(s, "'"); 8357 len = strchrnul(s, '\'') - s;
8204 len2 = strspn(s + len1, "'");
8205 8358
8206 len1p = len1 ? len1 + 2 : len1; 8359 q = p = makestrspace(len + 3, p);
8207 len2p = len2 + ((len2 < 2) ? len2 : 2);
8208 8360
8209 CHECKSTRSPACE(len1p + len2p + 1, p); 8361 *q++ = '\'';
8362 q = mempcpy(q, s, len);
8363 *q++ = '\'';
8364 s += len;
8210 8365
8211 if (len1) { 8366 STADJUST(q - p, p);
8212 *p = '\'';
8213 q = p + 1 + len1;
8214 memcpy(p + 1, s, len1);
8215 *q++ = '\'';
8216 s += len1;
8217 }
8218 8367
8219 if (len2 > 1) { 8368 len = strspn(s, "'");
8220 *q = '"'; 8369 if (!len)
8221 q += 1 + len2; 8370 break;
8222 memcpy(q + 1, s, len2); 8371
8223 *q = '"'; 8372 q = p = makestrspace(len + 3, p);
8224 s += len2; 8373
8225 } else if (len2 == 1) { 8374 *q++ = '"';
8226 *q++ = '\\'; 8375 q = mempcpy(q, s, len);
8227 *q = '\''; 8376 *q++ = '"';
8228 s++; 8377 s += len;
8229 }
8230 8378
8231 STADJUST(len1p + len2p, p); 8379 STADJUST(q - p, p);
8232 } while (*s); 8380 } while (*s);
8233 8381
8234 USTPUTC(0, p); 8382 USTPUTC(0, p);
8235 8383
8236 return grabstackstr(p); 8384 return stackblock();
8237} 8385}
8238 8386
8239/* 8387/*
8240 * Routine for dealing with parsed shell commands. 8388 * Like strdup but works with the ash stack.
8241 */ 8389 */
8242 8390
8243 8391char *
8244static void sizenodelist(const struct nodelist *); 8392sstrdup(const char *p)
8245static struct nodelist *copynodelist(const struct nodelist *);
8246static char *nodesavestr(const char *);
8247
8248#define CALCSIZE_TABLE
8249#define COPYNODE_TABLE
8250#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8251/*
8252 * To collect a lot of redundant code in case statements for copynode()
8253 * and calcsize(), we implement a mini language here. Each type of node
8254 * struct has an associated instruction sequence that operates on its
8255 * members via their offsets. The instruction are pack in unsigned chars
8256 * with format IIDDDDDE where the bits are
8257 * I : part of the instruction opcode, which are
8258 * 00 : member is a pointer to another node
8259 * 40 : member is an integer
8260 * 80 : member is a pointer to a nodelist
8261 * CC : member is a pointer to a char string
8262 * D : data - the actual offset of the member to operate on in the struct
8263 * (since we assume bit 0 is set, it is not shifted)
8264 * E : flag signaling end of instruction sequence
8265 *
8266 * WARNING: In order to handle larger offsets for 64bit archs, this code
8267 * assumes that no offset can be an odd number and stores the
8268 * end-of-instructions flag in bit 0.
8269 */
8270
8271#define NODE_INTEGER 0x40
8272#define NODE_NODELIST 0x80
8273#define NODE_CHARPTR 0xC0
8274#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned) */
8275#define NODE_MBRMASK 0xC0
8276#define NODE_OFFSETMASK 0x3E
8277
8278static const unsigned char copynode_ops[35] = {
8279#define COPYNODE_OPS0 0
8280 offsetof(union node, nbinary.ch2),
8281 offsetof(union node, nbinary.ch1) | NODE_NOMORE,
8282#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8283 offsetof(union node, ncmd.redirect),
8284 offsetof(union node, ncmd.args),
8285 offsetof(union node, ncmd.assign),
8286 offsetof(union node, ncmd.backgnd) | NODE_INTEGER | NODE_NOMORE,
8287#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8288 offsetof(union node, npipe.cmdlist) | NODE_NODELIST,
8289 offsetof(union node, npipe.backgnd) | NODE_INTEGER | NODE_NOMORE,
8290#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8291 offsetof(union node, nredir.redirect),
8292 offsetof(union node, nredir.n) | NODE_NOMORE,
8293#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8294 offsetof(union node, nif.elsepart),
8295 offsetof(union node, nif.ifpart),
8296 offsetof(union node, nif.test) | NODE_NOMORE,
8297#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8298 offsetof(union node, nfor.var) | NODE_CHARPTR,
8299 offsetof(union node, nfor.body),
8300 offsetof(union node, nfor.args) | NODE_NOMORE,
8301#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8302 offsetof(union node, ncase.cases),
8303 offsetof(union node, ncase.expr) | NODE_NOMORE,
8304#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8305 offsetof(union node, nclist.body),
8306 offsetof(union node, nclist.pattern),
8307 offsetof(union node, nclist.next) | NODE_NOMORE,
8308#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8309 offsetof(union node, narg.backquote) | NODE_NODELIST,
8310 offsetof(union node, narg.text) | NODE_CHARPTR,
8311 offsetof(union node, narg.next) | NODE_NOMORE,
8312#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8313 offsetof(union node, nfile.fname),
8314 offsetof(union node, nfile.fd) | NODE_INTEGER,
8315 offsetof(union node, nfile.next) | NODE_NOMORE,
8316#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8317 offsetof(union node, ndup.vname),
8318 offsetof(union node, ndup.dupfd) | NODE_INTEGER,
8319 offsetof(union node, ndup.fd) | NODE_INTEGER,
8320 offsetof(union node, ndup.next) | NODE_NOMORE,
8321#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8322 offsetof(union node, nhere.doc),
8323 offsetof(union node, nhere.fd) | NODE_INTEGER,
8324 offsetof(union node, nhere.next) | NODE_NOMORE,
8325#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8326 offsetof(union node, nnot.com) | NODE_NOMORE,
8327};
8328
8329#if COPYNODE_OPS12 != 34
8330#error COPYNODE_OPS12 is incorrect
8331#endif
8332
8333static const unsigned char copynode_ops_index[26] = {
8334 COPYNODE_OPS0, /* NSEMI */
8335 COPYNODE_OPS1, /* NCMD */
8336 COPYNODE_OPS2, /* NPIPE */
8337 COPYNODE_OPS3, /* NREDIR */
8338 COPYNODE_OPS3, /* NBACKGND */
8339 COPYNODE_OPS3, /* NSUBSHELL */
8340 COPYNODE_OPS0, /* NAND */
8341 COPYNODE_OPS0, /* NOR */
8342 COPYNODE_OPS4, /* NIF */
8343 COPYNODE_OPS0, /* NWHILE */
8344 COPYNODE_OPS0, /* NUNTIL */
8345 COPYNODE_OPS5, /* NFOR */
8346 COPYNODE_OPS6, /* NCASE */
8347 COPYNODE_OPS7, /* NCLIST */
8348 COPYNODE_OPS8, /* NDEFUN */
8349 COPYNODE_OPS8, /* NARG */
8350 COPYNODE_OPS9, /* NTO */
8351 COPYNODE_OPS9, /* NFROM */
8352 COPYNODE_OPS9, /* NFROMTO */
8353 COPYNODE_OPS9, /* NAPPEND */
8354 COPYNODE_OPS9, /* NTOOV */
8355 COPYNODE_OPS10, /* NTOFD */
8356 COPYNODE_OPS10, /* NFROMFD */
8357 COPYNODE_OPS11, /* NHERE */
8358 COPYNODE_OPS11, /* NXHERE */
8359 COPYNODE_OPS12, /* NNOT */
8360};
8361
8362#if NODE_CHARPTR != NODE_MBRMASK
8363#error NODE_CHARPTR != NODE_MBRMASK!!!
8364#endif
8365#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8366
8367#ifdef COPYNODE_TABLE
8368static union node *copynode(const union node *n)
8369{ 8393{
8370 union node *new; 8394 size_t len = strlen(p) + 1;
8371 const unsigned char *p; 8395 return memcpy(stalloc(len), p, len);
8372
8373 if (n == NULL) {
8374 return NULL;
8375 }
8376 new = funcblock;
8377 new->type = n->type;
8378 funcblock = (char *) funcblock + (int) nodesize[n->type];
8379 p = copynode_ops + (int) copynode_ops_index[n->type];
8380 do {
8381 char *nn = ((char *) new) + ((int) (*p & NODE_OFFSETMASK));
8382 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
8383
8384 if (!(*p & NODE_MBRMASK)) { /* standard node */
8385 *((union node **) nn) = copynode(*((const union node **) no));
8386 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8387 *((const char **) nn) = nodesavestr(*((const char **) no));
8388 } else if (*p & NODE_NODELIST) { /* nodelist */
8389 *((struct nodelist **) nn)
8390 = copynodelist(*((const struct nodelist **) no));
8391 } else { /* integer */
8392 *((int *) nn) = *((int *) no);
8393 }
8394 } while (!(*p++ & NODE_NOMORE));
8395 return new;
8396} 8396}
8397#else /* COPYNODE_TABLE */
8398static union node *copynode(const union node *n)
8399{
8400 union node *new;
8401 8397
8402 if (n == NULL)
8403 return NULL;
8404 new = funcblock;
8405 funcblock = (char *) funcblock + nodesize[n->type];
8406 switch (n->type) {
8407 case NSEMI:
8408 case NAND:
8409 case NOR:
8410 case NWHILE:
8411 case NUNTIL:
8412 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8413 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8414 break;
8415 case NCMD:
8416 new->ncmd.redirect = copynode(n->ncmd.redirect);
8417 new->ncmd.args = copynode(n->ncmd.args);
8418 new->ncmd.assign = copynode(n->ncmd.assign);
8419 new->ncmd.backgnd = n->ncmd.backgnd;
8420 break;
8421 case NPIPE:
8422 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8423 new->npipe.backgnd = n->npipe.backgnd;
8424 break;
8425 case NREDIR:
8426 case NBACKGND:
8427 case NSUBSHELL:
8428 new->nredir.redirect = copynode(n->nredir.redirect);
8429 new->nredir.n = copynode(n->nredir.n);
8430 break;
8431 case NIF:
8432 new->nif.elsepart = copynode(n->nif.elsepart);
8433 new->nif.ifpart = copynode(n->nif.ifpart);
8434 new->nif.test = copynode(n->nif.test);
8435 break;
8436 case NFOR:
8437 new->nfor.var = nodesavestr(n->nfor.var);
8438 new->nfor.body = copynode(n->nfor.body);
8439 new->nfor.args = copynode(n->nfor.args);
8440 break;
8441 case NCASE:
8442 new->ncase.cases = copynode(n->ncase.cases);
8443 new->ncase.expr = copynode(n->ncase.expr);
8444 break;
8445 case NCLIST:
8446 new->nclist.body = copynode(n->nclist.body);
8447 new->nclist.pattern = copynode(n->nclist.pattern);
8448 new->nclist.next = copynode(n->nclist.next);
8449 break;
8450 case NDEFUN:
8451 case NARG:
8452 new->narg.backquote = copynodelist(n->narg.backquote);
8453 new->narg.text = nodesavestr(n->narg.text);
8454 new->narg.next = copynode(n->narg.next);
8455 break;
8456 case NTO:
8457 case NFROM:
8458 case NFROMTO:
8459 case NAPPEND:
8460 case NTOOV:
8461 new->nfile.fname = copynode(n->nfile.fname);
8462 new->nfile.fd = n->nfile.fd;
8463 new->nfile.next = copynode(n->nfile.next);
8464 break;
8465 case NTOFD:
8466 case NFROMFD:
8467 new->ndup.vname = copynode(n->ndup.vname);
8468 new->ndup.dupfd = n->ndup.dupfd;
8469 new->ndup.fd = n->ndup.fd;
8470 new->ndup.next = copynode(n->ndup.next);
8471 break;
8472 case NHERE:
8473 case NXHERE:
8474 new->nhere.doc = copynode(n->nhere.doc);
8475 new->nhere.fd = n->nhere.fd;
8476 new->nhere.next = copynode(n->nhere.next);
8477 break;
8478 case NNOT:
8479 new->nnot.com = copynode(n->nnot.com);
8480 break;
8481 };
8482 new->type = n->type;
8483 return new;
8484}
8485#endif /* COPYNODE_TABLE */
8486 8398
8487#ifdef CALCSIZE_TABLE 8399static void
8488static void calcsize(const union node *n) 8400calcsize(union node *n)
8489{ 8401{
8490 const unsigned char *p; 8402 if (n == NULL)
8403 return;
8404 funcblocksize += nodesize[n->type];
8405 switch (n->type) {
8406 case NCMD:
8407 calcsize(n->ncmd.redirect);
8408 calcsize(n->ncmd.args);
8409 calcsize(n->ncmd.assign);
8410 break;
8411 case NPIPE:
8412 sizenodelist(n->npipe.cmdlist);
8413 break;
8414 case NREDIR:
8415 case NBACKGND:
8416 case NSUBSHELL:
8417 calcsize(n->nredir.redirect);
8418 calcsize(n->nredir.n);
8419 break;
8420 case NAND:
8421 case NOR:
8422 case NSEMI:
8423 case NWHILE:
8424 case NUNTIL:
8425 calcsize(n->nbinary.ch2);
8426 calcsize(n->nbinary.ch1);
8427 break;
8428 case NIF:
8429 calcsize(n->nif.elsepart);
8430 calcsize(n->nif.ifpart);
8431 calcsize(n->nif.test);
8432 break;
8433 case NFOR:
8434 funcstringsize += strlen(n->nfor.var) + 1;
8435 calcsize(n->nfor.body);
8436 calcsize(n->nfor.args);
8437 break;
8438 case NCASE:
8439 calcsize(n->ncase.cases);
8440 calcsize(n->ncase.expr);
8441 break;
8442 case NCLIST:
8443 calcsize(n->nclist.body);
8444 calcsize(n->nclist.pattern);
8445 calcsize(n->nclist.next);
8446 break;
8447 case NDEFUN:
8448 case NARG:
8449 sizenodelist(n->narg.backquote);
8450 funcstringsize += strlen(n->narg.text) + 1;
8451 calcsize(n->narg.next);
8452 break;
8453 case NTO:
8454 case NCLOBBER:
8455 case NFROM:
8456 case NFROMTO:
8457 case NAPPEND:
8458 calcsize(n->nfile.fname);
8459 calcsize(n->nfile.next);
8460 break;
8461 case NTOFD:
8462 case NFROMFD:
8463 calcsize(n->ndup.vname);
8464 calcsize(n->ndup.next);
8465 break;
8466 case NHERE:
8467 case NXHERE:
8468 calcsize(n->nhere.doc);
8469 calcsize(n->nhere.next);
8470 break;
8471 case NNOT:
8472 calcsize(n->nnot.com);
8473 break;
8474 };
8475}
8491 8476
8492 if (n == NULL)
8493 return;
8494 funcblocksize += (int) nodesize[n->type];
8495 8477
8496 p = copynode_ops + (int) copynode_ops_index[n->type];
8497 do {
8498 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
8499 8478
8500 if (!(*p & NODE_MBRMASK)) { /* standard node */ 8479static void
8501 calcsize(*((const union node **) no)); 8480sizenodelist(struct nodelist *lp)
8502 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8503 funcstringsize += strlen(*((const char **) no)) + 1;
8504 } else if (*p & NODE_NODELIST) { /* nodelist */
8505 sizenodelist(*((const struct nodelist **) no));
8506 } /* else integer -- ignore */
8507 } while (!(*p++ & NODE_NOMORE));
8508}
8509#else /* CALCSIZE_TABLE */
8510static void calcsize(const union node *n)
8511{
8512 if (n == NULL)
8513 return;
8514 funcblocksize += nodesize[n->type];
8515 switch (n->type) {
8516 case NSEMI:
8517 case NAND:
8518 case NOR:
8519 case NWHILE:
8520 case NUNTIL:
8521 calcsize(n->nbinary.ch2);
8522 calcsize(n->nbinary.ch1);
8523 break;
8524 case NCMD:
8525 calcsize(n->ncmd.redirect);
8526 calcsize(n->ncmd.args);
8527 calcsize(n->ncmd.assign);
8528 break;
8529 case NPIPE:
8530 sizenodelist(n->npipe.cmdlist);
8531 break;
8532 case NREDIR:
8533 case NBACKGND:
8534 case NSUBSHELL:
8535 calcsize(n->nredir.redirect);
8536 calcsize(n->nredir.n);
8537 break;
8538 case NIF:
8539 calcsize(n->nif.elsepart);
8540 calcsize(n->nif.ifpart);
8541 calcsize(n->nif.test);
8542 break;
8543 case NFOR:
8544 funcstringsize += strlen(n->nfor.var) + 1;
8545 calcsize(n->nfor.body);
8546 calcsize(n->nfor.args);
8547 break;
8548 case NCASE:
8549 calcsize(n->ncase.cases);
8550 calcsize(n->ncase.expr);
8551 break;
8552 case NCLIST:
8553 calcsize(n->nclist.body);
8554 calcsize(n->nclist.pattern);
8555 calcsize(n->nclist.next);
8556 break;
8557 case NDEFUN:
8558 case NARG:
8559 sizenodelist(n->narg.backquote);
8560 funcstringsize += strlen(n->narg.text) + 1;
8561 calcsize(n->narg.next);
8562 break;
8563 case NTO:
8564 case NFROM:
8565 case NFROMTO:
8566 case NAPPEND:
8567 case NTOOV:
8568 calcsize(n->nfile.fname);
8569 calcsize(n->nfile.next);
8570 break;
8571 case NTOFD:
8572 case NFROMFD:
8573 calcsize(n->ndup.vname);
8574 calcsize(n->ndup.next);
8575 break;
8576 case NHERE:
8577 case NXHERE:
8578 calcsize(n->nhere.doc);
8579 calcsize(n->nhere.next);
8580 break;
8581 case NNOT:
8582 calcsize(n->nnot.com);
8583 break;
8584 };
8585}
8586#endif /* CALCSIZE_TABLE */
8587
8588static void sizenodelist(const struct nodelist *lp)
8589{ 8481{
8590 while (lp) { 8482 while (lp) {
8591 funcblocksize += ALIGN(sizeof(struct nodelist)); 8483 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8592 calcsize(lp->n); 8484 calcsize(lp->n);
8593 lp = lp->next; 8485 lp = lp->next;
8594 } 8486 }
8595} 8487}
8596 8488
8597 8489
8598static struct nodelist *copynodelist(const struct nodelist *lp) 8490
8491static union node *
8492copynode(union node *n)
8493{
8494 union node *new;
8495
8496 if (n == NULL)
8497 return NULL;
8498 new = funcblock;
8499 funcblock = (char *) funcblock + nodesize[n->type];
8500 switch (n->type) {
8501 case NCMD:
8502 new->ncmd.redirect = copynode(n->ncmd.redirect);
8503 new->ncmd.args = copynode(n->ncmd.args);
8504 new->ncmd.assign = copynode(n->ncmd.assign);
8505 break;
8506 case NPIPE:
8507 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8508 new->npipe.backgnd = n->npipe.backgnd;
8509 break;
8510 case NREDIR:
8511 case NBACKGND:
8512 case NSUBSHELL:
8513 new->nredir.redirect = copynode(n->nredir.redirect);
8514 new->nredir.n = copynode(n->nredir.n);
8515 break;
8516 case NAND:
8517 case NOR:
8518 case NSEMI:
8519 case NWHILE:
8520 case NUNTIL:
8521 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8522 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8523 break;
8524 case NIF:
8525 new->nif.elsepart = copynode(n->nif.elsepart);
8526 new->nif.ifpart = copynode(n->nif.ifpart);
8527 new->nif.test = copynode(n->nif.test);
8528 break;
8529 case NFOR:
8530 new->nfor.var = nodesavestr(n->nfor.var);
8531 new->nfor.body = copynode(n->nfor.body);
8532 new->nfor.args = copynode(n->nfor.args);
8533 break;
8534 case NCASE:
8535 new->ncase.cases = copynode(n->ncase.cases);
8536 new->ncase.expr = copynode(n->ncase.expr);
8537 break;
8538 case NCLIST:
8539 new->nclist.body = copynode(n->nclist.body);
8540 new->nclist.pattern = copynode(n->nclist.pattern);
8541 new->nclist.next = copynode(n->nclist.next);
8542 break;
8543 case NDEFUN:
8544 case NARG:
8545 new->narg.backquote = copynodelist(n->narg.backquote);
8546 new->narg.text = nodesavestr(n->narg.text);
8547 new->narg.next = copynode(n->narg.next);
8548 break;
8549 case NTO:
8550 case NCLOBBER:
8551 case NFROM:
8552 case NFROMTO:
8553 case NAPPEND:
8554 new->nfile.fname = copynode(n->nfile.fname);
8555 new->nfile.fd = n->nfile.fd;
8556 new->nfile.next = copynode(n->nfile.next);
8557 break;
8558 case NTOFD:
8559 case NFROMFD:
8560 new->ndup.vname = copynode(n->ndup.vname);
8561 new->ndup.dupfd = n->ndup.dupfd;
8562 new->ndup.fd = n->ndup.fd;
8563 new->ndup.next = copynode(n->ndup.next);
8564 break;
8565 case NHERE:
8566 case NXHERE:
8567 new->nhere.doc = copynode(n->nhere.doc);
8568 new->nhere.fd = n->nhere.fd;
8569 new->nhere.next = copynode(n->nhere.next);
8570 break;
8571 case NNOT:
8572 new->nnot.com = copynode(n->nnot.com);
8573 break;
8574 };
8575 new->type = n->type;
8576 return new;
8577}
8578
8579
8580static struct nodelist *
8581copynodelist(struct nodelist *lp)
8599{ 8582{
8600 struct nodelist *start; 8583 struct nodelist *start;
8601 struct nodelist **lpp; 8584 struct nodelist **lpp;
@@ -8603,7 +8586,8 @@ static struct nodelist *copynodelist(const struct nodelist *lp)
8603 lpp = &start; 8586 lpp = &start;
8604 while (lp) { 8587 while (lp) {
8605 *lpp = funcblock; 8588 *lpp = funcblock;
8606 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist)); 8589 funcblock = (char *) funcblock +
8590 SHELL_ALIGN(sizeof(struct nodelist));
8607 (*lpp)->n = copynode(lp->n); 8591 (*lpp)->n = copynode(lp->n);
8608 lp = lp->next; 8592 lp = lp->next;
8609 lpp = &(*lpp)->next; 8593 lpp = &(*lpp)->next;
@@ -8613,95 +8597,133 @@ static struct nodelist *copynodelist(const struct nodelist *lp)
8613} 8597}
8614 8598
8615 8599
8616static char *nodesavestr(const char *s) 8600
8601static char *
8602nodesavestr(char *s)
8617{ 8603{
8618 const char *p = s; 8604 char *rtn = funcstring;
8619 char *q = funcstring;
8620 char *rtn = funcstring;
8621 8605
8622 while ((*q++ = *p++) != '\0') 8606 funcstring = stpcpy(funcstring, s) + 1;
8623 continue;
8624 funcstring = q;
8625 return rtn; 8607 return rtn;
8626} 8608}
8627 8609
8628#ifdef CONFIG_ASH_GETOPTS 8610
8629static int getopts(char *, char *, char **, int *, int *); 8611
8630#endif 8612/*
8613 * Free a parse tree.
8614 */
8615
8616static void
8617freefunc(struct funcnode *f)
8618{
8619 if (f && --f->count < 0)
8620 ckfree(f);
8621}
8622
8623
8624static void options(int);
8625static void setoption(int, int);
8626
8631 8627
8632/* 8628/*
8633 * Process the shell command line arguments. 8629 * Process the shell command line arguments.
8634 */ 8630 */
8635 8631
8636static void procargs(int argc, char **argv) 8632void
8633procargs(int argc, char **argv)
8637{ 8634{
8638 int i; 8635 int i;
8636 const char *xminusc;
8637 char **xargv;
8639 8638
8640 argptr = argv; 8639 xargv = argv;
8640 arg0 = xargv[0];
8641 if (argc > 0) 8641 if (argc > 0)
8642 argptr++; 8642 xargv++;
8643 for (i = 0; i < NOPTS; i++) 8643 for (i = 0; i < NOPTS; i++)
8644 optent_val(i) = 2; 8644 optlist[i] = 2;
8645 argptr = xargv;
8645 options(1); 8646 options(1);
8646 if (*argptr == NULL && minusc == NULL) 8647 xargv = argptr;
8648 xminusc = minusc;
8649 if (*xargv == NULL) {
8650 if (xminusc)
8651 error("-c requires an argument");
8647 sflag = 1; 8652 sflag = 1;
8653 }
8648 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 8654 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8649 iflag = 1; 8655 iflag = 1;
8650 if (mflag == 2) 8656 if (mflag == 2)
8651 mflag = iflag; 8657 mflag = iflag;
8652 for (i = 0; i < NOPTS; i++) 8658 for (i = 0; i < NOPTS; i++)
8653 if (optent_val(i) == 2) 8659 if (optlist[i] == 2)
8654 optent_val(i) = 0; 8660 optlist[i] = 0;
8655 arg0 = argv[0]; 8661#if DEBUG == 2
8656 if (sflag == 0 && minusc == NULL) { 8662 debug = 1;
8657 commandname = argv[0]; 8663#endif
8658 arg0 = *argptr++; 8664 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8659 setinputfile(arg0, 0); 8665 if (xminusc) {
8666 minusc = *xargv++;
8667 if (*xargv)
8668 goto setarg0;
8669 } else if (!sflag) {
8670 setinputfile(*xargv, 0);
8671setarg0:
8672 arg0 = *xargv++;
8660 commandname = arg0; 8673 commandname = arg0;
8661 } 8674 }
8662 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8663 if (argptr && minusc && *argptr)
8664 arg0 = *argptr++;
8665 8675
8666 shellparam.p = argptr; 8676 shellparam.p = xargv;
8677#ifdef CONFIG_ASH_GETOPTS
8667 shellparam.optind = 1; 8678 shellparam.optind = 1;
8668 shellparam.optoff = -1; 8679 shellparam.optoff = -1;
8680#endif
8669 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 8681 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8670 while (*argptr) { 8682 while (*xargv) {
8671 shellparam.nparam++; 8683 shellparam.nparam++;
8672 argptr++; 8684 xargv++;
8673 } 8685 }
8674 optschanged(); 8686 optschanged();
8675} 8687}
8676 8688
8677 8689
8690void
8691optschanged(void)
8692{
8693#ifdef DEBUG
8694 opentrace();
8695#endif
8696 setinteractive(iflag);
8697 setjobctl(mflag);
8698}
8678 8699
8679/* 8700static inline void
8680 * Process shell options. The global variable argptr contains a pointer 8701minus_o(char *name, int val)
8681 * to the argument list; we advance it past the options.
8682 */
8683
8684static inline void minus_o(const char *name, int val)
8685{ 8702{
8686 int i; 8703 int i;
8687 8704
8688 if (name == NULL) { 8705 if (name == NULL) {
8689 out1str("Current option settings\n"); 8706 out1str("Current option settings\n");
8690 for (i = 0; i < NOPTS; i++) 8707 for (i = 0; i < NOPTS; i++)
8691 printf("%-16s%s\n", optent_name(optlist[i]), 8708 out1fmt("%-16s%s\n", optnames(i),
8692 optent_val(i) ? "on" : "off"); 8709 optlist[i] ? "on" : "off");
8693 } else { 8710 } else {
8694 for (i = 0; i < NOPTS; i++) 8711 for (i = 0; i < NOPTS; i++)
8695 if (equal(name, optent_name(optlist[i]))) { 8712 if (equal(name, optnames(i))) {
8696 setoption(optent_letter(optlist[i]), val); 8713 optlist[i] = val;
8697 return; 8714 return;
8698 } 8715 }
8699 error("Illegal option -o %s", name); 8716 error("Illegal option -o %s", name);
8700 } 8717 }
8701} 8718}
8702 8719
8720/*
8721 * Process shell options. The global variable argptr contains a pointer
8722 * to the argument list; we advance it past the options.
8723 */
8703 8724
8704static void options(int cmdline) 8725static void
8726options(int cmdline)
8705{ 8727{
8706 char *p; 8728 char *p;
8707 int val; 8729 int val;
@@ -8722,7 +8744,7 @@ static void options(int cmdline)
8722 else if (*argptr == NULL) 8744 else if (*argptr == NULL)
8723 setparam(argptr); 8745 setparam(argptr);
8724 } 8746 }
8725 break; /* "-" or "--" terminates options */ 8747 break; /* "-" or "--" terminates options */
8726 } 8748 }
8727 } else if (c == '+') { 8749 } else if (c == '+') {
8728 val = 0; 8750 val = 0;
@@ -8732,23 +8754,12 @@ static void options(int cmdline)
8732 } 8754 }
8733 while ((c = *p++) != '\0') { 8755 while ((c = *p++) != '\0') {
8734 if (c == 'c' && cmdline) { 8756 if (c == 'c' && cmdline) {
8735 char *q; 8757 minusc = p; /* command is after shell args*/
8736
8737#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
8738 if (*p == '\0')
8739#endif
8740 q = *argptr++;
8741 if (q == NULL || minusc != NULL)
8742 error("Bad -c option");
8743 minusc = q;
8744#ifdef NOHACK
8745 break;
8746#endif
8747 } else if (c == 'o') { 8758 } else if (c == 'o') {
8748 minus_o(*argptr, val); 8759 minus_o(*argptr, val);
8749 if (*argptr) 8760 if (*argptr)
8750 argptr++; 8761 argptr++;
8751 } else if (cmdline && (c == '-')) { // long options 8762 } else if (cmdline && (c == '-')) { // long options
8752 if (strcmp(p, "login") == 0) 8763 if (strcmp(p, "login") == 0)
8753 isloginsh = 1; 8764 isloginsh = 1;
8754 break; 8765 break;
@@ -8760,20 +8771,15 @@ static void options(int cmdline)
8760} 8771}
8761 8772
8762 8773
8763static void setoption(int flag, int val) 8774
8775static void
8776setoption(int flag, int val)
8764{ 8777{
8765 int i; 8778 int i;
8766 8779
8767 for (i = 0; i < NOPTS; i++) 8780 for (i = 0; i < NOPTS; i++)
8768 if (optent_letter(optlist[i]) == flag) { 8781 if (optletters(i) == flag) {
8769 optent_val(i) = val; 8782 optlist[i] = val;
8770 if (val) {
8771 /* #%$ hack for ksh semantics */
8772 if (flag == 'V')
8773 Eflag = 0;
8774 else if (flag == 'E')
8775 Vflag = 0;
8776 }
8777 return; 8783 return;
8778 } 8784 }
8779 error("Illegal option -%c", flag); 8785 error("Illegal option -%c", flag);
@@ -8786,24 +8792,27 @@ static void setoption(int flag, int val)
8786 * Set the shell parameters. 8792 * Set the shell parameters.
8787 */ 8793 */
8788 8794
8789static void setparam(char **argv) 8795void
8796setparam(char **argv)
8790{ 8797{
8791 char **newparam; 8798 char **newparam;
8792 char **ap; 8799 char **ap;
8793 int nparam; 8800 int nparam;
8794 8801
8795 for (nparam = 0; argv[nparam]; nparam++); 8802 for (nparam = 0 ; argv[nparam] ; nparam++);
8796 ap = newparam = xmalloc((nparam + 1) * sizeof *ap); 8803 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8797 while (*argv) { 8804 while (*argv) {
8798 *ap++ = bb_xstrdup(*argv++); 8805 *ap++ = savestr(*argv++);
8799 } 8806 }
8800 *ap = NULL; 8807 *ap = NULL;
8801 freeparam(&shellparam); 8808 freeparam(&shellparam);
8802 shellparam.malloc = 1; 8809 shellparam.malloc = 1;
8803 shellparam.nparam = nparam; 8810 shellparam.nparam = nparam;
8804 shellparam.p = newparam; 8811 shellparam.p = newparam;
8812#ifdef CONFIG_ASH_GETOPTS
8805 shellparam.optind = 1; 8813 shellparam.optind = 1;
8806 shellparam.optoff = -1; 8814 shellparam.optoff = -1;
8815#endif
8807} 8816}
8808 8817
8809 8818
@@ -8811,14 +8820,15 @@ static void setparam(char **argv)
8811 * Free the list of positional parameters. 8820 * Free the list of positional parameters.
8812 */ 8821 */
8813 8822
8814static void freeparam(volatile struct shparam *param) 8823void
8824freeparam(volatile struct shparam *param)
8815{ 8825{
8816 char **ap; 8826 char **ap;
8817 8827
8818 if (param->malloc) { 8828 if (param->malloc) {
8819 for (ap = param->p; *ap; ap++) 8829 for (ap = param->p ; *ap ; ap++)
8820 free(*ap); 8830 ckfree(*ap);
8821 free(param->p); 8831 ckfree(param->p);
8822 } 8832 }
8823} 8833}
8824 8834
@@ -8828,7 +8838,8 @@ static void freeparam(volatile struct shparam *param)
8828 * The shift builtin command. 8838 * The shift builtin command.
8829 */ 8839 */
8830 8840
8831static int shiftcmd(int argc, char **argv) 8841int
8842shiftcmd(int argc, char **argv)
8832{ 8843{
8833 int n; 8844 int n;
8834 char **ap1, **ap2; 8845 char **ap1, **ap2;
@@ -8840,14 +8851,16 @@ static int shiftcmd(int argc, char **argv)
8840 error("can't shift that many"); 8851 error("can't shift that many");
8841 INTOFF; 8852 INTOFF;
8842 shellparam.nparam -= n; 8853 shellparam.nparam -= n;
8843 for (ap1 = shellparam.p; --n >= 0; ap1++) { 8854 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8844 if (shellparam.malloc) 8855 if (shellparam.malloc)
8845 free(*ap1); 8856 ckfree(*ap1);
8846 } 8857 }
8847 ap2 = shellparam.p; 8858 ap2 = shellparam.p;
8848 while ((*ap2++ = *ap1++) != NULL); 8859 while ((*ap2++ = *ap1++) != NULL);
8860#ifdef CONFIG_ASH_GETOPTS
8849 shellparam.optind = 1; 8861 shellparam.optind = 1;
8850 shellparam.optoff = -1; 8862 shellparam.optoff = -1;
8863#endif
8851 INTON; 8864 INTON;
8852 return 0; 8865 return 0;
8853} 8866}
@@ -8858,10 +8871,11 @@ static int shiftcmd(int argc, char **argv)
8858 * The set command builtin. 8871 * The set command builtin.
8859 */ 8872 */
8860 8873
8861static int setcmd(int argc, char **argv) 8874int
8875setcmd(int argc, char **argv)
8862{ 8876{
8863 if (argc == 1) 8877 if (argc == 1)
8864 return showvarscmd(argc, argv); 8878 return showvars(nullstr, 0, VUNSET);
8865 INTOFF; 8879 INTOFF;
8866 options(0); 8880 options(0);
8867 optschanged(); 8881 optschanged();
@@ -8873,11 +8887,15 @@ static int setcmd(int argc, char **argv)
8873} 8887}
8874 8888
8875 8889
8876static void getoptsreset(const char *value) 8890#ifdef CONFIG_ASH_GETOPTS
8891static void
8892getoptsreset(value)
8893 const char *value;
8877{ 8894{
8878 shellparam.optind = number(value); 8895 shellparam.optind = number(value);
8879 shellparam.optoff = -1; 8896 shellparam.optoff = -1;
8880} 8897}
8898#endif
8881 8899
8882#ifdef CONFIG_LOCALE_SUPPORT 8900#ifdef CONFIG_LOCALE_SUPPORT
8883static void change_lc_all(const char *value) 8901static void change_lc_all(const char *value)
@@ -8895,74 +8913,18 @@ static void change_lc_ctype(const char *value)
8895#endif 8913#endif
8896 8914
8897#ifdef CONFIG_ASH_GETOPTS 8915#ifdef CONFIG_ASH_GETOPTS
8898/*
8899 * The getopts builtin. Shellparam.optnext points to the next argument
8900 * to be processed. Shellparam.optptr points to the next character to
8901 * be processed in the current argument. If shellparam.optnext is NULL,
8902 * then it's the first time getopts has been called.
8903 */
8904
8905static int getoptscmd(int argc, char **argv)
8906{
8907 char **optbase;
8908
8909 if (argc < 3)
8910 error("Usage: getopts optstring var [arg]");
8911 else if (argc == 3) {
8912 optbase = shellparam.p;
8913 if (shellparam.optind > shellparam.nparam + 1) {
8914 shellparam.optind = 1;
8915 shellparam.optoff = -1;
8916 }
8917 } else {
8918 optbase = &argv[3];
8919 if (shellparam.optind > argc - 2) {
8920 shellparam.optind = 1;
8921 shellparam.optoff = -1;
8922 }
8923 }
8924
8925 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
8926 &shellparam.optoff);
8927}
8928
8929/*
8930 * Safe version of setvar, returns 1 on success 0 on failure.
8931 */
8932
8933static int setvarsafe(const char *name, const char *val, int flags)
8934{
8935 struct jmploc jmploc;
8936 struct jmploc *volatile savehandler = handler;
8937 int err = 0;
8938
8939#ifdef __GNUC__
8940 (void) &err;
8941#endif
8942
8943 if (setjmp(jmploc.loc))
8944 err = 1;
8945 else {
8946 handler = &jmploc;
8947 setvar(name, val, flags);
8948 }
8949 handler = savehandler;
8950 return err;
8951}
8952
8953static int 8916static int
8954getopts(char *optstr, char *optvar, char **optfirst, int *myoptind, 8917getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
8955 int *optoff)
8956{ 8918{
8957 char *p, *q; 8919 char *p, *q;
8958 char c = '?'; 8920 char c = '?';
8959 int done = 0; 8921 int done = 0;
8960 int err = 0; 8922 int err = 0;
8961 char s[10]; 8923 char s[10];
8962 char **optnext = optfirst + *myoptind - 1; 8924 char **optnext = optfirst + *param_optind - 1;
8963 8925
8964 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) || 8926 if (*param_optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
8965 strlen(*(optnext - 1)) < *optoff) 8927 strlen(*(optnext - 1)) < *optoff)
8966 p = NULL; 8928 p = NULL;
8967 else 8929 else
8968 p = *(optnext - 1) + *optoff; 8930 p = *(optnext - 1) + *optoff;
@@ -8972,30 +8934,29 @@ getopts(char *optstr, char *optvar, char **optfirst, int *myoptind,
8972 return 1; 8934 return 1;
8973 p = *optnext; 8935 p = *optnext;
8974 if (p == NULL || *p != '-' || *++p == '\0') { 8936 if (p == NULL || *p != '-' || *++p == '\0') {
8975 atend: 8937atend:
8976 *myoptind = optnext - optfirst + 1;
8977 p = NULL; 8938 p = NULL;
8978 done = 1; 8939 done = 1;
8979 goto out; 8940 goto out;
8980 } 8941 }
8981 optnext++; 8942 optnext++;
8982 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 8943 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
8983 goto atend; 8944 goto atend;
8984 } 8945 }
8985 8946
8986 c = *p++; 8947 c = *p++;
8987 for (q = optstr; *q != c;) { 8948 for (q = optstr; *q != c; ) {
8988 if (*q == '\0') { 8949 if (*q == '\0') {
8989 if (optstr[0] == ':') { 8950 if (optstr[0] == ':') {
8990 s[0] = c; 8951 s[0] = c;
8991 s[1] = '\0'; 8952 s[1] = '\0';
8992 err |= setvarsafe("OPTARG", s, 0); 8953 err |= setvarsafe("OPTARG", s, 0);
8993 } else { 8954 } else {
8994 out2fmt("Illegal option -%c\n", c); 8955 fprintf(stderr, "Illegal option -%c\n", c);
8995 (void) unsetvar("OPTARG"); 8956 (void) unsetvar("OPTARG");
8996 } 8957 }
8997 c = '?'; 8958 c = '?';
8998 goto bad; 8959 goto out;
8999 } 8960 }
9000 if (*++q == ':') 8961 if (*++q == ':')
9001 q++; 8962 q++;
@@ -9009,40 +8970,70 @@ getopts(char *optstr, char *optvar, char **optfirst, int *myoptind,
9009 err |= setvarsafe("OPTARG", s, 0); 8970 err |= setvarsafe("OPTARG", s, 0);
9010 c = ':'; 8971 c = ':';
9011 } else { 8972 } else {
9012 out2fmt("No arg for -%c option\n", c); 8973 fprintf(stderr, "No arg for -%c option\n", c);
9013 (void) unsetvar("OPTARG"); 8974 (void) unsetvar("OPTARG");
9014 c = '?'; 8975 c = '?';
9015 } 8976 }
9016 goto bad; 8977 goto out;
9017 } 8978 }
9018 8979
9019 if (p == *optnext) 8980 if (p == *optnext)
9020 optnext++; 8981 optnext++;
9021 setvarsafe("OPTARG", p, 0); 8982 err |= setvarsafe("OPTARG", p, 0);
9022 p = NULL; 8983 p = NULL;
9023 } else 8984 } else
9024 setvarsafe("OPTARG", "", 0); 8985 err |= setvarsafe("OPTARG", nullstr, 0);
9025 *myoptind = optnext - optfirst + 1;
9026 goto out;
9027 8986
9028 bad: 8987out:
9029 *myoptind = 1;
9030 p = NULL;
9031 out:
9032 *optoff = p ? p - *(optnext - 1) : -1; 8988 *optoff = p ? p - *(optnext - 1) : -1;
9033 snprintf(s, sizeof(s), "%d", *myoptind); 8989 *param_optind = optnext - optfirst + 1;
8990 fmtstr(s, sizeof(s), "%d", *param_optind);
9034 err |= setvarsafe("OPTIND", s, VNOFUNC); 8991 err |= setvarsafe("OPTIND", s, VNOFUNC);
9035 s[0] = c; 8992 s[0] = c;
9036 s[1] = '\0'; 8993 s[1] = '\0';
9037 err |= setvarsafe(optvar, s, 0); 8994 err |= setvarsafe(optvar, s, 0);
9038 if (err) { 8995 if (err) {
9039 *myoptind = 1; 8996 *param_optind = 1;
9040 *optoff = -1; 8997 *optoff = -1;
8998 flushall();
9041 exraise(EXERROR); 8999 exraise(EXERROR);
9042 } 9000 }
9043 return done; 9001 return done;
9044} 9002}
9045#endif 9003
9004/*
9005 * The getopts builtin. Shellparam.optnext points to the next argument
9006 * to be processed. Shellparam.optptr points to the next character to
9007 * be processed in the current argument. If shellparam.optnext is NULL,
9008 * then it's the first time getopts has been called.
9009 */
9010
9011int
9012getoptscmd(int argc, char **argv)
9013{
9014 char **optbase;
9015
9016 if (argc < 3)
9017 error("Usage: getopts optstring var [arg]");
9018 else if (argc == 3) {
9019 optbase = shellparam.p;
9020 if (shellparam.optind > shellparam.nparam + 1) {
9021 shellparam.optind = 1;
9022 shellparam.optoff = -1;
9023 }
9024 }
9025 else {
9026 optbase = &argv[3];
9027 if (shellparam.optind > argc - 2) {
9028 shellparam.optind = 1;
9029 shellparam.optoff = -1;
9030 }
9031 }
9032
9033 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9034 &shellparam.optoff);
9035}
9036#endif /* CONFIG_ASH_GETOPTS */
9046 9037
9047/* 9038/*
9048 * XXX - should get rid of. have all builtins use getopt(3). the 9039 * XXX - should get rid of. have all builtins use getopt(3). the
@@ -9055,7 +9046,8 @@ getopts(char *optstr, char *optvar, char **optfirst, int *myoptind,
9055 * end of input. 9046 * end of input.
9056 */ 9047 */
9057 9048
9058static int nextopt(const char *optstring) 9049static int
9050nextopt(const char *optstring)
9059{ 9051{
9060 char *p; 9052 char *p;
9061 const char *q; 9053 const char *q;
@@ -9066,11 +9058,11 @@ static int nextopt(const char *optstring)
9066 if (p == NULL || *p != '-' || *++p == '\0') 9058 if (p == NULL || *p != '-' || *++p == '\0')
9067 return '\0'; 9059 return '\0';
9068 argptr++; 9060 argptr++;
9069 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 9061 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9070 return '\0'; 9062 return '\0';
9071 } 9063 }
9072 c = *p++; 9064 c = *p++;
9073 for (q = optstring; *q != c;) { 9065 for (q = optstring ; *q != c ; ) {
9074 if (*q == '\0') 9066 if (*q == '\0')
9075 error("Illegal option -%c", c); 9067 error("Illegal option -%c", c);
9076 if (*++q == ':') 9068 if (*++q == ':')
@@ -9086,52 +9078,94 @@ static int nextopt(const char *optstring)
9086 return c; 9078 return c;
9087} 9079}
9088 9080
9089static void flushall() 9081/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9082
9083
9084
9085void
9086outstr(const char *p, FILE *file)
9087{
9088 INTOFF;
9089 fputs(p, file);
9090 INTON;
9091}
9092
9093void
9094flushall(void)
9090{ 9095{
9091 INTOFF; 9096 INTOFF;
9092 fflush(stdout); 9097 fflush(stdout);
9098 fflush(stderr);
9099 INTON;
9100}
9101
9102
9103void
9104flushout(FILE *dest)
9105{
9106 INTOFF;
9107 fflush(dest);
9108 INTON;
9109}
9110
9111static void
9112outcslow(int c, FILE *dest)
9113{
9114 INTOFF;
9115 putc(c, dest);
9116 fflush(dest);
9093 INTON; 9117 INTON;
9094} 9118}
9095 9119
9096 9120
9097static void out2fmt(const char *fmt, ...) 9121static int
9122out1fmt(const char *fmt, ...)
9098{ 9123{
9099 va_list ap; 9124 va_list ap;
9125 int r;
9100 9126
9127 INTOFF;
9101 va_start(ap, fmt); 9128 va_start(ap, fmt);
9102 vfprintf(stderr, fmt, ap); 9129 r = vprintf(fmt, ap);
9103 va_end(ap); 9130 va_end(ap);
9131 INTON;
9132 return r;
9104} 9133}
9105 9134
9135
9136int
9137fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9138{
9139 va_list ap;
9140 int ret;
9141
9142 va_start(ap, fmt);
9143 INTOFF;
9144 ret = vsnprintf(outbuf, length, fmt, ap);
9145 va_end(ap);
9146 INTON;
9147 return ret;
9148}
9149
9150
9106/* 9151/*
9107 * Version of write which resumes after a signal is caught. 9152 * Version of write which resumes after a signal is caught.
9108 */ 9153 */
9109 9154
9110static int xwrite(int fd, const char *buf, int nbytes) 9155static void
9156xwrite(int fd, const void *p, size_t n)
9111{ 9157{
9112 int ntry; 9158 ssize_t i;
9113 int i;
9114 int n;
9115 9159
9116 n = nbytes; 9160 do {
9117 ntry = 0; 9161 i = bb_full_write(fd, p, n);
9118 for (;;) { 9162 } while (i < 0 && errno == EINTR);
9119 i = write(fd, buf, n);
9120 if (i > 0) {
9121 if ((n -= i) <= 0)
9122 return nbytes;
9123 buf += i;
9124 ntry = 0;
9125 } else if (i == 0) {
9126 if (++ntry > 10)
9127 return nbytes - n;
9128 } else if (errno != EINTR) {
9129 return -1;
9130 }
9131 }
9132} 9163}
9133 9164
9134 9165
9166/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9167
9168
9135/* 9169/*
9136 * Shell command parser. 9170 * Shell command parser.
9137 */ 9171 */
@@ -9139,61 +9173,66 @@ static int xwrite(int fd, const char *buf, int nbytes)
9139#define EOFMARKLEN 79 9173#define EOFMARKLEN 79
9140 9174
9141 9175
9142
9143struct heredoc { 9176struct heredoc {
9144 struct heredoc *next; /* next here document in list */ 9177 struct heredoc *next; /* next here document in list */
9145 union node *here; /* redirection node */ 9178 union node *here; /* redirection node */
9146 char *eofmark; /* string indicating end of input */ 9179 char *eofmark; /* string indicating end of input */
9147 int striptabs; /* if set, strip leading tabs */ 9180 int striptabs; /* if set, strip leading tabs */
9148}; 9181};
9149 9182
9150static struct heredoc *heredoclist; /* list of here documents to read */
9151static int parsebackquote; /* nonzero if we are inside backquotes */
9152static int doprompt; /* if set, prompt the user */
9153static int needprompt; /* true if interactive and at start of line */
9154static int lasttoken; /* last token read */
9155 9183
9156static char *wordtext; /* text of last word returned by readtoken */
9157 9184
9158static struct nodelist *backquotelist; 9185static struct heredoc *heredoclist; /* list of here documents to read */
9159static union node *redirnode;
9160static struct heredoc *heredoc;
9161static int quoteflag; /* set if (part of) last token was quoted */
9162static int startlinno; /* line # where last token started */
9163 9186
9164 9187
9165static union node *list(int); 9188static union node *list(int);
9166static union node *andor(void); 9189static union node *andor(void);
9167static union node *pipeline(void); 9190static union node *pipeline(void);
9168static union node *command(void); 9191static union node *command(void);
9169static union node *simplecmd(union node **rpp, union node *redir); 9192static union node *simplecmd(void);
9193static union node *makename(void);
9170static void parsefname(void); 9194static void parsefname(void);
9171static void parseheredoc(void); 9195static void parseheredoc(void);
9172static char peektoken(void); 9196static char peektoken(void);
9173static int readtoken(void); 9197static int readtoken(void);
9174static int xxreadtoken(void); 9198static int xxreadtoken(void);
9175static int readtoken1(int, int, const char *, int); 9199static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9176static int noexpand(char *); 9200static int noexpand(char *);
9177static void synexpect(int) __attribute__ ((noreturn)); 9201static void synexpect(int) __attribute__((__noreturn__));
9178static void synerror(const char *) __attribute__ ((noreturn)); 9202static void synerror(const char *) __attribute__((__noreturn__));
9179static void setprompt(int); 9203static void setprompt(int);
9180 9204
9181 9205
9206static inline int
9207goodname(const char *p)
9208{
9209 return !*endofname(p);
9210}
9211
9212static inline int
9213isassignment(const char *p)
9214{
9215 const char *q = endofname(p);
9216 if (p == q)
9217 return 0;
9218 return *q == '=';
9219}
9220
9221
9182/* 9222/*
9183 * Read and parse a command. Returns NEOF on end of file. (NULL is a 9223 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9184 * valid parse tree indicating a blank line.) 9224 * valid parse tree indicating a blank line.)
9185 */ 9225 */
9186 9226
9187static union node *parsecmd(int interact) 9227union node *
9228parsecmd(int interact)
9188{ 9229{
9189 int t; 9230 int t;
9190 9231
9191 tokpushback = 0; 9232 tokpushback = 0;
9192 doprompt = interact; 9233 doprompt = interact;
9193 if (doprompt) 9234 if (doprompt)
9194 setprompt(1); 9235 setprompt(doprompt);
9195 else
9196 setprompt(0);
9197 needprompt = 0; 9236 needprompt = 0;
9198 t = readtoken(); 9237 t = readtoken();
9199 if (t == TEOF) 9238 if (t == TEOF)
@@ -9205,35 +9244,37 @@ static union node *parsecmd(int interact)
9205} 9244}
9206 9245
9207 9246
9208static union node *list(int nlflag) 9247static union node *
9248list(int nlflag)
9209{ 9249{
9210 union node *n1, *n2, *n3; 9250 union node *n1, *n2, *n3;
9211 int tok; 9251 int tok;
9212 9252
9213 checkkwd = 2; 9253 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9214 if (nlflag == 0 && peektoken()) 9254 if (nlflag == 2 && peektoken())
9215 return NULL; 9255 return NULL;
9216 n1 = NULL; 9256 n1 = NULL;
9217 for (;;) { 9257 for (;;) {
9218 n2 = andor(); 9258 n2 = andor();
9219 tok = readtoken(); 9259 tok = readtoken();
9220 if (tok == TBACKGND) { 9260 if (tok == TBACKGND) {
9221 if (n2->type == NCMD || n2->type == NPIPE) { 9261 if (n2->type == NPIPE) {
9222 n2->ncmd.backgnd = 1; 9262 n2->npipe.backgnd = 1;
9223 } else if (n2->type == NREDIR) {
9224 n2->type = NBACKGND;
9225 } else { 9263 } else {
9226 n3 = (union node *) stalloc(sizeof(struct nredir)); 9264 if (n2->type != NREDIR) {
9227 n3->type = NBACKGND; 9265 n3 = stalloc(sizeof(struct nredir));
9228 n3->nredir.n = n2; 9266 n3->nredir.n = n2;
9229 n3->nredir.redirect = NULL; 9267 n3->nredir.redirect = NULL;
9230 n2 = n3; 9268 n2 = n3;
9269 }
9270 n2->type = NBACKGND;
9231 } 9271 }
9232 } 9272 }
9233 if (n1 == NULL) { 9273 if (n1 == NULL) {
9234 n1 = n2; 9274 n1 = n2;
9235 } else { 9275 }
9236 n3 = (union node *) stalloc(sizeof(struct nbinary)); 9276 else {
9277 n3 = (union node *)stalloc(sizeof (struct nbinary));
9237 n3->type = NSEMI; 9278 n3->type = NSEMI;
9238 n3->nbinary.ch1 = n1; 9279 n3->nbinary.ch1 = n1;
9239 n3->nbinary.ch2 = n2; 9280 n3->nbinary.ch2 = n2;
@@ -9247,12 +9288,12 @@ static union node *list(int nlflag)
9247 case TNL: 9288 case TNL:
9248 if (tok == TNL) { 9289 if (tok == TNL) {
9249 parseheredoc(); 9290 parseheredoc();
9250 if (nlflag) 9291 if (nlflag == 1)
9251 return n1; 9292 return n1;
9252 } else { 9293 } else {
9253 tokpushback++; 9294 tokpushback++;
9254 } 9295 }
9255 checkkwd = 2; 9296 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9256 if (peektoken()) 9297 if (peektoken())
9257 return n1; 9298 return n1;
9258 break; 9299 break;
@@ -9260,10 +9301,10 @@ static union node *list(int nlflag)
9260 if (heredoclist) 9301 if (heredoclist)
9261 parseheredoc(); 9302 parseheredoc();
9262 else 9303 else
9263 pungetc(); /* push back EOF on input */ 9304 pungetc(); /* push back EOF on input */
9264 return n1; 9305 return n1;
9265 default: 9306 default:
9266 if (nlflag) 9307 if (nlflag == 1)
9267 synexpect(-1); 9308 synexpect(-1);
9268 tokpushback++; 9309 tokpushback++;
9269 return n1; 9310 return n1;
@@ -9273,12 +9314,12 @@ static union node *list(int nlflag)
9273 9314
9274 9315
9275 9316
9276static union node *andor() 9317static union node *
9318andor(void)
9277{ 9319{
9278 union node *n1, *n2, *n3; 9320 union node *n1, *n2, *n3;
9279 int t; 9321 int t;
9280 9322
9281 checkkwd = 1;
9282 n1 = pipeline(); 9323 n1 = pipeline();
9283 for (;;) { 9324 for (;;) {
9284 if ((t = readtoken()) == TAND) { 9325 if ((t = readtoken()) == TAND) {
@@ -9289,9 +9330,9 @@ static union node *andor()
9289 tokpushback++; 9330 tokpushback++;
9290 return n1; 9331 return n1;
9291 } 9332 }
9292 checkkwd = 2; 9333 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9293 n2 = pipeline(); 9334 n2 = pipeline();
9294 n3 = (union node *) stalloc(sizeof(struct nbinary)); 9335 n3 = (union node *)stalloc(sizeof (struct nbinary));
9295 n3->type = t; 9336 n3->type = t;
9296 n3->nbinary.ch1 = n1; 9337 n3->nbinary.ch1 = n1;
9297 n3->nbinary.ch2 = n2; 9338 n3->nbinary.ch2 = n2;
@@ -9301,7 +9342,8 @@ static union node *andor()
9301 9342
9302 9343
9303 9344
9304static union node *pipeline() 9345static union node *
9346pipeline(void)
9305{ 9347{
9306 union node *n1, *n2, *pipenode; 9348 union node *n1, *n2, *pipenode;
9307 struct nodelist *lp, *prev; 9349 struct nodelist *lp, *prev;
@@ -9311,21 +9353,21 @@ static union node *pipeline()
9311 TRACE(("pipeline: entered\n")); 9353 TRACE(("pipeline: entered\n"));
9312 if (readtoken() == TNOT) { 9354 if (readtoken() == TNOT) {
9313 negate = !negate; 9355 negate = !negate;
9314 checkkwd = 1; 9356 checkkwd = CHKKWD | CHKALIAS;
9315 } else 9357 } else
9316 tokpushback++; 9358 tokpushback++;
9317 n1 = command(); 9359 n1 = command();
9318 if (readtoken() == TPIPE) { 9360 if (readtoken() == TPIPE) {
9319 pipenode = (union node *) stalloc(sizeof(struct npipe)); 9361 pipenode = (union node *)stalloc(sizeof (struct npipe));
9320 pipenode->type = NPIPE; 9362 pipenode->type = NPIPE;
9321 pipenode->npipe.backgnd = 0; 9363 pipenode->npipe.backgnd = 0;
9322 lp = (struct nodelist *) stalloc(sizeof(struct nodelist)); 9364 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9323 pipenode->npipe.cmdlist = lp; 9365 pipenode->npipe.cmdlist = lp;
9324 lp->n = n1; 9366 lp->n = n1;
9325 do { 9367 do {
9326 prev = lp; 9368 prev = lp;
9327 lp = (struct nodelist *) stalloc(sizeof(struct nodelist)); 9369 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9328 checkkwd = 2; 9370 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9329 lp->n = command(); 9371 lp->n = command();
9330 prev->next = lp; 9372 prev->next = lp;
9331 } while (readtoken() == TPIPE); 9373 } while (readtoken() == TPIPE);
@@ -9334,7 +9376,7 @@ static union node *pipeline()
9334 } 9376 }
9335 tokpushback++; 9377 tokpushback++;
9336 if (negate) { 9378 if (negate) {
9337 n2 = (union node *) stalloc(sizeof(struct nnot)); 9379 n2 = (union node *)stalloc(sizeof (struct nnot));
9338 n2->type = NNOT; 9380 n2->type = NNOT;
9339 n2->nnot.com = n1; 9381 n2->nnot.com = n1;
9340 return n2; 9382 return n2;
@@ -9344,29 +9386,25 @@ static union node *pipeline()
9344 9386
9345 9387
9346 9388
9347static union node *command(void) 9389static union node *
9390command(void)
9348{ 9391{
9349 union node *n1, *n2; 9392 union node *n1, *n2;
9350 union node *ap, **app; 9393 union node *ap, **app;
9351 union node *cp, **cpp; 9394 union node *cp, **cpp;
9352 union node *redir, **rpp; 9395 union node *redir, **rpp;
9396 union node **rpp2;
9353 int t; 9397 int t;
9354 9398
9355 redir = NULL; 9399 redir = NULL;
9356 n1 = NULL; 9400 rpp2 = &redir;
9357 rpp = &redir;
9358
9359 /* Check for redirection which may precede command */
9360 while (readtoken() == TREDIR) {
9361 *rpp = n2 = redirnode;
9362 rpp = &n2->nfile.next;
9363 parsefname();
9364 }
9365 tokpushback++;
9366 9401
9367 switch (readtoken()) { 9402 switch (readtoken()) {
9403 default:
9404 synexpect(-1);
9405 /* NOTREACHED */
9368 case TIF: 9406 case TIF:
9369 n1 = (union node *) stalloc(sizeof(struct nif)); 9407 n1 = (union node *)stalloc(sizeof (struct nif));
9370 n1->type = NIF; 9408 n1->type = NIF;
9371 n1->nif.test = list(0); 9409 n1->nif.test = list(0);
9372 if (readtoken() != TTHEN) 9410 if (readtoken() != TTHEN)
@@ -9374,7 +9412,7 @@ static union node *command(void)
9374 n1->nif.ifpart = list(0); 9412 n1->nif.ifpart = list(0);
9375 n2 = n1; 9413 n2 = n1;
9376 while (readtoken() == TELIF) { 9414 while (readtoken() == TELIF) {
9377 n2->nif.elsepart = (union node *) stalloc(sizeof(struct nif)); 9415 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9378 n2 = n2->nif.elsepart; 9416 n2 = n2->nif.elsepart;
9379 n2->type = NIF; 9417 n2->type = NIF;
9380 n2->nif.test = list(0); 9418 n2->nif.test = list(0);
@@ -9388,38 +9426,33 @@ static union node *command(void)
9388 n2->nif.elsepart = NULL; 9426 n2->nif.elsepart = NULL;
9389 tokpushback++; 9427 tokpushback++;
9390 } 9428 }
9391 if (readtoken() != TFI) 9429 t = TFI;
9392 synexpect(TFI);
9393 checkkwd = 1;
9394 break; 9430 break;
9395 case TWHILE: 9431 case TWHILE:
9396 case TUNTIL:{ 9432 case TUNTIL: {
9397 int got; 9433 int got;
9398 n1 = (union node *) stalloc(sizeof(struct nbinary)); 9434 n1 = (union node *)stalloc(sizeof (struct nbinary));
9399 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL; 9435 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9400 n1->nbinary.ch1 = list(0); 9436 n1->nbinary.ch1 = list(0);
9401 if ((got = readtoken()) != TDO) { 9437 if ((got=readtoken()) != TDO) {
9402 TRACE(("expecting DO got %s %s\n", tokname(got), 9438TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9403 got == TWORD ? wordtext : ""));
9404 synexpect(TDO); 9439 synexpect(TDO);
9405 } 9440 }
9406 n1->nbinary.ch2 = list(0); 9441 n1->nbinary.ch2 = list(0);
9407 if (readtoken() != TDONE) 9442 t = TDONE;
9408 synexpect(TDONE);
9409 checkkwd = 1;
9410 break; 9443 break;
9411 } 9444 }
9412 case TFOR: 9445 case TFOR:
9413 if (readtoken() != TWORD || quoteflag || !goodname(wordtext)) 9446 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9414 synerror("Bad for loop variable"); 9447 synerror("Bad for loop variable");
9415 n1 = (union node *) stalloc(sizeof(struct nfor)); 9448 n1 = (union node *)stalloc(sizeof (struct nfor));
9416 n1->type = NFOR; 9449 n1->type = NFOR;
9417 n1->nfor.var = wordtext; 9450 n1->nfor.var = wordtext;
9418 checkkwd = 1; 9451 checkkwd = CHKKWD | CHKALIAS;
9419 if (readtoken() == TIN) { 9452 if (readtoken() == TIN) {
9420 app = &ap; 9453 app = &ap;
9421 while (readtoken() == TWORD) { 9454 while (readtoken() == TWORD) {
9422 n2 = (union node *) stalloc(sizeof(struct narg)); 9455 n2 = (union node *)stalloc(sizeof (struct narg));
9423 n2->type = NARG; 9456 n2->type = NARG;
9424 n2->narg.text = wordtext; 9457 n2->narg.text = wordtext;
9425 n2->narg.backquote = backquotelist; 9458 n2->narg.backquote = backquotelist;
@@ -9431,12 +9464,9 @@ static union node *command(void)
9431 if (lasttoken != TNL && lasttoken != TSEMI) 9464 if (lasttoken != TNL && lasttoken != TSEMI)
9432 synexpect(-1); 9465 synexpect(-1);
9433 } else { 9466 } else {
9434 static char argvars[5] = { CTLVAR, VSNORMAL | VSQUOTE, 9467 n2 = (union node *)stalloc(sizeof (struct narg));
9435 '@', '=', '\0'
9436 };
9437 n2 = (union node *) stalloc(sizeof(struct narg));
9438 n2->type = NARG; 9468 n2->type = NARG;
9439 n2->narg.text = argvars; 9469 n2->narg.text = (char *)dolatstr;
9440 n2->narg.backquote = NULL; 9470 n2->narg.backquote = NULL;
9441 n2->narg.next = NULL; 9471 n2->narg.next = NULL;
9442 n1->nfor.args = n2; 9472 n1->nfor.args = n2;
@@ -9447,43 +9477,43 @@ static union node *command(void)
9447 if (lasttoken != TNL && lasttoken != TSEMI) 9477 if (lasttoken != TNL && lasttoken != TSEMI)
9448 tokpushback++; 9478 tokpushback++;
9449 } 9479 }
9450 checkkwd = 2; 9480 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9451 if (readtoken() != TDO) 9481 if (readtoken() != TDO)
9452 synexpect(TDO); 9482 synexpect(TDO);
9453 n1->nfor.body = list(0); 9483 n1->nfor.body = list(0);
9454 if (readtoken() != TDONE) 9484 t = TDONE;
9455 synexpect(TDONE);
9456 checkkwd = 1;
9457 break; 9485 break;
9458 case TCASE: 9486 case TCASE:
9459 n1 = (union node *) stalloc(sizeof(struct ncase)); 9487 n1 = (union node *)stalloc(sizeof (struct ncase));
9460 n1->type = NCASE; 9488 n1->type = NCASE;
9461 if (readtoken() != TWORD) 9489 if (readtoken() != TWORD)
9462 synexpect(TWORD); 9490 synexpect(TWORD);
9463 n1->ncase.expr = n2 = (union node *) stalloc(sizeof(struct narg)); 9491 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9464 n2->type = NARG; 9492 n2->type = NARG;
9465 n2->narg.text = wordtext; 9493 n2->narg.text = wordtext;
9466 n2->narg.backquote = backquotelist; 9494 n2->narg.backquote = backquotelist;
9467 n2->narg.next = NULL; 9495 n2->narg.next = NULL;
9468 do { 9496 do {
9469 checkkwd = 1; 9497 checkkwd = CHKKWD | CHKALIAS;
9470 } while (readtoken() == TNL); 9498 } while (readtoken() == TNL);
9471 if (lasttoken != TIN) 9499 if (lasttoken != TIN)
9472 synerror("expecting \"in\""); 9500 synexpect(TIN);
9473 cpp = &n1->ncase.cases; 9501 cpp = &n1->ncase.cases;
9474 checkkwd = 2, readtoken(); 9502next_case:
9475 do { 9503 checkkwd = CHKNL | CHKKWD;
9504 t = readtoken();
9505 while(t != TESAC) {
9476 if (lasttoken == TLP) 9506 if (lasttoken == TLP)
9477 readtoken(); 9507 readtoken();
9478 *cpp = cp = (union node *) stalloc(sizeof(struct nclist)); 9508 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9479 cp->type = NCLIST; 9509 cp->type = NCLIST;
9480 app = &cp->nclist.pattern; 9510 app = &cp->nclist.pattern;
9481 for (;;) { 9511 for (;;) {
9482 *app = ap = (union node *) stalloc(sizeof(struct narg)); 9512 *app = ap = (union node *)stalloc(sizeof (struct narg));
9483 ap->type = NARG; 9513 ap->type = NARG;
9484 ap->narg.text = wordtext; 9514 ap->narg.text = wordtext;
9485 ap->narg.backquote = backquotelist; 9515 ap->narg.backquote = backquotelist;
9486 if (checkkwd = 2, readtoken() != TPIPE) 9516 if (readtoken() != TPIPE)
9487 break; 9517 break;
9488 app = &ap->narg.next; 9518 app = &ap->narg.next;
9489 readtoken(); 9519 readtoken();
@@ -9491,59 +9521,44 @@ static union node *command(void)
9491 ap->narg.next = NULL; 9521 ap->narg.next = NULL;
9492 if (lasttoken != TRP) 9522 if (lasttoken != TRP)
9493 synexpect(TRP); 9523 synexpect(TRP);
9494 cp->nclist.body = list(0); 9524 cp->nclist.body = list(2);
9525
9526 cpp = &cp->nclist.next;
9495 9527
9496 checkkwd = 2; 9528 checkkwd = CHKNL | CHKKWD;
9497 if ((t = readtoken()) != TESAC) { 9529 if ((t = readtoken()) != TESAC) {
9498 if (t != TENDCASE) 9530 if (t != TENDCASE)
9499 synexpect(TENDCASE); 9531 synexpect(TENDCASE);
9500 else 9532 else
9501 checkkwd = 2, readtoken(); 9533 goto next_case;
9502 } 9534 }
9503 cpp = &cp->nclist.next; 9535 }
9504 } while (lasttoken != TESAC);
9505 *cpp = NULL; 9536 *cpp = NULL;
9506 checkkwd = 1; 9537 goto redir;
9507 break;
9508 case TLP: 9538 case TLP:
9509 n1 = (union node *) stalloc(sizeof(struct nredir)); 9539 n1 = (union node *)stalloc(sizeof (struct nredir));
9510 n1->type = NSUBSHELL; 9540 n1->type = NSUBSHELL;
9511 n1->nredir.n = list(0); 9541 n1->nredir.n = list(0);
9512 n1->nredir.redirect = NULL; 9542 n1->nredir.redirect = NULL;
9513 if (readtoken() != TRP) 9543 t = TRP;
9514 synexpect(TRP);
9515 checkkwd = 1;
9516 break; 9544 break;
9517 case TBEGIN: 9545 case TBEGIN:
9518 n1 = list(0); 9546 n1 = list(0);
9519 if (readtoken() != TEND) 9547 t = TEND;
9520 synexpect(TEND);
9521 checkkwd = 1;
9522 break; 9548 break;
9523 /* Handle an empty command like other simple commands. */
9524 case TSEMI:
9525 case TAND:
9526 case TOR:
9527 case TNL:
9528 case TEOF:
9529 case TRP:
9530 case TBACKGND:
9531 /*
9532 * An empty command before a ; doesn't make much sense, and
9533 * should certainly be disallowed in the case of `if ;'.
9534 */
9535 if (!redir)
9536 synexpect(-1);
9537 case TWORD: 9549 case TWORD:
9550 case TREDIR:
9538 tokpushback++; 9551 tokpushback++;
9539 n1 = simplecmd(rpp, redir); 9552 return simplecmd();
9540 return n1;
9541 default:
9542 synexpect(-1);
9543 /* NOTREACHED */
9544 } 9553 }
9545 9554
9555 if (readtoken() != t)
9556 synexpect(t);
9557
9558redir:
9546 /* Now check for redirection which may follow command */ 9559 /* Now check for redirection which may follow command */
9560 checkkwd = CHKKWD | CHKALIAS;
9561 rpp = rpp2;
9547 while (readtoken() == TREDIR) { 9562 while (readtoken() == TREDIR) {
9548 *rpp = n2 = redirnode; 9563 *rpp = n2 = redirnode;
9549 rpp = &n2->nfile.next; 9564 rpp = &n2->nfile.next;
@@ -9553,7 +9568,7 @@ static union node *command(void)
9553 *rpp = NULL; 9568 *rpp = NULL;
9554 if (redir) { 9569 if (redir) {
9555 if (n1->type != NSUBSHELL) { 9570 if (n1->type != NSUBSHELL) {
9556 n2 = (union node *) stalloc(sizeof(struct nredir)); 9571 n2 = (union node *)stalloc(sizeof (struct nredir));
9557 n2->type = NREDIR; 9572 n2->type = NREDIR;
9558 n2->nredir.n = n1; 9573 n2->nredir.n = n1;
9559 n1 = n2; 9574 n1 = n2;
@@ -9565,56 +9580,65 @@ static union node *command(void)
9565} 9580}
9566 9581
9567 9582
9568static union node *simplecmd(union node **rpp, union node *redir) 9583static union node *
9569{ 9584simplecmd(void) {
9570 union node *args, **app; 9585 union node *args, **app;
9571 union node *n = NULL; 9586 union node *n = NULL;
9572 union node *vars, **vpp; 9587 union node *vars, **vpp;
9573 union node **orig_rpp; 9588 union node **rpp, *redir;
9589 int savecheckkwd;
9574 9590
9575 args = NULL; 9591 args = NULL;
9576 app = &args; 9592 app = &args;
9577 vars = NULL; 9593 vars = NULL;
9578 vpp = &vars; 9594 vpp = &vars;
9595 redir = NULL;
9596 rpp = &redir;
9579 9597
9580 /* If we don't have any redirections already, then we must reset 9598 savecheckkwd = CHKALIAS;
9581 rpp to be the address of the local redir variable. */
9582 if (redir == 0)
9583 rpp = &redir;
9584 /* We save the incoming value, because we need this for shell
9585 functions. There can not be a redirect or an argument between
9586 the function name and the open parenthesis. */
9587 orig_rpp = rpp;
9588
9589 checkalias = 2;
9590 for (;;) { 9599 for (;;) {
9600 checkkwd = savecheckkwd;
9591 switch (readtoken()) { 9601 switch (readtoken()) {
9592 case TWORD: 9602 case TWORD:
9593 case TASSIGN: 9603 n = (union node *)stalloc(sizeof (struct narg));
9594 n = (union node *) stalloc(sizeof(struct narg));
9595 n->type = NARG; 9604 n->type = NARG;
9596 n->narg.text = wordtext; 9605 n->narg.text = wordtext;
9597 n->narg.backquote = backquotelist; 9606 n->narg.backquote = backquotelist;
9598 if (lasttoken == TWORD) { 9607 if (savecheckkwd && isassignment(wordtext)) {
9599 *app = n;
9600 app = &n->narg.next;
9601 } else {
9602 *vpp = n; 9608 *vpp = n;
9603 vpp = &n->narg.next; 9609 vpp = &n->narg.next;
9610 } else {
9611 *app = n;
9612 app = &n->narg.next;
9613 savecheckkwd = 0;
9604 } 9614 }
9605 break; 9615 break;
9606 case TREDIR: 9616 case TREDIR:
9607 *rpp = n = redirnode; 9617 *rpp = n = redirnode;
9608 rpp = &n->nfile.next; 9618 rpp = &n->nfile.next;
9609 parsefname(); /* read name of redirection file */ 9619 parsefname(); /* read name of redirection file */
9610 break; 9620 break;
9611 case TLP: 9621 case TLP:
9612 if (args && app == &args->narg.next && !vars && rpp == orig_rpp) { 9622 if (
9623 args && app == &args->narg.next &&
9624 !vars && !redir
9625 ) {
9626 struct builtincmd *bcmd;
9627 const char *name;
9628
9613 /* We have a function */ 9629 /* We have a function */
9614 if (readtoken() != TRP) 9630 if (readtoken() != TRP)
9615 synexpect(TRP); 9631 synexpect(TRP);
9632 name = n->narg.text;
9633 if (
9634 !goodname(name) || (
9635 (bcmd = find_builtin(name)) &&
9636 IS_BUILTIN_SPECIAL(bcmd)
9637 )
9638 )
9639 synerror("Bad function name");
9616 n->type = NDEFUN; 9640 n->type = NDEFUN;
9617 checkkwd = 2; 9641 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9618 n->narg.next = command(); 9642 n->narg.next = command();
9619 return n; 9643 return n;
9620 } 9644 }
@@ -9624,24 +9648,24 @@ static union node *simplecmd(union node **rpp, union node *redir)
9624 goto out; 9648 goto out;
9625 } 9649 }
9626 } 9650 }
9627 out: 9651out:
9628 *app = NULL; 9652 *app = NULL;
9629 *vpp = NULL; 9653 *vpp = NULL;
9630 *rpp = NULL; 9654 *rpp = NULL;
9631 n = (union node *) stalloc(sizeof(struct ncmd)); 9655 n = (union node *)stalloc(sizeof (struct ncmd));
9632 n->type = NCMD; 9656 n->type = NCMD;
9633 n->ncmd.backgnd = 0;
9634 n->ncmd.args = args; 9657 n->ncmd.args = args;
9635 n->ncmd.assign = vars; 9658 n->ncmd.assign = vars;
9636 n->ncmd.redirect = redir; 9659 n->ncmd.redirect = redir;
9637 return n; 9660 return n;
9638} 9661}
9639 9662
9640static union node *makename(void) 9663static union node *
9664makename(void)
9641{ 9665{
9642 union node *n; 9666 union node *n;
9643 9667
9644 n = (union node *) stalloc(sizeof(struct narg)); 9668 n = (union node *)stalloc(sizeof (struct narg));
9645 n->type = NARG; 9669 n->type = NARG;
9646 n->narg.next = NULL; 9670 n->narg.next = NULL;
9647 n->narg.text = wordtext; 9671 n->narg.text = wordtext;
@@ -9649,7 +9673,7 @@ static union node *makename(void)
9649 return n; 9673 return n;
9650} 9674}
9651 9675
9652static void fixredir(union node *n, const char *text, int err) 9676void fixredir(union node *n, const char *text, int err)
9653{ 9677{
9654 TRACE(("Fix redir %s %d\n", text, err)); 9678 TRACE(("Fix redir %s %d\n", text, err));
9655 if (!err) 9679 if (!err)
@@ -9669,7 +9693,8 @@ static void fixredir(union node *n, const char *text, int err)
9669} 9693}
9670 9694
9671 9695
9672static void parsefname(void) 9696static void
9697parsefname(void)
9673{ 9698{
9674 union node *n = redirnode; 9699 union node *n = redirnode;
9675 9700
@@ -9683,12 +9708,7 @@ static void parsefname(void)
9683 if (quoteflag == 0) 9708 if (quoteflag == 0)
9684 n->type = NXHERE; 9709 n->type = NXHERE;
9685 TRACE(("Here document %d\n", n->type)); 9710 TRACE(("Here document %d\n", n->type));
9686 if (here->striptabs) { 9711 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9687 while (*wordtext == '\t')
9688 wordtext++;
9689 }
9690 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0
9691 || i > EOFMARKLEN)
9692 synerror("Illegal eof marker for << redirection"); 9712 synerror("Illegal eof marker for << redirection");
9693 rmescapes(wordtext); 9713 rmescapes(wordtext);
9694 here->eofmark = wordtext; 9714 here->eofmark = wordtext;
@@ -9696,7 +9716,7 @@ static void parsefname(void)
9696 if (heredoclist == NULL) 9716 if (heredoclist == NULL)
9697 heredoclist = here; 9717 heredoclist = here;
9698 else { 9718 else {
9699 for (p = heredoclist; p->next; p = p->next); 9719 for (p = heredoclist ; p->next ; p = p->next);
9700 p->next = here; 9720 p->next = here;
9701 } 9721 }
9702 } else if (n->type == NTOFD || n->type == NFROMFD) { 9722 } else if (n->type == NTOFD || n->type == NFROMFD) {
@@ -9711,30 +9731,33 @@ static void parsefname(void)
9711 * Input any here documents. 9731 * Input any here documents.
9712 */ 9732 */
9713 9733
9714static void parseheredoc() 9734static void
9735parseheredoc(void)
9715{ 9736{
9716 struct heredoc *here; 9737 struct heredoc *here;
9717 union node *n; 9738 union node *n;
9718 9739
9719 while (heredoclist) { 9740 here = heredoclist;
9720 here = heredoclist; 9741 heredoclist = 0;
9721 heredoclist = here->next; 9742
9743 while (here) {
9722 if (needprompt) { 9744 if (needprompt) {
9723 setprompt(2); 9745 setprompt(2);
9724 needprompt = 0; 9746 needprompt = 0;
9725 } 9747 }
9726 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX, 9748 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9727 here->eofmark, here->striptabs); 9749 here->eofmark, here->striptabs);
9728 n = (union node *) stalloc(sizeof(struct narg)); 9750 n = (union node *)stalloc(sizeof (struct narg));
9729 n->narg.type = NARG; 9751 n->narg.type = NARG;
9730 n->narg.next = NULL; 9752 n->narg.next = NULL;
9731 n->narg.text = wordtext; 9753 n->narg.text = wordtext;
9732 n->narg.backquote = backquotelist; 9754 n->narg.backquote = backquotelist;
9733 here->here->nhere.doc = n; 9755 here->here->nhere.doc = n;
9756 here = here->next;
9734 } 9757 }
9735} 9758}
9736 9759
9737static char peektoken() 9760static char peektoken(void)
9738{ 9761{
9739 int t; 9762 int t;
9740 9763
@@ -9743,83 +9766,65 @@ static char peektoken()
9743 return tokname_array[t][0]; 9766 return tokname_array[t][0];
9744} 9767}
9745 9768
9746static int readtoken() 9769static int
9770readtoken(void)
9747{ 9771{
9748 int t; 9772 int t;
9749
9750 int savecheckalias = checkalias;
9751
9752#ifdef CONFIG_ASH_ALIAS
9753 int savecheckkwd = checkkwd;
9754 struct alias *ap;
9755#endif
9756
9757#ifdef DEBUG 9773#ifdef DEBUG
9758 int alreadyseen = tokpushback; 9774 int alreadyseen = tokpushback;
9759#endif 9775#endif
9760 9776
9761#ifdef CONFIG_ASH_ALIAS 9777#ifdef CONFIG_ASH_ALIAS
9762 top: 9778top:
9763#endif 9779#endif
9764 9780
9765 t = xxreadtoken(); 9781 t = xxreadtoken();
9766 9782
9767 checkalias = savecheckalias; 9783 /*
9768 9784 * eat newlines
9769 if (checkkwd) { 9785 */
9770 /* 9786 if (checkkwd & CHKNL) {
9771 * eat newlines 9787 while (t == TNL) {
9772 */ 9788 parseheredoc();
9773 if (checkkwd == 2) { 9789 t = xxreadtoken();
9774 checkkwd = 0;
9775 while (t == TNL) {
9776 parseheredoc();
9777 t = xxreadtoken();
9778 }
9779 } 9790 }
9780 checkkwd = 0; 9791 }
9781 /*
9782 * check for keywords
9783 */
9784 if (t == TWORD && !quoteflag) {
9785 const char *const *pp;
9786 9792
9787 if ((pp = findkwd(wordtext))) { 9793 if (t != TWORD || quoteflag) {
9788 lasttoken = t = pp - tokname_array; 9794 goto out;
9789 TRACE(("keyword %s recognized\n", tokname(t)));
9790 goto out;
9791 }
9792 }
9793 } 9795 }
9794 9796
9797 /*
9798 * check for keywords
9799 */
9800 if (checkkwd & CHKKWD) {
9801 const char *const *pp;
9795 9802
9796 if (t != TWORD) { 9803 if ((pp = findkwd(wordtext))) {
9797 if (t != TREDIR) { 9804 lasttoken = t = pp - tokname_array;
9798 checkalias = 0; 9805 TRACE(("keyword %s recognized\n", tokname(t)));
9806 goto out;
9799 } 9807 }
9800 } else if (checkalias == 2 && isassignment(wordtext)) { 9808 }
9801 lasttoken = t = TASSIGN; 9809
9802 } else if (checkalias) { 9810 if (checkkwd & CHKALIAS) {
9803#ifdef CONFIG_ASH_ALIAS 9811#ifdef CONFIG_ASH_ALIAS
9804 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL 9812 struct alias *ap;
9805 && !(ap->flag & ALIASINUSE)) { 9813 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9806 if (*ap->val) { 9814 if (*ap->val) {
9807 pushstring(ap->val, strlen(ap->val), ap); 9815 pushstring(ap->val, ap);
9808 } 9816 }
9809 checkkwd = savecheckkwd;
9810 goto top; 9817 goto top;
9811 } 9818 }
9812#endif 9819#endif
9813 checkalias = 0;
9814 } 9820 }
9815 out: 9821out:
9822 checkkwd = 0;
9816#ifdef DEBUG 9823#ifdef DEBUG
9817 if (!alreadyseen) 9824 if (!alreadyseen)
9818 TRACE(("token %s %s\n", tokname(t), t == TWORD 9825 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9819 || t == TASSIGN ? wordtext : ""));
9820 else 9826 else
9821 TRACE(("reread token %s %s\n", tokname(t), t == TWORD 9827 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9822 || t == TASSIGN ? wordtext : ""));
9823#endif 9828#endif
9824 return (t); 9829 return (t);
9825} 9830}
@@ -9843,89 +9848,10 @@ static int readtoken()
9843 * have parseword (readtoken1?) handle both words and redirection.] 9848 * have parseword (readtoken1?) handle both words and redirection.]
9844 */ 9849 */
9845 9850
9846#define NEW_xxreadtoken
9847#ifdef NEW_xxreadtoken
9848
9849static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
9850static const char xxreadtoken_tokens[] = {
9851 TNL, TLP, TRP, /* only single occurrence allowed */
9852 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9853 TEOF, /* corresponds to trailing nul */
9854 TAND, TOR, TENDCASE, /* if double occurrence */
9855};
9856
9857#define xxreadtoken_doubles \
9858 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9859#define xxreadtoken_singles \
9860 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9861
9862static int xxreadtoken()
9863{
9864 int c;
9865
9866 if (tokpushback) {
9867 tokpushback = 0;
9868 return lasttoken;
9869 }
9870 if (needprompt) {
9871 setprompt(2);
9872 needprompt = 0;
9873 }
9874 startlinno = plinno;
9875 for (;;) { /* until token or start of word found */
9876 c = pgetc_macro();
9877
9878 if ((c != ' ') && (c != '\t')
9879#ifdef CONFIG_ASH_ALIAS
9880 && (c != PEOA)
9881#endif
9882 ) {
9883 if (c == '#') {
9884 while ((c = pgetc()) != '\n' && c != PEOF);
9885 pungetc();
9886 } else if (c == '\\') {
9887 if (pgetc() != '\n') {
9888 pungetc();
9889 goto READTOKEN1;
9890 }
9891 startlinno = ++plinno;
9892 setprompt(doprompt ? 2 : 0);
9893 } else {
9894 const char *p
9895 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9896
9897 if (c != PEOF) {
9898 if (c == '\n') {
9899 plinno++;
9900 needprompt = doprompt;
9901 }
9902
9903 p = strchr(xxreadtoken_chars, c);
9904 if (p == NULL) {
9905 READTOKEN1:
9906 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
9907 }
9908
9909 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
9910 if (pgetc() == *p) { /* double occurrence? */
9911 p += xxreadtoken_doubles + 1;
9912 } else {
9913 pungetc();
9914 }
9915 }
9916 }
9917
9918 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
9919 }
9920 }
9921 }
9922}
9923
9924
9925#else
9926#define RETURN(token) return lasttoken = token 9851#define RETURN(token) return lasttoken = token
9927 9852
9928static int xxreadtoken() 9853static int
9854xxreadtoken(void)
9929{ 9855{
9930 int c; 9856 int c;
9931 9857
@@ -9938,11 +9864,10 @@ static int xxreadtoken()
9938 needprompt = 0; 9864 needprompt = 0;
9939 } 9865 }
9940 startlinno = plinno; 9866 startlinno = plinno;
9941 for (;;) { /* until token or start of word found */ 9867 for (;;) { /* until token or start of word found */
9942 c = pgetc_macro(); 9868 c = pgetc_macro();
9943 switch (c) { 9869 switch (c) {
9944 case ' ': 9870 case ' ': case '\t':
9945 case '\t':
9946#ifdef CONFIG_ASH_ALIAS 9871#ifdef CONFIG_ASH_ALIAS
9947 case PEOA: 9872 case PEOA:
9948#endif 9873#endif
@@ -9956,8 +9881,6 @@ static int xxreadtoken()
9956 startlinno = ++plinno; 9881 startlinno = ++plinno;
9957 if (doprompt) 9882 if (doprompt)
9958 setprompt(2); 9883 setprompt(2);
9959 else
9960 setprompt(0);
9961 continue; 9884 continue;
9962 } 9885 }
9963 pungetc(); 9886 pungetc();
@@ -9991,11 +9914,12 @@ static int xxreadtoken()
9991 goto breakloop; 9914 goto breakloop;
9992 } 9915 }
9993 } 9916 }
9994 breakloop: 9917breakloop:
9995 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 9918 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
9996#undef RETURN 9919#undef RETURN
9997} 9920}
9998#endif 9921
9922
9999 9923
10000/* 9924/*
10001 * If eofmark is NULL, read a word or a redirection symbol. If eofmark 9925 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
@@ -10017,7 +9941,7 @@ static int xxreadtoken()
10017#define PARSEARITH() {goto parsearith; parsearith_return:;} 9941#define PARSEARITH() {goto parsearith; parsearith_return:;}
10018 9942
10019static int 9943static int
10020readtoken1(int firstc, int syntax, const char *eofmark, int striptabs) 9944readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10021{ 9945{
10022 int c = firstc; 9946 int c = firstc;
10023 char *out; 9947 char *out;
@@ -10026,13 +9950,12 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10026 struct nodelist *bqlist; 9950 struct nodelist *bqlist;
10027 int quotef; 9951 int quotef;
10028 int dblquote; 9952 int dblquote;
10029 int varnest; /* levels of variables expansion */ 9953 int varnest; /* levels of variables expansion */
10030 int arinest; /* levels of arithmetic expansion */ 9954 int arinest; /* levels of arithmetic expansion */
10031 int parenlevel; /* levels of parens in arithmetic */ 9955 int parenlevel; /* levels of parens in arithmetic */
10032 int dqvarnest; /* levels of variables expansion within double quotes */ 9956 int dqvarnest; /* levels of variables expansion within double quotes */
10033 int oldstyle; 9957 int oldstyle;
10034 int prevsyntax; /* syntax before arithmetic */ 9958 int prevsyntax; /* syntax before arithmetic */
10035
10036#if __GNUC__ 9959#if __GNUC__
10037 /* Avoid longjmp clobbering */ 9960 /* Avoid longjmp clobbering */
10038 (void) &out; 9961 (void) &out;
@@ -10059,81 +9982,83 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10059 dqvarnest = 0; 9982 dqvarnest = 0;
10060 9983
10061 STARTSTACKSTR(out); 9984 STARTSTACKSTR(out);
10062 loop:{ /* for each line, until end of word */ 9985 loop: { /* for each line, until end of word */
10063 CHECKEND(); /* set c to PEOF if at end of here document */ 9986 CHECKEND(); /* set c to PEOF if at end of here document */
10064 for (;;) { /* until end of line or end of word */ 9987 for (;;) { /* until end of line or end of word */
10065 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 9988 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10066 switch (SIT(c, syntax)) { 9989 switch(SIT(c, syntax)) {
10067 case CNL: /* '\n' */ 9990 case CNL: /* '\n' */
10068 if (syntax == BASESYNTAX) 9991 if (syntax == BASESYNTAX)
10069 goto endword; /* exit outer loop */ 9992 goto endword; /* exit outer loop */
10070 USTPUTC(c, out); 9993 USTPUTC(c, out);
10071 plinno++; 9994 plinno++;
10072 if (doprompt) 9995 if (doprompt)
10073 setprompt(2); 9996 setprompt(2);
10074 else
10075 setprompt(0);
10076 c = pgetc(); 9997 c = pgetc();
10077 goto loop; /* continue outer loop */ 9998 goto loop; /* continue outer loop */
10078 case CWORD: 9999 case CWORD:
10079 USTPUTC(c, out); 10000 USTPUTC(c, out);
10080 break; 10001 break;
10081 case CCTL: 10002 case CCTL:
10082 if ((eofmark == NULL || dblquote) && dqvarnest == 0) 10003 if (eofmark == NULL || dblquote)
10083 USTPUTC(CTLESC, out); 10004 USTPUTC(CTLESC, out);
10084 USTPUTC(c, out); 10005 USTPUTC(c, out);
10085 break; 10006 break;
10086 case CBACK: /* backslash */ 10007 case CBACK: /* backslash */
10087 c = pgetc2(); 10008 c = pgetc2();
10088 if (c == PEOF) { 10009 if (c == PEOF) {
10010 USTPUTC(CTLESC, out);
10089 USTPUTC('\\', out); 10011 USTPUTC('\\', out);
10090 pungetc(); 10012 pungetc();
10091 } else if (c == '\n') { 10013 } else if (c == '\n') {
10092 if (doprompt) 10014 if (doprompt)
10093 setprompt(2); 10015 setprompt(2);
10094 else
10095 setprompt(0);
10096 } else { 10016 } else {
10097 if (dblquote && c != '\\' && c != '`' && c != '$' 10017 if (
10098 && (c != '"' || eofmark != NULL)) 10018 dblquote &&
10019 c != '\\' && c != '`' &&
10020 c != '$' && (
10021 c != '"' ||
10022 eofmark != NULL
10023 )
10024 ) {
10025 USTPUTC(CTLESC, out);
10099 USTPUTC('\\', out); 10026 USTPUTC('\\', out);
10027 }
10100 if (SIT(c, SQSYNTAX) == CCTL) 10028 if (SIT(c, SQSYNTAX) == CCTL)
10101 USTPUTC(CTLESC, out); 10029 USTPUTC(CTLESC, out);
10102 else if (eofmark == NULL)
10103 USTPUTC(CTLQUOTEMARK, out);
10104 USTPUTC(c, out); 10030 USTPUTC(c, out);
10105 quotef++; 10031 quotef++;
10106 } 10032 }
10107 break; 10033 break;
10108 case CSQUOTE: 10034 case CSQUOTE:
10109 if (eofmark == NULL)
10110 USTPUTC(CTLQUOTEMARK, out);
10111 syntax = SQSYNTAX; 10035 syntax = SQSYNTAX;
10036quotemark:
10037 if (eofmark == NULL) {
10038 USTPUTC(CTLQUOTEMARK, out);
10039 }
10112 break; 10040 break;
10113 case CDQUOTE: 10041 case CDQUOTE:
10114 if (eofmark == NULL)
10115 USTPUTC(CTLQUOTEMARK, out);
10116 syntax = DQSYNTAX; 10042 syntax = DQSYNTAX;
10117 dblquote = 1; 10043 dblquote = 1;
10118 break; 10044 goto quotemark;
10119 case CENDQUOTE: 10045 case CENDQUOTE:
10120 if (eofmark != NULL && arinest == 0 && varnest == 0) { 10046 if (eofmark != NULL && arinest == 0 &&
10047 varnest == 0) {
10121 USTPUTC(c, out); 10048 USTPUTC(c, out);
10122 } else { 10049 } else {
10123 if (arinest) { 10050 if (dqvarnest == 0) {
10124 syntax = ARISYNTAX;
10125 dblquote = 0;
10126 } else if (eofmark == NULL && dqvarnest == 0) {
10127 syntax = BASESYNTAX; 10051 syntax = BASESYNTAX;
10128 dblquote = 0; 10052 dblquote = 0;
10129 } 10053 }
10130 quotef++; 10054 quotef++;
10055 goto quotemark;
10131 } 10056 }
10132 break; 10057 break;
10133 case CVAR: /* '$' */ 10058 case CVAR: /* '$' */
10134 PARSESUB(); /* parse substitution */ 10059 PARSESUB(); /* parse substitution */
10135 break; 10060 break;
10136 case CENDVAR: /* '}' */ 10061 case CENDVAR: /* '}' */
10137 if (varnest > 0) { 10062 if (varnest > 0) {
10138 varnest--; 10063 varnest--;
10139 if (dqvarnest > 0) { 10064 if (dqvarnest > 0) {
@@ -10145,11 +10070,11 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10145 } 10070 }
10146 break; 10071 break;
10147#ifdef CONFIG_ASH_MATH_SUPPORT 10072#ifdef CONFIG_ASH_MATH_SUPPORT
10148 case CLP: /* '(' in arithmetic */ 10073 case CLP: /* '(' in arithmetic */
10149 parenlevel++; 10074 parenlevel++;
10150 USTPUTC(c, out); 10075 USTPUTC(c, out);
10151 break; 10076 break;
10152 case CRP: /* ')' in arithmetic */ 10077 case CRP: /* ')' in arithmetic */
10153 if (parenlevel > 0) { 10078 if (parenlevel > 0) {
10154 USTPUTC(c, out); 10079 USTPUTC(c, out);
10155 --parenlevel; 10080 --parenlevel;
@@ -10175,16 +10100,16 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10175 } 10100 }
10176 break; 10101 break;
10177#endif 10102#endif
10178 case CBQUOTE: /* '`' */ 10103 case CBQUOTE: /* '`' */
10179 PARSEBACKQOLD(); 10104 PARSEBACKQOLD();
10180 break; 10105 break;
10181 case CENDFILE: 10106 case CENDFILE:
10182 goto endword; /* exit outer loop */ 10107 goto endword; /* exit outer loop */
10183 case CIGN: 10108 case CIGN:
10184 break; 10109 break;
10185 default: 10110 default:
10186 if (varnest == 0) 10111 if (varnest == 0)
10187 goto endword; /* exit outer loop */ 10112 goto endword; /* exit outer loop */
10188#ifdef CONFIG_ASH_ALIAS 10113#ifdef CONFIG_ASH_ALIAS
10189 if (c != PEOA) 10114 if (c != PEOA)
10190#endif 10115#endif
@@ -10194,21 +10119,26 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10194 c = pgetc_macro(); 10119 c = pgetc_macro();
10195 } 10120 }
10196 } 10121 }
10197 endword: 10122endword:
10123#ifdef CONFIG_ASH_MATH_SUPPORT
10198 if (syntax == ARISYNTAX) 10124 if (syntax == ARISYNTAX)
10199 synerror("Missing '))'"); 10125 synerror("Missing '))'");
10200 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL) 10126#endif
10127 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10201 synerror("Unterminated quoted string"); 10128 synerror("Unterminated quoted string");
10202 if (varnest != 0) { 10129 if (varnest != 0) {
10203 startlinno = plinno; 10130 startlinno = plinno;
10131 /* { */
10204 synerror("Missing '}'"); 10132 synerror("Missing '}'");
10205 } 10133 }
10206 USTPUTC('\0', out); 10134 USTPUTC('\0', out);
10207 len = out - stackblock(); 10135 len = out - (char *)stackblock();
10208 out = stackblock(); 10136 out = stackblock();
10209 if (eofmark == NULL) { 10137 if (eofmark == NULL) {
10210 if ((c == '>' || c == '<') 10138 if ((c == '>' || c == '<')
10211 && quotef == 0 && len <= 2 && (*out == '\0' || is_digit(*out))) { 10139 && quotef == 0
10140 && len <= 2
10141 && (*out == '\0' || is_digit(*out))) {
10212 PARSEREDIR(); 10142 PARSEREDIR();
10213 return lasttoken = TREDIR; 10143 return lasttoken = TREDIR;
10214 } else { 10144 } else {
@@ -10230,36 +10160,36 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10230 * we are at the end of the here document, this routine sets the c to PEOF. 10160 * we are at the end of the here document, this routine sets the c to PEOF.
10231 */ 10161 */
10232 10162
10233 checkend:{ 10163checkend: {
10234 if (eofmark) { 10164 if (eofmark) {
10235#ifdef CONFIG_ASH_ALIAS 10165#ifdef CONFIG_ASH_ALIAS
10236 if (c == PEOA) { 10166 if (c == PEOA) {
10237 c = pgetc2(); 10167 c = pgetc2();
10238 } 10168 }
10239#endif 10169#endif
10240 if (striptabs) { 10170 if (striptabs) {
10241 while (c == '\t') { 10171 while (c == '\t') {
10242 c = pgetc2(); 10172 c = pgetc2();
10243 }
10244 } 10173 }
10245 if (c == *eofmark) { 10174 }
10246 if (pfgets(line, sizeof line) != NULL) { 10175 if (c == *eofmark) {
10247 const char *p, *q; 10176 if (pfgets(line, sizeof line) != NULL) {
10248 10177 char *p, *q;
10249 p = line; 10178
10250 for (q = eofmark + 1; *q && *p == *q; p++, q++); 10179 p = line;
10251 if (*p == '\n' && *q == '\0') { 10180 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10252 c = PEOF; 10181 if (*p == '\n' && *q == '\0') {
10253 plinno++; 10182 c = PEOF;
10254 needprompt = doprompt; 10183 plinno++;
10255 } else { 10184 needprompt = doprompt;
10256 pushstring(line, strlen(line), NULL); 10185 } else {
10257 } 10186 pushstring(line, NULL);
10258 } 10187 }
10259 } 10188 }
10260 } 10189 }
10261 goto checkend_return;
10262 } 10190 }
10191 goto checkend_return;
10192}
10263 10193
10264 10194
10265/* 10195/*
@@ -10268,62 +10198,62 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10268 * first character of the redirection operator. 10198 * first character of the redirection operator.
10269 */ 10199 */
10270 10200
10271 parseredir:{ 10201parseredir: {
10272 char fd = *out; 10202 char fd = *out;
10273 union node *np; 10203 union node *np;
10274 10204
10275 np = (union node *) stalloc(sizeof(struct nfile)); 10205 np = (union node *)stalloc(sizeof (struct nfile));
10276 if (c == '>') { 10206 if (c == '>') {
10277 np->nfile.fd = 1; 10207 np->nfile.fd = 1;
10278 c = pgetc(); 10208 c = pgetc();
10279 if (c == '>') 10209 if (c == '>')
10280 np->type = NAPPEND; 10210 np->type = NAPPEND;
10281 else if (c == '&') 10211 else if (c == '|')
10282 np->type = NTOFD; 10212 np->type = NCLOBBER;
10283 else if (c == '|') 10213 else if (c == '&')
10284 np->type = NTOOV; 10214 np->type = NTOFD;
10285 else { 10215 else {
10286 np->type = NTO; 10216 np->type = NTO;
10217 pungetc();
10218 }
10219 } else { /* c == '<' */
10220 np->nfile.fd = 0;
10221 switch (c = pgetc()) {
10222 case '<':
10223 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10224 np = (union node *)stalloc(sizeof (struct nhere));
10225 np->nfile.fd = 0;
10226 }
10227 np->type = NHERE;
10228 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10229 heredoc->here = np;
10230 if ((c = pgetc()) == '-') {
10231 heredoc->striptabs = 1;
10232 } else {
10233 heredoc->striptabs = 0;
10287 pungetc(); 10234 pungetc();
10288 } 10235 }
10289 } else { /* c == '<' */ 10236 break;
10290 np->nfile.fd = 0;
10291 switch (c = pgetc()) {
10292 case '<':
10293 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10294 np = (union node *) stalloc(sizeof(struct nhere));
10295 np->nfile.fd = 0;
10296 }
10297 np->type = NHERE;
10298 heredoc = (struct heredoc *) stalloc(sizeof(struct heredoc));
10299 heredoc->here = np;
10300 if ((c = pgetc()) == '-') {
10301 heredoc->striptabs = 1;
10302 } else {
10303 heredoc->striptabs = 0;
10304 pungetc();
10305 }
10306 break;
10307 10237
10308 case '&': 10238 case '&':
10309 np->type = NFROMFD; 10239 np->type = NFROMFD;
10310 break; 10240 break;
10311 10241
10312 case '>': 10242 case '>':
10313 np->type = NFROMTO; 10243 np->type = NFROMTO;
10314 break; 10244 break;
10315 10245
10316 default: 10246 default:
10317 np->type = NFROM; 10247 np->type = NFROM;
10318 pungetc(); 10248 pungetc();
10319 break; 10249 break;
10320 }
10321 } 10250 }
10322 if (fd != '\0')
10323 np->nfile.fd = digit_val(fd);
10324 redirnode = np;
10325 goto parseredir_return;
10326 } 10251 }
10252 if (fd != '\0')
10253 np->nfile.fd = digit_val(fd);
10254 redirnode = np;
10255 goto parseredir_return;
10256}
10327 10257
10328 10258
10329/* 10259/*
@@ -10331,76 +10261,85 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10331 * and nothing else. 10261 * and nothing else.
10332 */ 10262 */
10333 10263
10334 parsesub:{ 10264parsesub: {
10335 int subtype; 10265 int subtype;
10336 int typeloc; 10266 int typeloc;
10337 int flags; 10267 int flags;
10338 char *p; 10268 char *p;
10339 static const char types[] = "}-+?="; 10269 static const char types[] = "}-+?=";
10340 10270
10341 c = pgetc(); 10271 c = pgetc();
10342 if (c <= PEOA || 10272 if (
10343 (c != '(' && c != '{' && !is_name(c) && !is_special(c)) 10273 c <= PEOA_OR_PEOF ||
10344 ) { 10274 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10345 USTPUTC('$', out); 10275 ) {
10276 USTPUTC('$', out);
10277 pungetc();
10278 } else if (c == '(') { /* $(command) or $((arith)) */
10279 if (pgetc() == '(') {
10280#ifdef CONFIG_ASH_MATH_SUPPORT
10281 PARSEARITH();
10282#else
10283 synerror("We unsupport $((arith))");
10284#endif
10285 } else {
10346 pungetc(); 10286 pungetc();
10347 } else if (c == '(') { /* $(command) or $((arith)) */ 10287 PARSEBACKQNEW();
10348 if (pgetc() == '(') { 10288 }
10349 PARSEARITH(); 10289 } else {
10350 } else { 10290 USTPUTC(CTLVAR, out);
10351 pungetc(); 10291 typeloc = out - (char *)stackblock();
10352 PARSEBACKQNEW(); 10292 USTPUTC(VSNORMAL, out);
10293 subtype = VSNORMAL;
10294 if (c == '{') {
10295 c = pgetc();
10296 if (c == '#') {
10297 if ((c = pgetc()) == '}')
10298 c = '#';
10299 else
10300 subtype = VSLENGTH;
10353 } 10301 }
10354 } else { 10302 else
10355 USTPUTC(CTLVAR, out); 10303 subtype = 0;
10356 typeloc = out - stackblock(); 10304 }
10357 USTPUTC(VSNORMAL, out); 10305 if (c > PEOA_OR_PEOF && is_name(c)) {
10358 subtype = VSNORMAL; 10306 do {
10359 if (c == '{') { 10307 STPUTC(c, out);
10360 c = pgetc(); 10308 c = pgetc();
10361 if (c == '#') { 10309 } while (c > PEOA_OR_PEOF && is_in_name(c));
10362 if ((c = pgetc()) == '}') 10310 } else if (is_digit(c)) {
10363 c = '#'; 10311 do {
10364 else 10312 STPUTC(c, out);
10365 subtype = VSLENGTH;
10366 } else
10367 subtype = 0;
10368 }
10369 if (c > PEOA && is_name(c)) {
10370 do {
10371 STPUTC(c, out);
10372 c = pgetc();
10373 } while (c > PEOA && is_in_name(c));
10374 } else if (is_digit(c)) {
10375 do {
10376 USTPUTC(c, out);
10377 c = pgetc();
10378 } while (is_digit(c));
10379 } else if (is_special(c)) {
10380 USTPUTC(c, out);
10381 c = pgetc(); 10313 c = pgetc();
10382 } else 10314 } while (is_digit(c));
10383 badsub:synerror("Bad substitution"); 10315 }
10384 10316 else if (is_special(c)) {
10385 STPUTC('=', out); 10317 USTPUTC(c, out);
10386 flags = 0; 10318 c = pgetc();
10387 if (subtype == 0) { 10319 }
10388 switch (c) { 10320 else
10389 case ':': 10321badsub: synerror("Bad substitution");
10390 flags = VSNUL; 10322
10391 c = pgetc(); 10323 STPUTC('=', out);
10392 /*FALLTHROUGH*/ default: 10324 flags = 0;
10393 p = strchr(types, c); 10325 if (subtype == 0) {
10394 if (p == NULL) 10326 switch (c) {
10395 goto badsub; 10327 case ':':
10396 subtype = p - types + VSNORMAL; 10328 flags = VSNUL;
10397 break; 10329 c = pgetc();
10398 case '%': 10330 /*FALLTHROUGH*/
10399 case '#': 10331 default:
10332 p = strchr(types, c);
10333 if (p == NULL)
10334 goto badsub;
10335 subtype = p - types + VSNORMAL;
10336 break;
10337 case '%':
10338 case '#':
10400 { 10339 {
10401 int cc = c; 10340 int cc = c;
10402 10341 subtype = c == '#' ? VSTRIMLEFT :
10403 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT; 10342 VSTRIMRIGHT;
10404 c = pgetc(); 10343 c = pgetc();
10405 if (c == cc) 10344 if (c == cc)
10406 subtype++; 10345 subtype++;
@@ -10408,22 +10347,22 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10408 pungetc(); 10347 pungetc();
10409 break; 10348 break;
10410 } 10349 }
10411 }
10412 } else {
10413 pungetc();
10414 } 10350 }
10415 if (dblquote || arinest) 10351 } else {
10416 flags |= VSQUOTE; 10352 pungetc();
10417 *(stackblock() + typeloc) = subtype | flags; 10353 }
10418 if (subtype != VSNORMAL) { 10354 if (dblquote || arinest)
10419 varnest++; 10355 flags |= VSQUOTE;
10420 if (dblquote) { 10356 *((char *)stackblock() + typeloc) = subtype | flags;
10421 dqvarnest++; 10357 if (subtype != VSNORMAL) {
10422 } 10358 varnest++;
10359 if (dblquote || arinest) {
10360 dqvarnest++;
10423 } 10361 }
10424 } 10362 }
10425 goto parsesub_return;
10426 } 10363 }
10364 goto parsesub_return;
10365}
10427 10366
10428 10367
10429/* 10368/*
@@ -10433,182 +10372,183 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10433 * characters on the top of the stack which must be preserved. 10372 * characters on the top of the stack which must be preserved.
10434 */ 10373 */
10435 10374
10436 parsebackq:{ 10375parsebackq: {
10437 struct nodelist **nlpp; 10376 struct nodelist **nlpp;
10438 int savepbq; 10377 int savepbq;
10439 union node *n; 10378 union node *n;
10440 char *volatile str; 10379 char *volatile str;
10441 struct jmploc jmploc; 10380 struct jmploc jmploc;
10442 struct jmploc *volatile savehandler; 10381 struct jmploc *volatile savehandler;
10443 int savelen; 10382 size_t savelen;
10444 int saveprompt; 10383 int saveprompt;
10445
10446#ifdef __GNUC__ 10384#ifdef __GNUC__
10447 (void) &saveprompt; 10385 (void) &saveprompt;
10448#endif 10386#endif
10449 10387
10450 savepbq = parsebackquote; 10388 savepbq = parsebackquote;
10451 if (setjmp(jmploc.loc)) { 10389 if (setjmp(jmploc.loc)) {
10452 free(str); 10390 if (str)
10453 parsebackquote = 0; 10391 ckfree(str);
10454 handler = savehandler; 10392 parsebackquote = 0;
10455 longjmp(handler->loc, 1); 10393 handler = savehandler;
10456 } 10394 longjmp(handler->loc, 1);
10457 INTOFF; 10395 }
10458 str = NULL; 10396 INTOFF;
10459 savelen = out - stackblock(); 10397 str = NULL;
10460 if (savelen > 0) { 10398 savelen = out - (char *)stackblock();
10461 str = xmalloc(savelen); 10399 if (savelen > 0) {
10462 memcpy(str, stackblock(), savelen); 10400 str = ckmalloc(savelen);
10463 } 10401 memcpy(str, stackblock(), savelen);
10464 savehandler = handler; 10402 }
10465 handler = &jmploc; 10403 savehandler = handler;
10466 INTON; 10404 handler = &jmploc;
10467 if (oldstyle) { 10405 INTON;
10468 /* We must read until the closing backquote, giving special 10406 if (oldstyle) {
10469 treatment to some slashes, and then push the string and 10407 /* We must read until the closing backquote, giving special
10470 reread it as input, interpreting it normally. */ 10408 treatment to some slashes, and then push the string and
10471 char *pout; 10409 reread it as input, interpreting it normally. */
10472 int pc; 10410 char *pout;
10473 int psavelen; 10411 int pc;
10474 char *pstr; 10412 size_t psavelen;
10413 char *pstr;
10475 10414
10476 10415
10477 STARTSTACKSTR(pout); 10416 STARTSTACKSTR(pout);
10478 for (;;) { 10417 for (;;) {
10479 if (needprompt) { 10418 if (needprompt) {
10480 setprompt(2); 10419 setprompt(2);
10481 needprompt = 0; 10420 needprompt = 0;
10421 }
10422 switch (pc = pgetc()) {
10423 case '`':
10424 goto done;
10425
10426 case '\\':
10427 if ((pc = pgetc()) == '\n') {
10428 plinno++;
10429 if (doprompt)
10430 setprompt(2);
10431 /*
10432 * If eating a newline, avoid putting
10433 * the newline into the new character
10434 * stream (via the STPUTC after the
10435 * switch).
10436 */
10437 continue;
10482 } 10438 }
10483 switch (pc = pgetc()) { 10439 if (pc != '\\' && pc != '`' && pc != '$'
10484 case '`': 10440 && (!dblquote || pc != '"'))
10485 goto done; 10441 STPUTC('\\', pout);
10486 10442 if (pc > PEOA_OR_PEOF) {
10487 case '\\': 10443 break;
10488 if ((pc = pgetc()) == '\n') { 10444 }
10489 plinno++; 10445 /* fall through */
10490 if (doprompt)
10491 setprompt(2);
10492 else
10493 setprompt(0);
10494 /*
10495 * If eating a newline, avoid putting
10496 * the newline into the new character
10497 * stream (via the STPUTC after the
10498 * switch).
10499 */
10500 continue;
10501 }
10502 if (pc != '\\' && pc != '`' && pc != '$'
10503 && (!dblquote || pc != '"'))
10504 STPUTC('\\', pout);
10505 if (pc > PEOA) {
10506 break;
10507 }
10508 /* fall through */
10509 10446
10510 case PEOF: 10447 case PEOF:
10511#ifdef CONFIG_ASH_ALIAS 10448#ifdef CONFIG_ASH_ALIAS
10512 case PEOA: 10449 case PEOA:
10513#endif 10450#endif
10514 startlinno = plinno; 10451 startlinno = plinno;
10515 synerror("EOF in backquote substitution"); 10452 synerror("EOF in backquote substitution");
10516 10453
10517 case '\n': 10454 case '\n':
10518 plinno++; 10455 plinno++;
10519 needprompt = doprompt; 10456 needprompt = doprompt;
10520 break; 10457 break;
10521 10458
10522 default: 10459 default:
10523 break; 10460 break;
10524 }
10525 STPUTC(pc, pout);
10526 }
10527 done:
10528 STPUTC('\0', pout);
10529 psavelen = pout - stackblock();
10530 if (psavelen > 0) {
10531 pstr = grabstackstr(pout);
10532 setinputstring(pstr);
10533 } 10461 }
10462 STPUTC(pc, pout);
10534 } 10463 }
10535 nlpp = &bqlist; 10464done:
10536 while (*nlpp) 10465 STPUTC('\0', pout);
10537 nlpp = &(*nlpp)->next; 10466 psavelen = pout - (char *)stackblock();
10538 *nlpp = (struct nodelist *) stalloc(sizeof(struct nodelist)); 10467 if (psavelen > 0) {
10539 (*nlpp)->next = NULL; 10468 pstr = grabstackstr(pout);
10540 parsebackquote = oldstyle; 10469 setinputstring(pstr);
10541
10542 if (oldstyle) {
10543 saveprompt = doprompt;
10544 doprompt = 0;
10545 } 10470 }
10471 }
10472 nlpp = &bqlist;
10473 while (*nlpp)
10474 nlpp = &(*nlpp)->next;
10475 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10476 (*nlpp)->next = NULL;
10477 parsebackquote = oldstyle;
10546 10478
10547 n = list(0); 10479 if (oldstyle) {
10480 saveprompt = doprompt;
10481 doprompt = 0;
10482 }
10548 10483
10549 if (oldstyle) 10484 n = list(2);
10550 doprompt = saveprompt;
10551 else {
10552 if (readtoken() != TRP)
10553 synexpect(TRP);
10554 }
10555 10485
10556 (*nlpp)->n = n; 10486 if (oldstyle)
10557 if (oldstyle) { 10487 doprompt = saveprompt;
10558 /* 10488 else {
10559 * Start reading from old file again, ignoring any pushed back 10489 if (readtoken() != TRP)
10560 * tokens left from the backquote parsing 10490 synexpect(TRP);
10561 */
10562 popfile();
10563 tokpushback = 0;
10564 }
10565 while (stackblocksize() <= savelen)
10566 growstackblock();
10567 STARTSTACKSTR(out);
10568 if (str) {
10569 memcpy(out, str, savelen);
10570 STADJUST(savelen, out);
10571 INTOFF;
10572 free(str);
10573 str = NULL;
10574 INTON;
10575 }
10576 parsebackquote = savepbq;
10577 handler = savehandler;
10578 if (arinest || dblquote)
10579 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10580 else
10581 USTPUTC(CTLBACKQ, out);
10582 if (oldstyle)
10583 goto parsebackq_oldreturn;
10584 else
10585 goto parsebackq_newreturn;
10586 } 10491 }
10587 10492
10493 (*nlpp)->n = n;
10494 if (oldstyle) {
10495 /*
10496 * Start reading from old file again, ignoring any pushed back
10497 * tokens left from the backquote parsing
10498 */
10499 popfile();
10500 tokpushback = 0;
10501 }
10502 while (stackblocksize() <= savelen)
10503 growstackblock();
10504 STARTSTACKSTR(out);
10505 if (str) {
10506 memcpy(out, str, savelen);
10507 STADJUST(savelen, out);
10508 INTOFF;
10509 ckfree(str);
10510 str = NULL;
10511 INTON;
10512 }
10513 parsebackquote = savepbq;
10514 handler = savehandler;
10515 if (arinest || dblquote)
10516 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10517 else
10518 USTPUTC(CTLBACKQ, out);
10519 if (oldstyle)
10520 goto parsebackq_oldreturn;
10521 else
10522 goto parsebackq_newreturn;
10523}
10524
10525#ifdef CONFIG_ASH_MATH_SUPPORT
10588/* 10526/*
10589 * Parse an arithmetic expansion (indicate start of one and set state) 10527 * Parse an arithmetic expansion (indicate start of one and set state)
10590 */ 10528 */
10591 parsearith:{ 10529parsearith: {
10592 10530
10593 if (++arinest == 1) { 10531 if (++arinest == 1) {
10594 prevsyntax = syntax; 10532 prevsyntax = syntax;
10595 syntax = ARISYNTAX; 10533 syntax = ARISYNTAX;
10596 USTPUTC(CTLARI, out); 10534 USTPUTC(CTLARI, out);
10597 if (dblquote) 10535 if (dblquote)
10598 USTPUTC('"', out); 10536 USTPUTC('"',out);
10599 else 10537 else
10600 USTPUTC(' ', out); 10538 USTPUTC(' ',out);
10601 } else { 10539 } else {
10602 /* 10540 /*
10603 * we collapse embedded arithmetic expansion to 10541 * we collapse embedded arithmetic expansion to
10604 * parenthesis, which should be equivalent 10542 * parenthesis, which should be equivalent
10605 */ 10543 */
10606 USTPUTC('(', out); 10544 USTPUTC('(', out);
10607 }
10608 goto parsearith_return;
10609 } 10545 }
10546 goto parsearith_return;
10547}
10548#endif
10549
10550} /* end of readtoken */
10610 10551
10611} /* end of readtoken */
10612 10552
10613 10553
10614/* 10554/*
@@ -10616,7 +10556,8 @@ readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10616 * or backquotes). 10556 * or backquotes).
10617 */ 10557 */
10618 10558
10619static int noexpand(char *text) 10559static int
10560noexpand(char *text)
10620{ 10561{
10621 char *p; 10562 char *p;
10622 char c; 10563 char c;
@@ -10635,22 +10576,23 @@ static int noexpand(char *text)
10635 10576
10636 10577
10637/* 10578/*
10638 * Return true if the argument is a legal variable name (a letter or 10579 * Return of a legal variable name (a letter or underscore followed by zero or
10639 * underscore followed by zero or more letters, underscores, and digits). 10580 * more letters, underscores, and digits).
10640 */ 10581 */
10641 10582
10642static int goodname(const char *name) 10583char *
10643{ 10584endofname(const char *name)
10644 const char *p; 10585 {
10586 char *p;
10645 10587
10646 p = name; 10588 p = (char *) name;
10647 if (!is_name(*p)) 10589 if (! is_name(*p))
10648 return 0; 10590 return p;
10649 while (*++p) { 10591 while (*++p) {
10650 if (!is_in_name(*p)) 10592 if (! is_in_name(*p))
10651 return 0; 10593 break;
10652 } 10594 }
10653 return 1; 10595 return p;
10654} 10596}
10655 10597
10656 10598
@@ -10672,13 +10614,10 @@ static void synexpect(int token)
10672 /* NOTREACHED */ 10614 /* NOTREACHED */
10673} 10615}
10674 10616
10675 10617static void
10676static void synerror(const char *msg) 10618synerror(const char *msg)
10677{ 10619{
10678 if (commandname) 10620 error("Syntax error: %s", msg);
10679 out2fmt("%s: %d: ", commandname, startlinno);
10680 out2fmt("Syntax error: %s\n", msg);
10681 error((char *) NULL);
10682 /* NOTREACHED */ 10621 /* NOTREACHED */
10683} 10622}
10684 10623
@@ -10687,9 +10626,10 @@ static void synerror(const char *msg)
10687 * called by editline -- any expansions to the prompt 10626 * called by editline -- any expansions to the prompt
10688 * should be added here. 10627 * should be added here.
10689 */ 10628 */
10629
10690static void setprompt(int whichprompt) 10630static void setprompt(int whichprompt)
10691{ 10631{
10692 char *prompt; 10632 const char *prompt;
10693 10633
10694 switch (whichprompt) { 10634 switch (whichprompt) {
10695 case 1: 10635 case 1:
@@ -10698,30 +10638,39 @@ static void setprompt(int whichprompt)
10698 case 2: 10638 case 2:
10699 prompt = ps2val(); 10639 prompt = ps2val();
10700 break; 10640 break;
10701 default: /* 0 */ 10641 default: /* 0 */
10702 prompt = ""; 10642 prompt = nullstr;
10703 } 10643 }
10704 putprompt(prompt); 10644 putprompt(prompt);
10705} 10645}
10706 10646
10707 10647
10648static const char *const *findkwd(const char *s)
10649{
10650 return bsearch(s, tokname_array + KWDOFFSET,
10651 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10652 sizeof(const char *), pstrcmp);
10653}
10654
10655/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10656
10708/* 10657/*
10709 * Code for dealing with input/output redirection. 10658 * Code for dealing with input/output redirection.
10710 */ 10659 */
10711 10660
10712#define EMPTY -2 /* marks an unused slot in redirtab */ 10661#define EMPTY -2 /* marks an unused slot in redirtab */
10713#ifndef PIPE_BUF 10662#ifndef PIPE_BUF
10714# define PIPESIZE 4096 /* amount of buffering in a pipe */ 10663# define PIPESIZE 4096 /* amount of buffering in a pipe */
10715#else 10664#else
10716# define PIPESIZE PIPE_BUF 10665# define PIPESIZE PIPE_BUF
10717#endif 10666#endif
10718 10667
10719
10720/* 10668/*
10721 * Open a file in noclobber mode. 10669 * Open a file in noclobber mode.
10722 * The code was copied from bash. 10670 * The code was copied from bash.
10723 */ 10671 */
10724static inline int noclobberopen(const char *fname) 10672static inline int
10673noclobberopen(const char *fname)
10725{ 10674{
10726 int r, fd; 10675 int r, fd;
10727 struct stat finfo, finfo2; 10676 struct stat finfo, finfo2;
@@ -10744,8 +10693,8 @@ static inline int noclobberopen(const char *fname)
10744 * file was not a regular file, we leave O_EXCL off. 10693 * file was not a regular file, we leave O_EXCL off.
10745 */ 10694 */
10746 if (r != 0) 10695 if (r != 0)
10747 return open(fname, O_WRONLY | O_CREAT | O_EXCL, 0666); 10696 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10748 fd = open(fname, O_WRONLY | O_CREAT, 0666); 10697 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10749 10698
10750 /* If the open failed, return the file descriptor right away. */ 10699 /* If the open failed, return the file descriptor right away. */
10751 if (fd < 0) 10700 if (fd < 0)
@@ -10764,8 +10713,8 @@ static inline int noclobberopen(const char *fname)
10764 * revealed that it was a regular file, and the file has not been 10713 * revealed that it was a regular file, and the file has not been
10765 * replaced, return the file descriptor. 10714 * replaced, return the file descriptor.
10766 */ 10715 */
10767 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) && 10716 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10768 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) 10717 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10769 return fd; 10718 return fd;
10770 10719
10771 /* The file has been replaced. badness. */ 10720 /* The file has been replaced. badness. */
@@ -10780,10 +10729,11 @@ static inline int noclobberopen(const char *fname)
10780 * the pipe without forking. 10729 * the pipe without forking.
10781 */ 10730 */
10782 10731
10783static inline int openhere(const union node *redir) 10732static inline int
10733openhere(union node *redir)
10784{ 10734{
10785 int pip[2]; 10735 int pip[2];
10786 int len = 0; 10736 size_t len = 0;
10787 10737
10788 if (pipe(pip) < 0) 10738 if (pipe(pip) < 0)
10789 error("Pipe call failed"); 10739 error("Pipe call failed");
@@ -10794,7 +10744,7 @@ static inline int openhere(const union node *redir)
10794 goto out; 10744 goto out;
10795 } 10745 }
10796 } 10746 }
10797 if (forkshell((struct job *) NULL, (union node *) NULL, FORK_NOJOB) == 0) { 10747 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10798 close(pip[0]); 10748 close(pip[0]);
10799 signal(SIGINT, SIG_IGN); 10749 signal(SIGINT, SIG_IGN);
10800 signal(SIGQUIT, SIG_IGN); 10750 signal(SIGQUIT, SIG_IGN);
@@ -10809,13 +10759,13 @@ static inline int openhere(const union node *redir)
10809 expandhere(redir->nhere.doc, pip[1]); 10759 expandhere(redir->nhere.doc, pip[1]);
10810 _exit(0); 10760 _exit(0);
10811 } 10761 }
10812 out: 10762out:
10813 close(pip[1]); 10763 close(pip[1]);
10814 return pip[0]; 10764 return pip[0];
10815} 10765}
10816 10766
10817 10767static int
10818static inline int openredirect(const union node *redir) 10768openredirect(union node *redir)
10819{ 10769{
10820 char *fname; 10770 char *fname;
10821 int f; 10771 int f;
@@ -10828,7 +10778,7 @@ static inline int openredirect(const union node *redir)
10828 break; 10778 break;
10829 case NFROMTO: 10779 case NFROMTO:
10830 fname = redir->nfile.expfname; 10780 fname = redir->nfile.expfname;
10831 if ((f = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0) 10781 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10832 goto ecreate; 10782 goto ecreate;
10833 break; 10783 break;
10834 case NTO: 10784 case NTO:
@@ -10839,26 +10789,16 @@ static inline int openredirect(const union node *redir)
10839 goto ecreate; 10789 goto ecreate;
10840 break; 10790 break;
10841 } 10791 }
10842 case NTOOV: 10792 /* FALLTHROUGH */
10793 case NCLOBBER:
10843 fname = redir->nfile.expfname; 10794 fname = redir->nfile.expfname;
10844#ifdef O_CREAT 10795 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10845 if ((f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
10846 goto ecreate; 10796 goto ecreate;
10847#else
10848 if ((f = creat(fname, 0666)) < 0)
10849 goto ecreate;
10850#endif
10851 break; 10797 break;
10852 case NAPPEND: 10798 case NAPPEND:
10853 fname = redir->nfile.expfname; 10799 fname = redir->nfile.expfname;
10854#ifdef O_APPEND 10800 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10855 if ((f = open(fname, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0)
10856 goto ecreate;
10857#else
10858 if ((f = open(fname, O_WRONLY)) < 0 && (f = creat(fname, 0666)) < 0)
10859 goto ecreate; 10801 goto ecreate;
10860 lseek(f, (off_t) 0, 2);
10861#endif
10862 break; 10802 break;
10863 default: 10803 default:
10864#ifdef DEBUG 10804#ifdef DEBUG
@@ -10876,109 +10816,100 @@ static inline int openredirect(const union node *redir)
10876 } 10816 }
10877 10817
10878 return f; 10818 return f;
10879 ecreate: 10819ecreate:
10880 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 10820 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
10881 eopen: 10821eopen:
10882 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); 10822 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10883} 10823}
10884 10824
10825static inline void
10826dupredirect(union node *redir, int f)
10827{
10828 int fd = redir->nfile.fd;
10829
10830 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
10831 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10832 copyfd(redir->ndup.dupfd, fd);
10833 }
10834 return;
10835 }
10836
10837 if (f != fd) {
10838 copyfd(f, fd);
10839 close(f);
10840 }
10841 return;
10842}
10885 10843
10886/* 10844/*
10887 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 10845 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10888 * old file descriptors are stashed away so that the redirection can be 10846 * old file descriptors are stashed away so that the redirection can be
10889 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 10847 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10890 * standard output, and the standard error if it becomes a duplicate of 10848 * standard output, and the standard error if it becomes a duplicate of
10891 * stdout. 10849 * stdout, is saved in memory.
10892 */ 10850 */
10893 10851
10894static void redirect(union node *redir, int flags) 10852static void
10853redirect(union node *redir, int flags)
10895{ 10854{
10896 union node *n; 10855 union node *n;
10897 struct redirtab *sv = NULL; 10856 struct redirtab *sv;
10898 int i; 10857 int i;
10899 int fd; 10858 int fd;
10900 int newfd; 10859 int newfd;
10901 int try; 10860 int *p;
10902 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */ 10861 nullredirs++;
10903 10862 if (!redir) {
10904 TRACE(("redirect(%s) called\n", 10863 return;
10905 flags & REDIR_PUSH ? "REDIR_PUSH" : "NO_REDIR_PUSH"));
10906 if (flags & REDIR_PUSH) {
10907 sv = xmalloc(sizeof(struct redirtab));
10908 for (i = 0; i < 10; i++)
10909 sv->renamed[i] = EMPTY;
10910 sv->next = redirlist;
10911 redirlist = sv;
10912 } 10864 }
10913 for (n = redir; n; n = n->nfile.next) { 10865 sv = NULL;
10866 INTOFF;
10867 if (flags & REDIR_PUSH) {
10868 struct redirtab *q;
10869 q = ckmalloc(sizeof (struct redirtab));
10870 q->next = redirlist;
10871 redirlist = q;
10872 q->nullredirs = nullredirs - 1;
10873 for (i = 0 ; i < 10 ; i++)
10874 q->renamed[i] = EMPTY;
10875 nullredirs = 0;
10876 sv = q;
10877 }
10878 n = redir;
10879 do {
10914 fd = n->nfile.fd; 10880 fd = n->nfile.fd;
10915 try = 0;
10916 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && 10881 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
10917 n->ndup.dupfd == fd) 10882 n->ndup.dupfd == fd)
10918 continue; /* redirect from/to same file descriptor */ 10883 continue; /* redirect from/to same file descriptor */
10919 10884
10920 INTOFF;
10921 newfd = openredirect(n); 10885 newfd = openredirect(n);
10922 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { 10886 if (fd == newfd)
10923 i = fd; 10887 continue;
10924 if (newfd == fd) { 10888 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
10925 try++; 10889 i = fcntl(fd, F_DUPFD, 10);
10926 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { 10890
10927 switch (errno) { 10891 if (i == -1) {
10928 case EBADF: 10892 i = errno;
10929 if (!try) { 10893 if (i != EBADF) {
10930 dupredirect(n, newfd, fd1dup); 10894 close(newfd);
10931 try++; 10895 errno = i;
10932 break;
10933 }
10934 /* FALLTHROUGH */
10935 default:
10936 if (newfd >= 0) {
10937 close(newfd);
10938 }
10939 INTON;
10940 error("%d: %m", fd); 10896 error("%d: %m", fd);
10941 /* NOTREACHED */ 10897 /* NOTREACHED */
10942 } 10898 }
10943 } 10899 } else {
10944 if (!try) { 10900 *p = i;
10945 close(fd); 10901 close(fd);
10946 if (flags & REDIR_PUSH) {
10947 sv->renamed[fd] = i;
10948 }
10949 } 10902 }
10950 } else if (fd != newfd) { 10903 } else {
10951 close(fd); 10904 close(fd);
10952 } 10905 }
10953 if (fd == 0) 10906 dupredirect(n, newfd);
10954 fd0_redirected++; 10907 } while ((n = n->nfile.next));
10955 if (!try) 10908 INTON;
10956 dupredirect(n, newfd, fd1dup);
10957 INTON;
10958 }
10959} 10909}
10960 10910
10961 10911
10962static void dupredirect(const union node *redir, int f, int fd1dup)
10963{
10964 int fd = redir->nfile.fd;
10965 10912
10966 if (fd == 1)
10967 fd1dup = 0;
10968 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
10969 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10970 if (redir->ndup.dupfd != 1 || fd1dup != 1)
10971 dup_as_newfd(redir->ndup.dupfd, fd);
10972 }
10973 return;
10974 }
10975
10976 if (f != fd) {
10977 dup_as_newfd(f, fd);
10978 close(f);
10979 }
10980 return;
10981}
10982 10913
10983 10914
10984 10915
@@ -10986,55 +10917,60 @@ static void dupredirect(const union node *redir, int f, int fd1dup)
10986 * Undo the effects of the last redirection. 10917 * Undo the effects of the last redirection.
10987 */ 10918 */
10988 10919
10989static void popredir(void) 10920void
10921popredir(int drop)
10990{ 10922{
10991 struct redirtab *rp = redirlist; 10923 struct redirtab *rp;
10992 int i; 10924 int i;
10993 10925
10926 if (--nullredirs >= 0)
10927 return;
10994 INTOFF; 10928 INTOFF;
10995 for (i = 0; i < 10; i++) { 10929 rp = redirlist;
10930 for (i = 0 ; i < 10 ; i++) {
10996 if (rp->renamed[i] != EMPTY) { 10931 if (rp->renamed[i] != EMPTY) {
10997 if (i == 0) 10932 if (!drop) {
10998 fd0_redirected--; 10933 close(i);
10999 close(i); 10934 copyfd(rp->renamed[i], i);
11000 if (rp->renamed[i] >= 0) {
11001 dup_as_newfd(rp->renamed[i], i);
11002 close(rp->renamed[i]);
11003 } 10935 }
10936 close(rp->renamed[i]);
11004 } 10937 }
11005 } 10938 }
11006 redirlist = rp->next; 10939 redirlist = rp->next;
11007 free(rp); 10940 nullredirs = rp->nullredirs;
10941 ckfree(rp);
11008 INTON; 10942 INTON;
11009} 10943}
11010 10944
11011/* 10945/*
10946 * Undo all redirections. Called on error or interrupt.
10947 */
10948
10949/*
11012 * Discard all saved file descriptors. 10950 * Discard all saved file descriptors.
11013 */ 10951 */
11014 10952
11015static void clearredir(void) 10953void
10954clearredir(int drop)
11016{ 10955{
11017 struct redirtab *rp; 10956 for (;;) {
11018 int i; 10957 nullredirs = 0;
11019 10958 if (!redirlist)
11020 for (rp = redirlist; rp; rp = rp->next) { 10959 break;
11021 for (i = 0; i < 10; i++) { 10960 popredir(drop);
11022 if (rp->renamed[i] >= 0) {
11023 close(rp->renamed[i]);
11024 }
11025 rp->renamed[i] = EMPTY;
11026 }
11027 } 10961 }
11028} 10962}
11029 10963
11030 10964
10965
11031/* 10966/*
11032 * Copy a file descriptor to be >= to. Returns -1 10967 * Copy a file descriptor to be >= to. Returns -1
11033 * if the source file descriptor is closed, EMPTY if there are no unused 10968 * if the source file descriptor is closed, EMPTY if there are no unused
11034 * file descriptors left. 10969 * file descriptors left.
11035 */ 10970 */
11036 10971
11037static int dup_as_newfd(int from, int to) 10972int
10973copyfd(int from, int to)
11038{ 10974{
11039 int newfd; 10975 int newfd;
11040 10976
@@ -11048,27 +10984,47 @@ static int dup_as_newfd(int from, int to)
11048 return newfd; 10984 return newfd;
11049} 10985}
11050 10986
11051#ifdef DEBUG
11052/*
11053 * Debugging stuff.
11054 */
11055 10987
11056static void shtree(union node *, int, char *, FILE *); 10988int
10989redirectsafe(union node *redir, int flags)
10990{
10991 int err;
10992 volatile int saveint;
10993 struct jmploc *volatile savehandler = handler;
10994 struct jmploc jmploc;
10995
10996 SAVEINT(saveint);
10997 if (!(err = setjmp(jmploc.loc) * 2)) {
10998 handler = &jmploc;
10999 redirect(redir, flags);
11000 }
11001 handler = savehandler;
11002 if (err && exception != EXERROR)
11003 longjmp(handler->loc, 1);
11004 RESTOREINT(saveint);
11005 return err;
11006}
11007
11008/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11009
11010#ifdef DEBUG
11011static void shtree(union node *, int, char *, FILE*);
11057static void shcmd(union node *, FILE *); 11012static void shcmd(union node *, FILE *);
11058static void sharg(union node *, FILE *); 11013static void sharg(union node *, FILE *);
11059static void indent(int, char *, FILE *); 11014static void indent(int, char *, FILE *);
11060static void trstring(char *); 11015static void trstring(char *);
11061 11016
11062 11017
11063#if 0 11018void
11064static void showtree(node * n) 11019showtree(union node *n)
11065{ 11020{
11066 trputs("showtree called\n"); 11021 trputs("showtree called\n");
11067 shtree(n, 1, NULL, stdout); 11022 shtree(n, 1, NULL, stdout);
11068} 11023}
11069#endif
11070 11024
11071static void shtree(union node *n, int ind, char *pfx, FILE * fp) 11025
11026static void
11027shtree(union node *n, int ind, char *pfx, FILE *fp)
11072{ 11028{
11073 struct nodelist *lp; 11029 struct nodelist *lp;
11074 const char *s; 11030 const char *s;
@@ -11077,7 +11033,7 @@ static void shtree(union node *n, int ind, char *pfx, FILE * fp)
11077 return; 11033 return;
11078 11034
11079 indent(ind, pfx, fp); 11035 indent(ind, pfx, fp);
11080 switch (n->type) { 11036 switch(n->type) {
11081 case NSEMI: 11037 case NSEMI:
11082 s = "; "; 11038 s = "; ";
11083 goto binop; 11039 goto binop;
@@ -11086,10 +11042,10 @@ static void shtree(union node *n, int ind, char *pfx, FILE * fp)
11086 goto binop; 11042 goto binop;
11087 case NOR: 11043 case NOR:
11088 s = " || "; 11044 s = " || ";
11089 binop: 11045binop:
11090 shtree(n->nbinary.ch1, ind, NULL, fp); 11046 shtree(n->nbinary.ch1, ind, NULL, fp);
11091 /* if (ind < 0) */ 11047 /* if (ind < 0) */
11092 fputs(s, fp); 11048 fputs(s, fp);
11093 shtree(n->nbinary.ch2, ind, NULL, fp); 11049 shtree(n->nbinary.ch2, ind, NULL, fp);
11094 break; 11050 break;
11095 case NCMD: 11051 case NCMD:
@@ -11098,7 +11054,7 @@ static void shtree(union node *n, int ind, char *pfx, FILE * fp)
11098 putc('\n', fp); 11054 putc('\n', fp);
11099 break; 11055 break;
11100 case NPIPE: 11056 case NPIPE:
11101 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 11057 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11102 shcmd(lp->n, fp); 11058 shcmd(lp->n, fp);
11103 if (lp->next) 11059 if (lp->next)
11104 fputs(" | ", fp); 11060 fputs(" | ", fp);
@@ -11117,7 +11073,9 @@ static void shtree(union node *n, int ind, char *pfx, FILE * fp)
11117} 11073}
11118 11074
11119 11075
11120static void shcmd(union node *cmd, FILE * fp) 11076
11077static void
11078shcmd(union node *cmd, FILE *fp)
11121{ 11079{
11122 union node *np; 11080 union node *np;
11123 int first; 11081 int first;
@@ -11125,60 +11083,25 @@ static void shcmd(union node *cmd, FILE * fp)
11125 int dftfd; 11083 int dftfd;
11126 11084
11127 first = 1; 11085 first = 1;
11128 for (np = cmd->ncmd.args; np; np = np->narg.next) { 11086 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11129 if (!first) 11087 if (! first)
11130 putchar(' '); 11088 putchar(' ');
11131 sharg(np, fp); 11089 sharg(np, fp);
11132 first = 0; 11090 first = 0;
11133 } 11091 }
11134 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) { 11092 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11135 if (!first) 11093 if (! first)
11136 putchar(' '); 11094 putchar(' ');
11137#if 1
11138 s = "*error*";
11139 dftfd = 0;
11140 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11141 s = redir_strings[np->nfile.type - NTO];
11142 if (*s == '>') {
11143 dftfd = 1;
11144 }
11145 }
11146#else
11147 switch (np->nfile.type) { 11095 switch (np->nfile.type) {
11148 case NTO: 11096 case NTO: s = ">"; dftfd = 1; break;
11149 s = ">"; 11097 case NCLOBBER: s = ">|"; dftfd = 1; break;
11150 dftfd = 1; 11098 case NAPPEND: s = ">>"; dftfd = 1; break;
11151 break; 11099 case NTOFD: s = ">&"; dftfd = 1; break;
11152 case NAPPEND: 11100 case NFROM: s = "<"; dftfd = 0; break;
11153 s = ">>"; 11101 case NFROMFD: s = "<&"; dftfd = 0; break;
11154 dftfd = 1; 11102 case NFROMTO: s = "<>"; dftfd = 0; break;
11155 break; 11103 default: s = "*error*"; dftfd = 0; break;
11156 case NTOFD:
11157 s = ">&";
11158 dftfd = 1;
11159 break;
11160 case NTOOV:
11161 s = ">|";
11162 dftfd = 1;
11163 break;
11164 case NFROM:
11165 s = "<";
11166 dftfd = 0;
11167 break;
11168 case NFROMFD:
11169 s = "<&";
11170 dftfd = 0;
11171 break;
11172 case NFROMTO:
11173 s = "<>";
11174 dftfd = 0;
11175 break;
11176 default:
11177 s = "*error*";
11178 dftfd = 0;
11179 break;
11180 } 11104 }
11181#endif
11182 if (np->nfile.fd != dftfd) 11105 if (np->nfile.fd != dftfd)
11183 fprintf(fp, "%d", np->nfile.fd); 11106 fprintf(fp, "%d", np->nfile.fd);
11184 fputs(s, fp); 11107 fputs(s, fp);
@@ -11192,19 +11115,20 @@ static void shcmd(union node *cmd, FILE * fp)
11192} 11115}
11193 11116
11194 11117
11195static void sharg(union node *arg, FILE * fp) 11118
11119static void
11120sharg(union node *arg, FILE *fp)
11196{ 11121{
11197 char *p; 11122 char *p;
11198 struct nodelist *bqlist; 11123 struct nodelist *bqlist;
11199 int subtype; 11124 int subtype;
11200 11125
11201 if (arg->type != NARG) { 11126 if (arg->type != NARG) {
11202 printf("<node type %d>\n", arg->type); 11127 out1fmt("<node type %d>\n", arg->type);
11203 fflush(stdout);
11204 abort(); 11128 abort();
11205 } 11129 }
11206 bqlist = arg->narg.backquote; 11130 bqlist = arg->narg.backquote;
11207 for (p = arg->narg.text; *p; p++) { 11131 for (p = arg->narg.text ; *p ; p++) {
11208 switch (*p) { 11132 switch (*p) {
11209 case CTLESC: 11133 case CTLESC:
11210 putc(*++p, fp); 11134 putc(*++p, fp);
@@ -11255,14 +11179,14 @@ static void sharg(union node *arg, FILE * fp)
11255 case VSLENGTH: 11179 case VSLENGTH:
11256 break; 11180 break;
11257 default: 11181 default:
11258 printf("<subtype %d>", subtype); 11182 out1fmt("<subtype %d>", subtype);
11259 } 11183 }
11260 break; 11184 break;
11261 case CTLENDVAR: 11185 case CTLENDVAR:
11262 putc('}', fp); 11186 putc('}', fp);
11263 break; 11187 break;
11264 case CTLBACKQ: 11188 case CTLBACKQ:
11265 case CTLBACKQ | CTLQUOTE: 11189 case CTLBACKQ|CTLQUOTE:
11266 putc('$', fp); 11190 putc('$', fp);
11267 putc('(', fp); 11191 putc('(', fp);
11268 shtree(bqlist->n, -1, NULL, fp); 11192 shtree(bqlist->n, -1, NULL, fp);
@@ -11276,100 +11200,88 @@ static void sharg(union node *arg, FILE * fp)
11276} 11200}
11277 11201
11278 11202
11279static void indent(int amount, char *pfx, FILE * fp) 11203static void
11204indent(int amount, char *pfx, FILE *fp)
11280{ 11205{
11281 int i; 11206 int i;
11282 11207
11283 for (i = 0; i < amount; i++) { 11208 for (i = 0 ; i < amount ; i++) {
11284 if (pfx && i == amount - 1) 11209 if (pfx && i == amount - 1)
11285 fputs(pfx, fp); 11210 fputs(pfx, fp);
11286 putc('\t', fp); 11211 putc('\t', fp);
11287 } 11212 }
11288} 11213}
11289 11214
11290FILE *tracefile;
11291 11215
11292#if DEBUG == 2 11216
11293static int debug = 1; 11217/*
11294#else 11218 * Debugging stuff.
11295static int debug = 0; 11219 */
11296#endif 11220
11221
11222FILE *tracefile;
11297 11223
11298 11224
11299static void trputc(int c) 11225void
11226trputc(int c)
11300{ 11227{
11301 if (tracefile == NULL) 11228 if (debug != 1)
11302 return; 11229 return;
11303 putc(c, tracefile); 11230 putc(c, tracefile);
11304 if (c == '\n')
11305 fflush(tracefile);
11306} 11231}
11307 11232
11308static void trace(const char *fmt, ...) 11233void
11234trace(const char *fmt, ...)
11309{ 11235{
11310 va_list va; 11236 va_list va;
11311 11237
11238 if (debug != 1)
11239 return;
11312 va_start(va, fmt); 11240 va_start(va, fmt);
11313 if (tracefile != NULL) { 11241 (void) vfprintf(tracefile, fmt, va);
11314 (void) vfprintf(tracefile, fmt, va);
11315 if (strchr(fmt, '\n'))
11316 (void) fflush(tracefile);
11317 }
11318 va_end(va); 11242 va_end(va);
11319} 11243}
11320 11244
11245void
11246tracev(const char *fmt, va_list va)
11247{
11248 if (debug != 1)
11249 return;
11250 (void) vfprintf(tracefile, fmt, va);
11251}
11252
11321 11253
11322static void trputs(const char *s) 11254void
11255trputs(const char *s)
11323{ 11256{
11324 if (tracefile == NULL) 11257 if (debug != 1)
11325 return; 11258 return;
11326 fputs(s, tracefile); 11259 fputs(s, tracefile);
11327 if (strchr(s, '\n'))
11328 fflush(tracefile);
11329} 11260}
11330 11261
11331 11262
11332static void trstring(char *s) 11263static void
11264trstring(char *s)
11333{ 11265{
11334 char *p; 11266 char *p;
11335 char c; 11267 char c;
11336 11268
11337 if (tracefile == NULL) 11269 if (debug != 1)
11338 return; 11270 return;
11339 putc('"', tracefile); 11271 putc('"', tracefile);
11340 for (p = s; *p; p++) { 11272 for (p = s ; *p ; p++) {
11341 switch (*p) { 11273 switch (*p) {
11342 case '\n': 11274 case '\n': c = 'n'; goto backslash;
11343 c = 'n'; 11275 case '\t': c = 't'; goto backslash;
11344 goto backslash; 11276 case '\r': c = 'r'; goto backslash;
11345 case '\t': 11277 case '"': c = '"'; goto backslash;
11346 c = 't'; 11278 case '\\': c = '\\'; goto backslash;
11347 goto backslash; 11279 case CTLESC: c = 'e'; goto backslash;
11348 case '\r': 11280 case CTLVAR: c = 'v'; goto backslash;
11349 c = 'r'; 11281 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11350 goto backslash; 11282 case CTLBACKQ: c = 'q'; goto backslash;
11351 case '"': 11283 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11352 c = '"'; 11284backslash: putc('\\', tracefile);
11353 goto backslash;
11354 case '\\':
11355 c = '\\';
11356 goto backslash;
11357 case CTLESC:
11358 c = 'e';
11359 goto backslash;
11360 case CTLVAR:
11361 c = 'v';
11362 goto backslash;
11363 case CTLVAR + CTLQUOTE:
11364 c = 'V';
11365 goto backslash;
11366 case CTLBACKQ:
11367 c = 'q';
11368 goto backslash;
11369 case CTLBACKQ + CTLQUOTE:
11370 c = 'Q';
11371 goto backslash;
11372 backslash:putc('\\', tracefile);
11373 putc(c, tracefile); 11285 putc(c, tracefile);
11374 break; 11286 break;
11375 default: 11287 default:
@@ -11388,9 +11300,10 @@ static void trstring(char *s)
11388} 11300}
11389 11301
11390 11302
11391static void trargs(char **ap) 11303void
11304trargs(char **ap)
11392{ 11305{
11393 if (tracefile == NULL) 11306 if (debug != 1)
11394 return; 11307 return;
11395 while (*ap) { 11308 while (*ap) {
11396 trstring(*ap++); 11309 trstring(*ap++);
@@ -11399,78 +11312,91 @@ static void trargs(char **ap)
11399 else 11312 else
11400 putc('\n', tracefile); 11313 putc('\n', tracefile);
11401 } 11314 }
11402 fflush(tracefile);
11403} 11315}
11404 11316
11405 11317
11406static void opentrace() 11318void
11319opentrace(void)
11407{ 11320{
11408 char s[100]; 11321 char s[100];
11409
11410#ifdef O_APPEND 11322#ifdef O_APPEND
11411 int flags; 11323 int flags;
11412#endif 11324#endif
11413 11325
11414 if (!debug) 11326 if (debug != 1) {
11327 if (tracefile)
11328 fflush(tracefile);
11329 /* leave open because libedit might be using it */
11415 return; 11330 return;
11416#ifdef not_this_way 11331 }
11417 { 11332 scopy("./trace", s);
11418 char *p; 11333 if (tracefile) {
11419 11334 if (!freopen(s, "a", tracefile)) {
11420 if ((p = getenv("HOME")) == NULL) { 11335 fprintf(stderr, "Can't re-open %s\n", s);
11421 if (geteuid() == 0) 11336 debug = 0;
11422 p = "/"; 11337 return;
11423 else 11338 }
11424 p = "/tmp"; 11339 } else {
11340 if ((tracefile = fopen(s, "a")) == NULL) {
11341 fprintf(stderr, "Can't open %s\n", s);
11342 debug = 0;
11343 return;
11425 } 11344 }
11426 strcpy(s, p);
11427 strcat(s, "/trace");
11428 } 11345 }
11429#else
11430 strcpy(s, "./trace");
11431#endif /* not_this_way */
11432 if ((tracefile = bb_wfopen(s, "a")) == NULL)
11433 return;
11434#ifdef O_APPEND 11346#ifdef O_APPEND
11435 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) 11347 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11436 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 11348 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11437#endif 11349#endif
11350 setlinebuf(tracefile);
11438 fputs("\nTracing started.\n", tracefile); 11351 fputs("\nTracing started.\n", tracefile);
11439 fflush(tracefile);
11440} 11352}
11441#endif /* DEBUG */ 11353#endif /* DEBUG */
11354
11355
11356/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11357
11358/*
11359 * Sigmode records the current value of the signal handlers for the various
11360 * modes. A value of zero means that the current handler is not known.
11361 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11362 */
11363
11364#define S_DFL 1 /* default signal handling (SIG_DFL) */
11365#define S_CATCH 2 /* signal is caught */
11366#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11367#define S_HARD_IGN 4 /* signal is ignored permenantly */
11368#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11369
11442 11370
11443 11371
11444/* 11372/*
11445 * The trap builtin. 11373 * The trap builtin.
11446 */ 11374 */
11447 11375
11448static int trapcmd(int argc, char **argv) 11376int
11377trapcmd(int argc, char **argv)
11449{ 11378{
11450 char *action; 11379 char *action;
11451 char **ap; 11380 char **ap;
11452 int signo; 11381 int signo;
11453 11382
11454 if (argc <= 1) { 11383 nextopt(nullstr);
11455 for (signo = 0; signo < NSIG; signo++) { 11384 ap = argptr;
11385 if (!*ap) {
11386 for (signo = 0 ; signo < NSIG ; signo++) {
11456 if (trap[signo] != NULL) { 11387 if (trap[signo] != NULL) {
11457 char *p;
11458 const char *sn; 11388 const char *sn;
11459 11389
11460 p = single_quote(trap[signo]); 11390 sn = u_signal_names(0, &signo, 0);
11461 sn = sys_siglist[signo];
11462 if (sn == NULL)
11463 sn = u_signal_names(0, &signo, 0);
11464 if (sn == NULL) 11391 if (sn == NULL)
11465 sn = "???"; 11392 sn = "???";
11466 printf("trap -- %s %s\n", p, sn); 11393 out1fmt("trap -- %s %s\n",
11467 stunalloc(p); 11394 single_quote(trap[signo]), sn);
11468 } 11395 }
11469 } 11396 }
11470 return 0; 11397 return 0;
11471 } 11398 }
11472 ap = argv + 1; 11399 if (!ap[1])
11473 if (argc == 2)
11474 action = NULL; 11400 action = NULL;
11475 else 11401 else
11476 action = *ap++; 11402 action = *ap++;
@@ -11482,9 +11408,10 @@ static int trapcmd(int argc, char **argv)
11482 if (action[0] == '-' && action[1] == '\0') 11408 if (action[0] == '-' && action[1] == '\0')
11483 action = NULL; 11409 action = NULL;
11484 else 11410 else
11485 action = bb_xstrdup(action); 11411 action = savestr(action);
11486 } 11412 }
11487 free(trap[signo]); 11413 if (trap[signo])
11414 ckfree(trap[signo]);
11488 trap[signo] = action; 11415 trap[signo] = action;
11489 if (signo != 0) 11416 if (signo != 0)
11490 setsignal(signo); 11417 setsignal(signo);
@@ -11495,15 +11422,40 @@ static int trapcmd(int argc, char **argv)
11495} 11422}
11496 11423
11497 11424
11425
11426/*
11427 * Clear traps on a fork.
11428 */
11429
11430void
11431clear_traps(void)
11432{
11433 char **tp;
11434
11435 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11436 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11437 INTOFF;
11438 ckfree(*tp);
11439 *tp = NULL;
11440 if (tp != &trap[0])
11441 setsignal(tp - trap);
11442 INTON;
11443 }
11444 }
11445}
11446
11447
11448
11498/* 11449/*
11499 * Set the signal handler for the specified signal. The routine figures 11450 * Set the signal handler for the specified signal. The routine figures
11500 * out what it should be set to. 11451 * out what it should be set to.
11501 */ 11452 */
11502 11453
11503static void setsignal(int signo) 11454void
11455setsignal(int signo)
11504{ 11456{
11505 int action; 11457 int action;
11506 char *t; 11458 char *t, tsig;
11507 struct sigaction act; 11459 struct sigaction act;
11508 11460
11509 if ((t = trap[signo]) == NULL) 11461 if ((t = trap[signo]) == NULL)
@@ -11520,18 +11472,15 @@ static void setsignal(int signo)
11520 break; 11472 break;
11521 case SIGQUIT: 11473 case SIGQUIT:
11522#ifdef DEBUG 11474#ifdef DEBUG
11523 {
11524
11525 if (debug) 11475 if (debug)
11526 break; 11476 break;
11527 }
11528#endif 11477#endif
11529 /* FALLTHROUGH */ 11478 /* FALLTHROUGH */
11530 case SIGTERM: 11479 case SIGTERM:
11531 if (iflag) 11480 if (iflag)
11532 action = S_IGN; 11481 action = S_IGN;
11533 break; 11482 break;
11534#ifdef CONFIG_ASH_JOB_CONTROL 11483#if JOBS
11535 case SIGTSTP: 11484 case SIGTSTP:
11536 case SIGTTOU: 11485 case SIGTTOU:
11537 if (mflag) 11486 if (mflag)
@@ -11542,7 +11491,8 @@ static void setsignal(int signo)
11542 } 11491 }
11543 11492
11544 t = &sigmode[signo - 1]; 11493 t = &sigmode[signo - 1];
11545 if (*t == 0) { 11494 tsig = *t;
11495 if (tsig == 0) {
11546 /* 11496 /*
11547 * current setting unknown 11497 * current setting unknown
11548 */ 11498 */
@@ -11556,21 +11506,29 @@ static void setsignal(int signo)
11556 } 11506 }
11557 if (act.sa_handler == SIG_IGN) { 11507 if (act.sa_handler == SIG_IGN) {
11558 if (mflag && (signo == SIGTSTP || 11508 if (mflag && (signo == SIGTSTP ||
11559 signo == SIGTTIN || signo == SIGTTOU)) { 11509 signo == SIGTTIN || signo == SIGTTOU)) {
11560 *t = S_IGN; /* don't hard ignore these */ 11510 tsig = S_IGN; /* don't hard ignore these */
11561 } else 11511 } else
11562 *t = S_HARD_IGN; 11512 tsig = S_HARD_IGN;
11563 } else { 11513 } else {
11564 *t = S_RESET; /* force to be set */ 11514 tsig = S_RESET; /* force to be set */
11565 } 11515 }
11566 } 11516 }
11567 if (*t == S_HARD_IGN || *t == action) 11517 if (tsig == S_HARD_IGN || tsig == action)
11568 return; 11518 return;
11569 act.sa_handler = ((action == S_CATCH) ? onsig 11519 switch (action) {
11570 : ((action == S_IGN) ? SIG_IGN : SIG_DFL)); 11520 case S_CATCH:
11521 act.sa_handler = onsig;
11522 break;
11523 case S_IGN:
11524 act.sa_handler = SIG_IGN;
11525 break;
11526 default:
11527 act.sa_handler = SIG_DFL;
11528 }
11571 *t = action; 11529 *t = action;
11572 act.sa_flags = 0; 11530 act.sa_flags = 0;
11573 sigemptyset(&act.sa_mask); 11531 sigfillset(&act.sa_mask);
11574 sigaction(signo, &act, 0); 11532 sigaction(signo, &act, 0);
11575} 11533}
11576 11534
@@ -11578,7 +11536,8 @@ static void setsignal(int signo)
11578 * Ignore a signal. 11536 * Ignore a signal.
11579 */ 11537 */
11580 11538
11581static void ignoresig(int signo) 11539void
11540ignoresig(int signo)
11582{ 11541{
11583 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 11542 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11584 signal(signo, SIG_IGN); 11543 signal(signo, SIG_IGN);
@@ -11587,74 +11546,142 @@ static void ignoresig(int signo)
11587} 11546}
11588 11547
11589 11548
11549
11590/* 11550/*
11591 * Signal handler. 11551 * Signal handler.
11592 */ 11552 */
11593 11553
11594static void onsig(int signo) 11554void
11555onsig(int signo)
11595{ 11556{
11596 if (signo == SIGINT && trap[SIGINT] == NULL) {
11597 onint();
11598 return;
11599 }
11600 gotsig[signo - 1] = 1; 11557 gotsig[signo - 1] = 1;
11601 pendingsigs++; 11558 pendingsigs = signo;
11559
11560 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11561 if (!suppressint)
11562 onint();
11563 intpending = 1;
11564 }
11602} 11565}
11603 11566
11604 11567
11568
11605/* 11569/*
11606 * Called to execute a trap. Perhaps we should avoid entering new trap 11570 * Called to execute a trap. Perhaps we should avoid entering new trap
11607 * handlers while we are executing a trap handler. 11571 * handlers while we are executing a trap handler.
11608 */ 11572 */
11609 11573
11610static void dotrap(void) 11574void
11575dotrap(void)
11611{ 11576{
11612 int i; 11577 char *p;
11578 char *q;
11613 int savestatus; 11579 int savestatus;
11614 11580
11615 for (;;) { 11581 savestatus = exitstatus;
11616 for (i = 1;; i++) { 11582 q = gotsig;
11617 if (gotsig[i - 1]) 11583 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11618 break; 11584 *p = 0;
11619 if (i >= NSIG - 1) 11585 p = trap[p - q + 1];
11620 goto done; 11586 if (!p)
11621 } 11587 continue;
11622 gotsig[i - 1] = 0; 11588 evalstring(p, 0);
11623 savestatus = exitstatus;
11624 evalstring(trap[i], 0);
11625 exitstatus = savestatus; 11589 exitstatus = savestatus;
11626 } 11590 }
11627 done:
11628 pendingsigs = 0;
11629} 11591}
11630 11592
11593
11594
11595/*
11596 * Controls whether the shell is interactive or not.
11597 */
11598
11599
11600void
11601setinteractive(int on)
11602{
11603 static int is_interactive;
11604
11605 if (++on == is_interactive)
11606 return;
11607 is_interactive = on;
11608 setsignal(SIGINT);
11609 setsignal(SIGQUIT);
11610 setsignal(SIGTERM);
11611#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11612 if(is_interactive > 1) {
11613 /* Looks like they want an interactive shell */
11614 static int do_banner;
11615
11616 if(!do_banner) {
11617 out1fmt(
11618 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11619 "Enter 'help' for a list of built-in commands.\n\n");
11620 do_banner++;
11621 }
11622 }
11623#endif
11624}
11625
11626
11627#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11628/*** List the available builtins ***/
11629
11630static int helpcmd(int argc, char **argv)
11631{
11632 int col, i;
11633
11634 out1fmt("\nBuilt-in commands:\n-------------------\n");
11635 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11636 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11637 builtincmd[i].name + 1);
11638 if (col > 60) {
11639 out1fmt("\n");
11640 col = 0;
11641 }
11642 }
11643#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11644 {
11645 extern const struct BB_applet applets[];
11646 extern const size_t NUM_APPLETS;
11647
11648 for (i = 0; i < NUM_APPLETS; i++) {
11649
11650 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11651 if (col > 60) {
11652 out1fmt("\n");
11653 col = 0;
11654 }
11655 }
11656 }
11657#endif
11658 out1fmt("\n\n");
11659 return EXIT_SUCCESS;
11660}
11661#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11662
11631/* 11663/*
11632 * Called to exit the shell. 11664 * Called to exit the shell.
11633 */ 11665 */
11634 11666
11635static void exitshell(int status) 11667void
11668exitshell(void)
11636{ 11669{
11637 struct jmploc loc1, loc2; 11670 struct jmploc loc;
11638 char *p; 11671 char *p;
11672 int status;
11639 11673
11640 TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 11674 status = exitstatus;
11641 if (setjmp(loc1.loc)) { 11675 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11642 goto l1; 11676 if (setjmp(loc.loc)) {
11643 } 11677 goto out;
11644 if (setjmp(loc2.loc)) {
11645 goto l2;
11646 } 11678 }
11647 handler = &loc1; 11679 handler = &loc;
11648 if ((p = trap[0]) != NULL && *p != '\0') { 11680 if ((p = trap[0]) != NULL && *p != '\0') {
11649 trap[0] = NULL; 11681 trap[0] = NULL;
11650 evalstring(p, 0); 11682 evalstring(p, 0);
11651 } 11683 }
11652l1:
11653 handler = &loc2; /* probably unnecessary */
11654 flushall(); 11684 flushall();
11655#ifdef CONFIG_ASH_JOB_CONTROL
11656 setjobctl(0);
11657#endif
11658#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 11685#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11659 if (iflag && rootshell) { 11686 if (iflag && rootshell) {
11660 const char *hp = lookupvar("HISTFILE"); 11687 const char *hp = lookupvar("HISTFILE");
@@ -11663,7 +11690,8 @@ l1:
11663 save_history ( hp ); 11690 save_history ( hp );
11664 } 11691 }
11665#endif 11692#endif
11666l2: 11693out:
11694 out1c('\n');
11667 _exit(status); 11695 _exit(status);
11668 /* NOTREACHED */ 11696 /* NOTREACHED */
11669} 11697}
@@ -11676,95 +11704,78 @@ static int decode_signal(const char *string, int minsig)
11676 return name ? signo : -1; 11704 return name ? signo : -1;
11677} 11705}
11678 11706
11679static struct var **hashvar(const char *); 11707/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11680static void showvars(const char *, int, int); 11708
11709static struct var *vartab[VTABSIZE];
11710
11711static int vpcmp(const void *, const void *);
11681static struct var **findvar(struct var **, const char *); 11712static struct var **findvar(struct var **, const char *);
11682 11713
11683/* 11714/*
11684 * Initialize the varable symbol tables and import the environment 11715 * Initialize the varable symbol tables and import the environment
11685 */ 11716 */
11686 11717
11718
11719#ifdef CONFIG_ASH_GETOPTS
11687/* 11720/*
11688 * This routine initializes the builtin variables. It is called when the 11721 * Safe version of setvar, returns 1 on success 0 on failure.
11689 * shell is initialized and again when a shell procedure is spawned.
11690 */ 11722 */
11691 11723
11692static void initvar() 11724int
11725setvarsafe(const char *name, const char *val, int flags)
11693{ 11726{
11694 const struct varinit *ip; 11727 int err;
11695 struct var *vp; 11728 volatile int saveint;
11696 struct var **vpp; 11729 struct jmploc *volatile savehandler = handler;
11730 struct jmploc jmploc;
11697 11731
11698 for (ip = varinit; (vp = ip->var) != NULL; ip++) { 11732 SAVEINT(saveint);
11699 if ((vp->flags & VEXPORT) == 0) { 11733 if (setjmp(jmploc.loc))
11700 vpp = hashvar(ip->text); 11734 err = 1;
11701 vp->next = *vpp; 11735 else {
11702 *vpp = vp; 11736 handler = &jmploc;
11703 vp->text = bb_xstrdup(ip->text); 11737 setvar(name, val, flags);
11704 vp->flags = ip->flags; 11738 err = 0;
11705 vp->func = ip->func;
11706 }
11707 }
11708#if !defined(CONFIG_FEATURE_COMMAND_EDITING) || !defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
11709 /*
11710 * PS1 depends on uid
11711 */
11712 if ((vps1.flags & VEXPORT) == 0) {
11713 vpp = hashvar("PS1=$ ");
11714 vps1.next = *vpp;
11715 *vpp = &vps1;
11716 vps1.text = bb_xstrdup(geteuid()? "PS1=$ " : "PS1=# ");
11717 vps1.flags = VSTRFIXED | VTEXTFIXED;
11718 } 11739 }
11719#endif 11740 handler = savehandler;
11741 RESTOREINT(saveint);
11742 return err;
11720} 11743}
11744#endif
11721 11745
11722/* 11746/*
11723 * Set the value of a variable. The flags argument is ored with the 11747 * Set the value of a variable. The flags argument is ored with the
11724 * flags of the variable. If val is NULL, the variable is unset. 11748 * flags of the variable. If val is NULL, the variable is unset.
11725 */ 11749 */
11726 11750
11727static void setvar(const char *name, const char *val, int flags) 11751static void
11752setvar(const char *name, const char *val, int flags)
11728{ 11753{
11729 const char *p; 11754 char *p, *q;
11730 int len; 11755 size_t namelen;
11731 int namelen;
11732 char *nameeq; 11756 char *nameeq;
11733 int isbad; 11757 size_t vallen;
11734 int vallen = 0;
11735 11758
11736 isbad = 0; 11759 q = endofname(name);
11737 p = name; 11760 p = strchrnul(q, '=');
11738 if (!is_name(*p))
11739 isbad = 1;
11740 p++;
11741 for (;;) {
11742 if (!is_in_name(*p)) {
11743 if (*p == '\0' || *p == '=')
11744 break;
11745 isbad = 1;
11746 }
11747 p++;
11748 }
11749 namelen = p - name; 11761 namelen = p - name;
11750 if (isbad) 11762 if (!namelen || p != q)
11751 error("%.*s: bad variable name", namelen, name); 11763 error("%.*s: bad variable name", namelen, name);
11752 len = namelen + 2; /* 2 is space for '=' and '\0' */ 11764 vallen = 0;
11753 if (val == NULL) { 11765 if (val == NULL) {
11754 flags |= VUNSET; 11766 flags |= VUNSET;
11755 } else { 11767 } else {
11756 len += vallen = strlen(val); 11768 vallen = strlen(val);
11757 } 11769 }
11758 INTOFF; 11770 INTOFF;
11759 nameeq = xmalloc(len); 11771 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11760 memcpy(nameeq, name, namelen); 11772 *p++ = '\0';
11761 nameeq[namelen] = '='; 11773 if (vallen) {
11762 if (val) { 11774 p[-1] = '=';
11763 memcpy(nameeq + namelen + 1, val, vallen + 1); 11775 p = mempcpy(p, val, vallen);
11764 } else {
11765 nameeq[namelen + 1] = '\0';
11766 } 11776 }
11767 setvareq(nameeq, flags); 11777 *p = '\0';
11778 setvareq(nameeq, flags | VNOSAVE);
11768 INTON; 11779 INTON;
11769} 11780}
11770 11781
@@ -11775,50 +11786,47 @@ static void setvar(const char *name, const char *val, int flags)
11775 * the first argument as name=value. Since the first argument will 11786 * the first argument as name=value. Since the first argument will
11776 * be actually stored in the table, it should not be a string that 11787 * be actually stored in the table, it should not be a string that
11777 * will go away. 11788 * will go away.
11789 * Called with interrupts off.
11778 */ 11790 */
11779 11791
11780static void setvareq(char *s, int flags) 11792void
11793setvareq(char *s, int flags)
11781{ 11794{
11782 struct var *vp, **vpp; 11795 struct var *vp, **vpp;
11783 11796
11784 vpp = hashvar(s); 11797 vpp = hashvar(s);
11785 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); 11798 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11786 if ((vp = *findvar(vpp, s))) { 11799 vp = *findvar(vpp, s);
11800 if (vp) {
11787 if (vp->flags & VREADONLY) { 11801 if (vp->flags & VREADONLY) {
11788 size_t len = strchr(s, '=') - s; 11802 if (flags & VNOSAVE)
11789 11803 free(s);
11790 error("%.*s: is read only", len, s); 11804 error("%.*s: is read only", strchrnul(s, '=') - s, s);
11791 } 11805 }
11792 INTOFF;
11793 11806
11794 if (vp->func && (flags & VNOFUNC) == 0) 11807 if (flags & VNOSET)
11795 (*vp->func) (strchr(s, '=') + 1); 11808 return;
11796 11809
11797 if ((vp->flags & (VTEXTFIXED | VSTACK)) == 0) 11810 if (vp->func && (flags & VNOFUNC) == 0)
11798 free(vp->text); 11811 (*vp->func)(strchrnul(s, '=') + 1);
11799 11812
11800 vp->flags &= ~(VTEXTFIXED | VSTACK | VUNSET); 11813 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11801 vp->flags |= flags; 11814 ckfree(vp->text);
11802 vp->text = s;
11803 11815
11804#ifdef CONFIG_ASH_MAIL 11816 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11805 /* 11817 } else {
11806 * We could roll this to a function, to handle it as 11818 if (flags & VNOSET)
11807 * a regular variable function callback, but why bother? 11819 return;
11808 */ 11820 /* not found */
11809 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset()))) 11821 vp = ckmalloc(sizeof (*vp));
11810 chkmail(1); 11822 vp->next = *vpp;
11811#endif 11823 vp->func = NULL;
11812 INTON; 11824 *vpp = vp;
11813 return;
11814 } 11825 }
11815 /* not found */ 11826 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
11816 vp = xmalloc(sizeof(*vp)); 11827 s = savestr(s);
11817 vp->flags = flags;
11818 vp->text = s; 11828 vp->text = s;
11819 vp->next = *vpp; 11829 vp->flags = flags;
11820 vp->func = NULL;
11821 *vpp = vp;
11822} 11830}
11823 11831
11824 11832
@@ -11827,29 +11835,32 @@ static void setvareq(char *s, int flags)
11827 * Process a linked list of variable assignments. 11835 * Process a linked list of variable assignments.
11828 */ 11836 */
11829 11837
11830static void listsetvar(struct strlist *mylist) 11838static void
11839listsetvar(struct strlist *list_set_var, int flags)
11831{ 11840{
11832 struct strlist *lp; 11841 struct strlist *lp = list_set_var;
11833 11842
11843 if (!lp)
11844 return;
11834 INTOFF; 11845 INTOFF;
11835 for (lp = mylist; lp; lp = lp->next) { 11846 do {
11836 setvareq(bb_xstrdup(lp->text), 0); 11847 setvareq(lp->text, flags);
11837 } 11848 } while ((lp = lp->next));
11838 INTON; 11849 INTON;
11839} 11850}
11840 11851
11841 11852
11842
11843/* 11853/*
11844 * Find the value of a variable. Returns NULL if not set. 11854 * Find the value of a variable. Returns NULL if not set.
11845 */ 11855 */
11846 11856
11847static const char *lookupvar(const char *name) 11857static char *
11858lookupvar(const char *name)
11848{ 11859{
11849 struct var *v; 11860 struct var *v;
11850 11861
11851 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { 11862 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
11852 return strchr(v->text, '=') + 1; 11863 return strchrnul(v->text, '=') + 1;
11853 } 11864 }
11854 return NULL; 11865 return NULL;
11855} 11866}
@@ -11860,13 +11871,14 @@ static const char *lookupvar(const char *name)
11860 * Search the environment of a builtin command. 11871 * Search the environment of a builtin command.
11861 */ 11872 */
11862 11873
11863static const char *bltinlookup(const char *name) 11874static char *
11875bltinlookup(const char *name)
11864{ 11876{
11865 const struct strlist *sp; 11877 struct strlist *sp;
11866 11878
11867 for (sp = cmdenviron; sp; sp = sp->next) { 11879 for (sp = cmdenviron ; sp ; sp = sp->next) {
11868 if (varequal(sp->text, name)) 11880 if (varequal(sp->text, name))
11869 return strchr(sp->text, '=') + 1; 11881 return strchrnul(sp->text, '=') + 1;
11870 } 11882 }
11871 return lookupvar(name); 11883 return lookupvar(name);
11872} 11884}
@@ -11874,44 +11886,69 @@ static const char *bltinlookup(const char *name)
11874 11886
11875 11887
11876/* 11888/*
11877 * Generate a list of exported variables. This routine is used to construct 11889 * Generate a list of variables satisfying the given conditions.
11878 * the third argument to execve when executing a program.
11879 */ 11890 */
11880 11891
11881static char **environment() 11892static char **
11893listvars(int on, int off, char ***end)
11882{ 11894{
11883 int nenv;
11884 struct var **vpp; 11895 struct var **vpp;
11885 struct var *vp; 11896 struct var *vp;
11886 char **env;
11887 char **ep; 11897 char **ep;
11898 int mask;
11888 11899
11889 nenv = 0; 11900 STARTSTACKSTR(ep);
11890 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { 11901 vpp = vartab;
11891 for (vp = *vpp; vp; vp = vp->next) 11902 mask = on | off;
11892 if (vp->flags & VEXPORT) 11903 do {
11893 nenv++; 11904 for (vp = *vpp ; vp ; vp = vp->next)
11894 } 11905 if ((vp->flags & mask) == on) {
11895 ep = env = stalloc((nenv + 1) * sizeof *env); 11906 if (ep == stackstrend())
11896 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { 11907 ep = growstackstr();
11897 for (vp = *vpp; vp; vp = vp->next) 11908 *ep++ = (char *) vp->text;
11898 if (vp->flags & VEXPORT) 11909 }
11899 *ep++ = vp->text; 11910 } while (++vpp < vartab + VTABSIZE);
11900 } 11911 if (ep == stackstrend())
11901 *ep = NULL; 11912 ep = growstackstr();
11902 return env; 11913 if (end)
11914 *end = ep;
11915 *ep++ = NULL;
11916 return grabstackstr(ep);
11903} 11917}
11904 11918
11905 11919
11920
11906/* 11921/*
11907 * Command to list all variables which are set. Currently this command 11922 * POSIX requires that 'set' (but not export or readonly) output the
11908 * is invoked from the set command when the set command is called without 11923 * variables in lexicographic order - by the locale's collating order (sigh).
11909 * any variables. 11924 * Maybe we could keep them in an ordered balanced binary tree
11925 * instead of hashed lists.
11926 * For now just roll 'em through qsort for printing...
11910 */ 11927 */
11911 11928
11912static int showvarscmd(int argc, char **argv) 11929static int
11930showvars(const char *sep_prefix, int on, int off)
11913{ 11931{
11914 showvars(nullstr, VUNSET, VUNSET); 11932 const char *sep;
11933 char **ep, **epend;
11934
11935 ep = listvars(on, off, &epend);
11936 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11937
11938 sep = *sep_prefix ? spcstr : sep_prefix;
11939
11940 for (; ep < epend; ep++) {
11941 const char *p;
11942 const char *q;
11943
11944 p = strchrnul(*ep, '=');
11945 q = nullstr;
11946 if (*p)
11947 q = single_quote(++p);
11948
11949 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11950 }
11951
11915 return 0; 11952 return 0;
11916} 11953}
11917 11954
@@ -11921,29 +11958,29 @@ static int showvarscmd(int argc, char **argv)
11921 * The export and readonly commands. 11958 * The export and readonly commands.
11922 */ 11959 */
11923 11960
11924static int exportcmd(int argc, char **argv) 11961static int
11962exportcmd(int argc, char **argv)
11925{ 11963{
11926 struct var *vp; 11964 struct var *vp;
11927 char *name; 11965 char *name;
11928 const char *p; 11966 const char *p;
11929 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT; 11967 char **aptr;
11930 int pflag; 11968 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11969 int notp;
11931 11970
11932 listsetvar(cmdenviron); 11971 notp = nextopt("p") - 'p';
11933 pflag = (nextopt("p") == 'p'); 11972 if (notp && ((name = *(aptr = argptr)))) {
11934 if (argc > 1 && !pflag) { 11973 do {
11935 while ((name = *argptr++) != NULL) {
11936 if ((p = strchr(name, '=')) != NULL) { 11974 if ((p = strchr(name, '=')) != NULL) {
11937 p++; 11975 p++;
11938 } else { 11976 } else {
11939 if ((vp = *findvar(hashvar(name), name))) { 11977 if ((vp = *findvar(hashvar(name), name))) {
11940 vp->flags |= flag; 11978 vp->flags |= flag;
11941 goto found; 11979 continue;
11942 } 11980 }
11943 } 11981 }
11944 setvar(name, p, flag); 11982 setvar(name, p, flag);
11945 found:; 11983 } while ((name = *++aptr) != NULL);
11946 }
11947 } else { 11984 } else {
11948 showvars(argv[0], flag, 0); 11985 showvars(argv[0], flag, 0);
11949 } 11986 }
@@ -11952,62 +11989,45 @@ static int exportcmd(int argc, char **argv)
11952 11989
11953 11990
11954/* 11991/*
11955 * The "local" command.
11956 */
11957
11958/* funcnest nonzero if we are currently evaluating a function */
11959
11960static int localcmd(int argc, char **argv)
11961{
11962 char *name;
11963
11964 if (!funcnest)
11965 error("Not in a function");
11966 while ((name = *argptr++) != NULL) {
11967 mklocal(name);
11968 }
11969 return 0;
11970}
11971
11972
11973/*
11974 * Make a variable a local variable. When a variable is made local, it's 11992 * Make a variable a local variable. When a variable is made local, it's
11975 * value and flags are saved in a localvar structure. The saved values 11993 * value and flags are saved in a localvar structure. The saved values
11976 * will be restored when the shell function returns. We handle the name 11994 * will be restored when the shell function returns. We handle the name
11977 * "-" as a special case. 11995 * "-" as a special case.
11978 */ 11996 */
11979 11997
11980static void mklocal(char *name) 11998static inline void
11999mklocal(char *name)
11981{ 12000{
11982 struct localvar *lvp; 12001 struct localvar *lvp;
11983 struct var **vpp; 12002 struct var **vpp;
11984 struct var *vp; 12003 struct var *vp;
11985 12004
11986 INTOFF; 12005 INTOFF;
11987 lvp = xmalloc(sizeof(struct localvar)); 12006 lvp = ckmalloc(sizeof (struct localvar));
11988 if (name[0] == '-' && name[1] == '\0') { 12007 if (name[0] == '-' && name[1] == '\0') {
11989 char *p; 12008 char *p;
11990 12009 p = ckmalloc(sizeof(optlist));
11991 p = xmalloc(sizeof optet_vals); 12010 lvp->text = memcpy(p, optlist, sizeof(optlist));
11992 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
11993 vp = NULL; 12011 vp = NULL;
11994 } else { 12012 } else {
12013 char *eq;
12014
11995 vpp = hashvar(name); 12015 vpp = hashvar(name);
11996 vp = *findvar(vpp, name); 12016 vp = *findvar(vpp, name);
12017 eq = strchr(name, '=');
11997 if (vp == NULL) { 12018 if (vp == NULL) {
11998 if (strchr(name, '=')) 12019 if (eq)
11999 setvareq(bb_xstrdup(name), VSTRFIXED); 12020 setvareq(name, VSTRFIXED);
12000 else 12021 else
12001 setvar(name, NULL, VSTRFIXED); 12022 setvar(name, NULL, VSTRFIXED);
12002 vp = *vpp; /* the new variable */ 12023 vp = *vpp; /* the new variable */
12003 lvp->text = NULL;
12004 lvp->flags = VUNSET; 12024 lvp->flags = VUNSET;
12005 } else { 12025 } else {
12006 lvp->text = vp->text; 12026 lvp->text = vp->text;
12007 lvp->flags = vp->flags; 12027 lvp->flags = vp->flags;
12008 vp->flags |= VSTRFIXED | VTEXTFIXED; 12028 vp->flags |= VSTRFIXED|VTEXTFIXED;
12009 if (strchr(name, '=')) 12029 if (eq)
12010 setvareq(bb_xstrdup(name), 0); 12030 setvareq(name, 0);
12011 } 12031 }
12012 } 12032 }
12013 lvp->vp = vp; 12033 lvp->vp = vp;
@@ -12016,12 +12036,32 @@ static void mklocal(char *name)
12016 INTON; 12036 INTON;
12017} 12037}
12018 12038
12039/*
12040 * The "local" command.
12041 */
12042
12043static int
12044localcmd(int argc, char **argv)
12045{
12046 char *name;
12047
12048 argv = argptr;
12049 while ((name = *argv++) != NULL) {
12050 mklocal(name);
12051 }
12052 return 0;
12053}
12054
12055
12056
12019 12057
12020/* 12058/*
12021 * Called after a function returns. 12059 * Called after a function returns.
12060 * Interrupts must be off.
12022 */ 12061 */
12023 12062
12024static void poplocalvars() 12063static void
12064poplocalvars(void)
12025{ 12065{
12026 struct localvar *lvp; 12066 struct localvar *lvp;
12027 struct var *vp; 12067 struct var *vp;
@@ -12029,64 +12069,55 @@ static void poplocalvars()
12029 while ((lvp = localvars) != NULL) { 12069 while ((lvp = localvars) != NULL) {
12030 localvars = lvp->next; 12070 localvars = lvp->next;
12031 vp = lvp->vp; 12071 vp = lvp->vp;
12032 if (vp == NULL) { /* $- saved */ 12072 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12033 memcpy(optet_vals, lvp->text, sizeof optet_vals); 12073 if (vp == NULL) { /* $- saved */
12034 free(lvp->text); 12074 memcpy(optlist, lvp->text, sizeof(optlist));
12035 } else if ((lvp->flags & (VUNSET | VSTRFIXED)) == VUNSET) { 12075 ckfree(lvp->text);
12036 (void) unsetvar(vp->text); 12076 optschanged();
12077 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12078 unsetvar(vp->text);
12037 } else { 12079 } else {
12038 if ((vp->flags & VTEXTFIXED) == 0) 12080 if (vp->func)
12039 free(vp->text); 12081 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12082 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12083 ckfree(vp->text);
12040 vp->flags = lvp->flags; 12084 vp->flags = lvp->flags;
12041 vp->text = lvp->text; 12085 vp->text = lvp->text;
12042 } 12086 }
12043 free(lvp); 12087 ckfree(lvp);
12044 } 12088 }
12045} 12089}
12046 12090
12047 12091
12048static int setvarcmd(int argc, char **argv)
12049{
12050 if (argc <= 2)
12051 return unsetcmd(argc, argv);
12052 else if (argc == 3)
12053 setvar(argv[1], argv[2], 0);
12054 else
12055 error("List assignment not implemented");
12056 return 0;
12057}
12058
12059
12060/* 12092/*
12061 * The unset builtin command. We unset the function before we unset the 12093 * The unset builtin command. We unset the function before we unset the
12062 * variable to allow a function to be unset when there is a readonly variable 12094 * variable to allow a function to be unset when there is a readonly variable
12063 * with the same name. 12095 * with the same name.
12064 */ 12096 */
12065 12097
12066static int unsetcmd(int argc, char **argv) 12098int
12099unsetcmd(int argc, char **argv)
12067{ 12100{
12068 char **ap; 12101 char **ap;
12069 int i; 12102 int i;
12070 int flg_func = 0; 12103 int flag = 0;
12071 int flg_var = 0;
12072 int ret = 0; 12104 int ret = 0;
12073 12105
12074 while ((i = nextopt("vf")) != '\0') { 12106 while ((i = nextopt("vf")) != '\0') {
12075 if (i == 'f') 12107 flag = i;
12076 flg_func = 1;
12077 else
12078 flg_var = 1;
12079 } 12108 }
12080 if (flg_func == 0 && flg_var == 0)
12081 flg_var = 1;
12082 12109
12083 for (ap = argptr; *ap; ap++) { 12110 for (ap = argptr; *ap ; ap++) {
12084 if (flg_func) 12111 if (flag != 'f') {
12112 i = unsetvar(*ap);
12113 ret |= i;
12114 if (!(i & 2))
12115 continue;
12116 }
12117 if (flag != 'v')
12085 unsetfunc(*ap); 12118 unsetfunc(*ap);
12086 if (flg_var)
12087 ret |= unsetvar(*ap);
12088 } 12119 }
12089 return ret; 12120 return ret & 1;
12090} 12121}
12091 12122
12092 12123
@@ -12094,32 +12125,41 @@ static int unsetcmd(int argc, char **argv)
12094 * Unset the specified variable. 12125 * Unset the specified variable.
12095 */ 12126 */
12096 12127
12097static int unsetvar(const char *s) 12128int
12129unsetvar(const char *s)
12098{ 12130{
12099 struct var **vpp; 12131 struct var **vpp;
12100 struct var *vp; 12132 struct var *vp;
12133 int retval;
12101 12134
12102 vpp = findvar(hashvar(s), s); 12135 vpp = findvar(hashvar(s), s);
12103 vp = *vpp; 12136 vp = *vpp;
12137 retval = 2;
12104 if (vp) { 12138 if (vp) {
12105 if (vp->flags & VREADONLY) 12139 int flags = vp->flags;
12106 return (1); 12140
12107 INTOFF; 12141 retval = 1;
12108 if (*(strchr(vp->text, '=') + 1) != '\0') 12142 if (flags & VREADONLY)
12109 setvar(s, nullstr, 0); 12143 goto out;
12110 vp->flags &= ~VEXPORT; 12144 if (flags & VUNSET)
12111 vp->flags |= VUNSET; 12145 goto ok;
12112 if ((vp->flags & VSTRFIXED) == 0) { 12146 if ((flags & VSTRFIXED) == 0) {
12113 if ((vp->flags & VTEXTFIXED) == 0) 12147 INTOFF;
12114 free(vp->text); 12148 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12149 ckfree(vp->text);
12115 *vpp = vp->next; 12150 *vpp = vp->next;
12116 free(vp); 12151 ckfree(vp);
12152 INTON;
12153 } else {
12154 setvar(s, 0, 0);
12155 vp->flags &= ~VEXPORT;
12117 } 12156 }
12118 INTON; 12157ok:
12119 return (0); 12158 retval = 0;
12120 } 12159 }
12121 12160
12122 return (0); 12161out:
12162 return retval;
12123} 12163}
12124 12164
12125 12165
@@ -12128,7 +12168,8 @@ static int unsetvar(const char *s)
12128 * Find the appropriate entry in the hash table from the name. 12168 * Find the appropriate entry in the hash table from the name.
12129 */ 12169 */
12130 12170
12131static struct var **hashvar(const char *p) 12171static struct var **
12172hashvar(const char *p)
12132{ 12173{
12133 unsigned int hashval; 12174 unsigned int hashval;
12134 12175
@@ -12141,46 +12182,38 @@ static struct var **hashvar(const char *p)
12141 12182
12142 12183
12143/* 12184/*
12144 * Returns true if the two strings specify the same varable. The first 12185 * Compares two strings up to the first = or '\0'. The first
12145 * variable name is terminated by '='; the second may be terminated by 12186 * string must be terminated by '='; the second may be terminated by
12146 * either '=' or '\0'. 12187 * either '=' or '\0'.
12147 */ 12188 */
12148 12189
12149static int varequal(const char *p, const char *q) 12190int
12191varcmp(const char *p, const char *q)
12150{ 12192{
12151 while (*p == *q++) { 12193 int c, d;
12152 if (*p++ == '=') 12194
12153 return 1; 12195 while ((c = *p) == (d = *q)) {
12196 if (!c || c == '=')
12197 goto out;
12198 p++;
12199 q++;
12154 } 12200 }
12155 if (*p == '=' && *(q - 1) == '\0') 12201 if (c == '=')
12156 return 1; 12202 c = 0;
12157 return 0; 12203 if (d == '=')
12204 d = 0;
12205out:
12206 return c - d;
12158} 12207}
12159 12208
12160static void showvars(const char *myprefix, int mask, int xor) 12209static int
12210vpcmp(const void *a, const void *b)
12161{ 12211{
12162 struct var **vpp; 12212 return varcmp(*(const char **)a, *(const char **)b);
12163 struct var *vp;
12164 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12165
12166 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
12167 for (vp = *vpp; vp; vp = vp->next) {
12168 if ((vp->flags & mask) ^ xor) {
12169 char *p;
12170 int len;
12171
12172 p = strchr(vp->text, '=') + 1;
12173 len = p - vp->text;
12174 p = single_quote(p);
12175
12176 printf("%s%s%.*s%s\n", myprefix, sep, len, vp->text, p);
12177 stunalloc(p);
12178 }
12179 }
12180 }
12181} 12213}
12182 12214
12183static struct var **findvar(struct var **vpp, const char *name) 12215static struct var **
12216findvar(struct var **vpp, const char *name)
12184{ 12217{
12185 for (; *vpp; vpp = &(*vpp)->next) { 12218 for (; *vpp; vpp = &(*vpp)->next) {
12186 if (varequal((*vpp)->text, name)) { 12219 if (varequal((*vpp)->text, name)) {
@@ -12189,68 +12222,420 @@ static struct var **findvar(struct var **vpp, const char *name)
12189 } 12222 }
12190 return vpp; 12223 return vpp;
12191} 12224}
12225/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12192 12226
12193/* 12227/*
12194 * Copyright (c) 1999 Herbert Xu <herbert@debian.org> 12228 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12195 * This file contains code for the times builtin. 12229 * This code for the times builtin.
12196 */ 12230 */
12197static int timescmd(int argc, char **argv) 12231
12198{ 12232#include <sys/times.h>
12233
12234int timescmd(int ac, char **av) {
12199 struct tms buf; 12235 struct tms buf;
12200 long int clk_tck = sysconf(_SC_CLK_TCK); 12236 long int clk_tck = sysconf(_SC_CLK_TCK);
12201 12237
12202 times(&buf); 12238 times(&buf);
12203 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", 12239 out1fmt("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12204 (int) (buf.tms_utime / clk_tck / 60), 12240 (int) (buf.tms_utime / clk_tck / 60),
12205 ((double) buf.tms_utime) / clk_tck, 12241 ((double) buf.tms_utime) / clk_tck,
12206 (int) (buf.tms_stime / clk_tck / 60), 12242 (int) (buf.tms_stime / clk_tck / 60),
12207 ((double) buf.tms_stime) / clk_tck, 12243 ((double) buf.tms_stime) / clk_tck,
12208 (int) (buf.tms_cutime / clk_tck / 60), 12244 (int) (buf.tms_cutime / clk_tck / 60),
12209 ((double) buf.tms_cutime) / clk_tck, 12245 ((double) buf.tms_cutime) / clk_tck,
12210 (int) (buf.tms_cstime / clk_tck / 60), 12246 (int) (buf.tms_cstime / clk_tck / 60),
12211 ((double) buf.tms_cstime) / clk_tck); 12247 ((double) buf.tms_cstime) / clk_tck);
12212 return 0; 12248 return 0;
12213} 12249}
12214 12250
12215#ifdef CONFIG_ASH_MATH_SUPPORT 12251#ifdef CONFIG_ASH_MATH_SUPPORT
12216/* The let builtin. */ 12252static int
12217int letcmd(int argc, char **argv) 12253dash_arith(const char *s)
12218{ 12254{
12219 int errcode;
12220 long result = 0; 12255 long result = 0;
12256 int errcode = 0;
12221 12257
12222 if (argc == 2) { 12258 INTOFF;
12223 char *tmp, *expression, p[13]; 12259 result = arith(s, &errcode);
12260 if (errcode < 0) {
12261 if (errcode == -2)
12262 error("divide by zero");
12263 else
12264 synerror(s);
12265 }
12266 INTON;
12224 12267
12225 expression = strchr(argv[1], '='); 12268 return (result);
12226 if (!expression) { 12269}
12227 /* Cannot use 'error()' here, or the return code 12270
12228 * will be incorrect */ 12271
12229 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]); 12272/*
12230 return 0; 12273 * The exp(1) builtin.
12274 */
12275static int
12276expcmd(int argc, char **argv)
12277{
12278 const char *p;
12279 char *concat;
12280 char **ap;
12281 long i;
12282
12283 if (argc > 1) {
12284 p = argv[1];
12285 if (argc > 2) {
12286 /*
12287 * concatenate arguments
12288 */
12289 STARTSTACKSTR(concat);
12290 ap = argv + 2;
12291 for (;;) {
12292 while (*p)
12293 STPUTC(*p++, concat);
12294 if ((p = *ap++) == NULL)
12295 break;
12296 STPUTC(' ', concat);
12297 }
12298 STPUTC('\0', concat);
12299 p = grabstackstr(concat);
12231 } 12300 }
12232 *expression = '\0'; 12301 } else
12233 tmp = ++expression; 12302 p = nullstr;
12234 result = arith(tmp, &errcode); 12303
12235 if (errcode < 0) { 12304 i = dash_arith(p);
12236 /* Cannot use 'error()' here, or the return code 12305
12237 * will be incorrect */ 12306 out1fmt("%ld\n", i);
12238 out2fmt("sh: let: "); 12307 return (! i);
12239 if (errcode == -2) 12308}
12240 out2fmt("divide by zero"); 12309#endif /* CONFIG_ASH_MATH_SUPPORT */
12241 else 12310
12242 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression); 12311/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12243 return 0; 12312
12313/*
12314 * Miscelaneous builtins.
12315 */
12316
12317#undef rflag
12318
12319#ifdef __GLIBC__
12320#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12321typedef enum __rlimit_resource rlim_t;
12322#endif
12323#endif
12324
12325
12326/*
12327 * The read builtin. The -e option causes backslashes to escape the
12328 * following character.
12329 *
12330 * This uses unbuffered input, which may be avoidable in some cases.
12331 */
12332
12333static int
12334readcmd(int argc, char **argv)
12335{
12336 char **ap;
12337 int backslash;
12338 char c;
12339 int rflag;
12340 char *prompt;
12341 const char *ifs;
12342 char *p;
12343 int startword;
12344 int status;
12345 int i;
12346
12347 rflag = 0;
12348 prompt = NULL;
12349 while ((i = nextopt("p:r")) != '\0') {
12350 if (i == 'p')
12351 prompt = optionarg;
12352 else
12353 rflag = 1;
12354 }
12355 if (prompt && isatty(0)) {
12356 out2str(prompt);
12357 flushall();
12358 }
12359 if (*(ap = argptr) == NULL)
12360 error("arg count");
12361 if ((ifs = bltinlookup("IFS")) == NULL)
12362 ifs = defifs;
12363 status = 0;
12364 startword = 1;
12365 backslash = 0;
12366 STARTSTACKSTR(p);
12367 for (;;) {
12368 if (read(0, &c, 1) != 1) {
12369 status = 1;
12370 break;
12371 }
12372 if (c == '\0')
12373 continue;
12374 if (backslash) {
12375 backslash = 0;
12376 if (c != '\n')
12377 goto put;
12378 continue;
12379 }
12380 if (!rflag && c == '\\') {
12381 backslash++;
12382 continue;
12383 }
12384 if (c == '\n')
12385 break;
12386 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12387 continue;
12388 }
12389 startword = 0;
12390 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12391 STACKSTRNUL(p);
12392 setvar(*ap, stackblock(), 0);
12393 ap++;
12394 startword = 1;
12395 STARTSTACKSTR(p);
12396 } else {
12397put:
12398 STPUTC(c, p);
12399 }
12400 }
12401 STACKSTRNUL(p);
12402 /* Remove trailing blanks */
12403 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12404 *p = '\0';
12405 setvar(*ap, stackblock(), 0);
12406 while (*++ap != NULL)
12407 setvar(*ap, nullstr, 0);
12408 return status;
12409}
12410
12411
12412static int umaskcmd(int argc, char **argv)
12413{
12414 static const char permuser[3] = "ugo";
12415 static const char permmode[3] = "rwx";
12416 static const short int permmask[] = {
12417 S_IRUSR, S_IWUSR, S_IXUSR,
12418 S_IRGRP, S_IWGRP, S_IXGRP,
12419 S_IROTH, S_IWOTH, S_IXOTH
12420 };
12421
12422 char *ap;
12423 mode_t mask;
12424 int i;
12425 int symbolic_mode = 0;
12426
12427 while (nextopt("S") != '\0') {
12428 symbolic_mode = 1;
12429 }
12430
12431 INTOFF;
12432 mask = umask(0);
12433 umask(mask);
12434 INTON;
12435
12436 if ((ap = *argptr) == NULL) {
12437 if (symbolic_mode) {
12438 char buf[18];
12439 char *p = buf;
12440
12441 for (i = 0; i < 3; i++) {
12442 int j;
12443
12444 *p++ = permuser[i];
12445 *p++ = '=';
12446 for (j = 0; j < 3; j++) {
12447 if ((mask & permmask[3 * i + j]) == 0) {
12448 *p++ = permmode[j];
12449 }
12450 }
12451 *p++ = ',';
12452 }
12453 *--p = 0;
12454 puts(buf);
12455 } else {
12456 out1fmt("%.4o\n", mask);
12457 }
12458 } else {
12459 if (is_digit((unsigned char) *ap)) {
12460 mask = 0;
12461 do {
12462 if (*ap >= '8' || *ap < '0')
12463 error(illnum, argv[1]);
12464 mask = (mask << 3) + (*ap - '0');
12465 } while (*++ap != '\0');
12466 umask(mask);
12467 } else {
12468 mask = ~mask & 0777;
12469 if (!bb_parse_mode(ap, &mask)) {
12470 error("Illegal mode: %s", ap);
12471 }
12472 umask(~mask & 0777);
12244 } 12473 }
12245 snprintf(p, 12, "%ld", result); 12474 }
12246 setvar(argv[1], bb_xstrdup(p), 0); 12475 return 0;
12247 } else if (argc >= 3)
12248 synerror("invalid operand");
12249 return !result;
12250} 12476}
12477
12478/*
12479 * ulimit builtin
12480 *
12481 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12482 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12483 * ash by J.T. Conklin.
12484 *
12485 * Public domain.
12486 */
12487
12488struct limits {
12489 const char *name;
12490 int cmd;
12491 int factor; /* multiply by to get rlim_{cur,max} values */
12492 char option;
12493};
12494
12495static const struct limits limits[] = {
12496#ifdef RLIMIT_CPU
12497 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12498#endif
12499#ifdef RLIMIT_FSIZE
12500 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12501#endif
12502#ifdef RLIMIT_DATA
12503 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12504#endif
12505#ifdef RLIMIT_STACK
12506 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12507#endif
12508#ifdef RLIMIT_CORE
12509 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12510#endif
12511#ifdef RLIMIT_RSS
12512 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12251#endif 12513#endif
12514#ifdef RLIMIT_MEMLOCK
12515 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12516#endif
12517#ifdef RLIMIT_NPROC
12518 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
12519#endif
12520#ifdef RLIMIT_NOFILE
12521 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
12522#endif
12523#ifdef RLIMIT_VMEM
12524 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
12525#endif
12526#ifdef RLIMIT_SWAP
12527 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
12528#endif
12529 { (char *) 0, 0, 0, '\0' }
12530};
12252 12531
12532int
12533ulimitcmd(int argc, char **argv)
12534{
12535 int c;
12536 rlim_t val = 0;
12537 enum { SOFT = 0x1, HARD = 0x2 }
12538 how = SOFT | HARD;
12539 const struct limits *l;
12540 int set, all = 0;
12541 int optc, what;
12542 struct rlimit limit;
12253 12543
12544 what = 'f';
12545 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
12546 switch (optc) {
12547 case 'H':
12548 how = HARD;
12549 break;
12550 case 'S':
12551 how = SOFT;
12552 break;
12553 case 'a':
12554 all = 1;
12555 break;
12556 default:
12557 what = optc;
12558 }
12559
12560 for (l = limits; l->name && l->option != what; l++)
12561 ;
12562 if (!l->name)
12563 error("internal error (%c)", what);
12564
12565 set = *argptr ? 1 : 0;
12566 if (set) {
12567 char *p = *argptr;
12568
12569 if (all || argptr[1])
12570 error("too many arguments");
12571 if (strcmp(p, "unlimited") == 0)
12572 val = RLIM_INFINITY;
12573 else {
12574 val = (rlim_t) 0;
12575
12576 while ((c = *p++) >= '0' && c <= '9')
12577 {
12578 val = (val * 10) + (long)(c - '0');
12579 if (val < (rlim_t) 0)
12580 break;
12581 }
12582 if (c)
12583 error("bad number");
12584 val *= l->factor;
12585 }
12586 }
12587 if (all) {
12588 for (l = limits; l->name; l++) {
12589 getrlimit(l->cmd, &limit);
12590 if (how & SOFT)
12591 val = limit.rlim_cur;
12592 else if (how & HARD)
12593 val = limit.rlim_max;
12594
12595 out1fmt("%-20s ", l->name);
12596 if (val == RLIM_INFINITY)
12597 out1fmt("unlimited\n");
12598 else
12599 {
12600 val /= l->factor;
12601 out1fmt("%lld\n", (long long) val);
12602 }
12603 }
12604 return 0;
12605 }
12606
12607 getrlimit(l->cmd, &limit);
12608 if (set) {
12609 if (how & HARD)
12610 limit.rlim_max = val;
12611 if (how & SOFT)
12612 limit.rlim_cur = val;
12613 if (setrlimit(l->cmd, &limit) < 0)
12614 error("error setting limit (%m)");
12615 } else {
12616 if (how & SOFT)
12617 val = limit.rlim_cur;
12618 else if (how & HARD)
12619 val = limit.rlim_max;
12620
12621 if (val == RLIM_INFINITY)
12622 out1fmt("unlimited\n");
12623 else
12624 {
12625 val /= l->factor;
12626 out1fmt("%lld\n", (long long) val);
12627 }
12628 }
12629 return 0;
12630}
12631
12632#ifdef DEBUG
12633const char *bb_applet_name = "debug stuff usage";
12634int main(int argc, char **argv)
12635{
12636 return ash_main(argc, argv);
12637}
12638#endif
12254 12639
12255/*- 12640/*-
12256 * Copyright (c) 1989, 1991, 1993, 1994 12641 * Copyright (c) 1989, 1991, 1993, 1994
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
index 843f73fef..717067267 100644
--- a/shell/cmdedit.c
+++ b/shell/cmdedit.c
@@ -9,7 +9,7 @@
9 * Adam Rogoyski <rogoyski@cs.utexas.edu> 9 * Adam Rogoyski <rogoyski@cs.utexas.edu>
10 * Dave Cinege <dcinege@psychosis.com> 10 * Dave Cinege <dcinege@psychosis.com>
11 * Jakub Jelinek (c) 1995 11 * Jakub Jelinek (c) 1995
12 * Erik Andersen <andersen@codepoet.org> (Majorly adjusted for busybox) 12 * Erik Andersen <andersee@debian.org> (Majorly adjusted for busybox)
13 * 13 *
14 * This code is 'as is' with no warranty. 14 * This code is 'as is' with no warranty.
15 * 15 *
@@ -63,7 +63,7 @@
63 63
64#define D(x) x 64#define D(x) x
65 65
66#endif /* TEST */ 66#endif /* TEST */
67 67
68#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION 68#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
69#include <dirent.h> 69#include <dirent.h>
@@ -86,7 +86,7 @@
86# else 86# else
87# include <pwd.h> 87# include <pwd.h>
88# endif /* TEST */ 88# endif /* TEST */
89#endif /* advanced FEATURES */ 89#endif /* advanced FEATURES */
90 90
91 91
92/* Maximum length of the linked list for the command line history */ 92/* Maximum length of the linked list for the command line history */
@@ -115,30 +115,30 @@ static struct termios initial_settings, new_settings;
115 115
116 116
117static 117static
118volatile int cmdedit_termw = 80; /* actual terminal width */ 118volatile int cmdedit_termw = 80; /* actual terminal width */
119static 119static
120volatile int handlers_sets = 0; /* Set next bites: */ 120volatile int handlers_sets = 0; /* Set next bites: */
121 121
122enum { 122enum {
123 SET_ATEXIT = 1, /* when atexit() has been called 123 SET_ATEXIT = 1, /* when atexit() has been called
124 and get euid,uid,gid to fast compare */ 124 and get euid,uid,gid to fast compare */
125 SET_WCHG_HANDLERS = 2, /* winchg signal handler */ 125 SET_WCHG_HANDLERS = 2, /* winchg signal handler */
126 SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */ 126 SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */
127}; 127};
128 128
129 129
130static int cmdedit_x; /* real x terminal position */ 130static int cmdedit_x; /* real x terminal position */
131static int cmdedit_y; /* pseudoreal y terminal position */ 131static int cmdedit_y; /* pseudoreal y terminal position */
132static int cmdedit_prmt_len; /* lenght prompt without colores string */ 132static int cmdedit_prmt_len; /* lenght prompt without colores string */
133 133
134static int cursor; /* required global for signal handler */ 134static int cursor; /* required global for signal handler */
135static int len; /* --- "" - - "" - -"- --""-- --""--- */ 135static int len; /* --- "" - - "" - -"- --""-- --""--- */
136static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ 136static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */
137static 137static
138#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT 138#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
139 const 139 const
140#endif 140#endif
141char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ 141char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */
142 142
143#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR 143#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
144static char *user_buf = ""; 144static char *user_buf = "";
@@ -161,31 +161,36 @@ static int my_euid;
161static int my_uid; 161static int my_uid;
162static int my_gid; 162static int my_gid;
163 163
164#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */ 164#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
165
166/* It seems that libc5 doesn't know what a sighandler_t is... */
167#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
168typedef void (*sighandler_t) (int);
169#endif
165 170
166static void cmdedit_setwidth(int w, int redraw_flg); 171static void cmdedit_setwidth(int w, int redraw_flg);
167 172
168static void win_changed(int nsig) 173static void win_changed(int nsig)
169{ 174{
170 struct winsize win = { 0, 0, 0, 0 }; 175 struct winsize win = { 0, 0, 0, 0 };
171 static sighandler_t previous_SIGWINCH_handler; /* for reset */ 176 static sighandler_t previous_SIGWINCH_handler; /* for reset */
172 177
173 /* emulate || signal call */ 178 /* emulate || signal call */
174 if (nsig == -SIGWINCH || nsig == SIGWINCH) { 179 if (nsig == -SIGWINCH || nsig == SIGWINCH) {
175 ioctl(0, TIOCGWINSZ, &win); 180 ioctl(0, TIOCGWINSZ, &win);
176 if (win.ws_col > 0) { 181 if (win.ws_col > 0) {
177 cmdedit_setwidth(win.ws_col, nsig == SIGWINCH); 182 cmdedit_setwidth(win.ws_col, nsig == SIGWINCH);
178 } 183 }
179 } 184 }
180 /* Unix not all standart in recall signal */ 185 /* Unix not all standart in recall signal */
181 186
182 if (nsig == -SIGWINCH) /* save previous handler */ 187 if (nsig == -SIGWINCH) /* save previous handler */
183 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); 188 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
184 else if (nsig == SIGWINCH) /* signaled called handler */ 189 else if (nsig == SIGWINCH) /* signaled called handler */
185 signal(SIGWINCH, win_changed); /* set for next call */ 190 signal(SIGWINCH, win_changed); /* set for next call */
186 else /* nsig == 0 */ 191 else /* nsig == 0 */
187 /* set previous handler */ 192 /* set previous handler */
188 signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */ 193 signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */
189} 194}
190 195
191static void cmdedit_reset_term(void) 196static void cmdedit_reset_term(void)
@@ -211,9 +216,9 @@ static void cmdedit_set_out_char(int next_char)
211 int c = (int)((unsigned char) command_ps[cursor]); 216 int c = (int)((unsigned char) command_ps[cursor]);
212 217
213 if (c == 0) 218 if (c == 0)
214 c = ' '; /* destroy end char? */ 219 c = ' '; /* destroy end char? */
215#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT 220#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
216 if (!Isprint(c)) { /* Inverse put non-printable characters */ 221 if (!Isprint(c)) { /* Inverse put non-printable characters */
217 if (c >= 128) 222 if (c >= 128)
218 c -= 128; 223 c -= 128;
219 if (c < ' ') 224 if (c < ' ')
@@ -270,9 +275,9 @@ static void input_backward(int num)
270{ 275{
271 if (num > cursor) 276 if (num > cursor)
272 num = cursor; 277 num = cursor;
273 cursor -= num; /* new cursor (in command, not terminal) */ 278 cursor -= num; /* new cursor (in command, not terminal) */
274 279
275 if (cmdedit_x >= num) { /* no to up line */ 280 if (cmdedit_x >= num) { /* no to up line */
276 cmdedit_x -= num; 281 cmdedit_x -= num;
277 if (num < 4) 282 if (num < 4)
278 while (num-- > 0) 283 while (num-- > 0)
@@ -284,22 +289,22 @@ static void input_backward(int num)
284 int count_y; 289 int count_y;
285 290
286 if (cmdedit_x) { 291 if (cmdedit_x) {
287 putchar('\r'); /* back to first terminal pos. */ 292 putchar('\r'); /* back to first terminal pos. */
288 num -= cmdedit_x; /* set previous backward */ 293 num -= cmdedit_x; /* set previous backward */
289 } 294 }
290 count_y = 1 + num / cmdedit_termw; 295 count_y = 1 + num / cmdedit_termw;
291 printf("\033[%dA", count_y); 296 printf("\033[%dA", count_y);
292 cmdedit_y -= count_y; 297 cmdedit_y -= count_y;
293 /* require forward after uping */ 298 /* require forward after uping */
294 cmdedit_x = cmdedit_termw * count_y - num; 299 cmdedit_x = cmdedit_termw * count_y - num;
295 printf("\033[%dC", cmdedit_x); /* set term cursor */ 300 printf("\033[%dC", cmdedit_x); /* set term cursor */
296 } 301 }
297} 302}
298 303
299static void put_prompt(void) 304static void put_prompt(void)
300{ 305{
301 out1str(cmdedit_prompt); 306 out1str(cmdedit_prompt);
302 cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */ 307 cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */
303 cursor = 0; 308 cursor = 0;
304 cmdedit_y = 0; /* new quasireal y */ 309 cmdedit_y = 0; /* new quasireal y */
305} 310}
@@ -335,7 +340,7 @@ static void parse_prompt(const char *prmt_ptr)
335 if (c == '\\') { 340 if (c == '\\') {
336 const char *cp = prmt_ptr; 341 const char *cp = prmt_ptr;
337 int l; 342 int l;
338 343
339 c = bb_process_escape_sequence(&prmt_ptr); 344 c = bb_process_escape_sequence(&prmt_ptr);
340 if(prmt_ptr==cp) { 345 if(prmt_ptr==cp) {
341 if (*cp == 0) 346 if (*cp == 0)
@@ -346,7 +351,7 @@ static void parse_prompt(const char *prmt_ptr)
346 case 'u': 351 case 'u':
347 pbuf = user_buf; 352 pbuf = user_buf;
348 break; 353 break;
349#endif 354#endif
350 case 'h': 355 case 'h':
351 pbuf = hostname_buf; 356 pbuf = hostname_buf;
352 if (pbuf == 0) { 357 if (pbuf == 0) {
@@ -378,7 +383,7 @@ static void parse_prompt(const char *prmt_ptr)
378 strcpy(pbuf+1, pwd_buf+l); 383 strcpy(pbuf+1, pwd_buf+l);
379 } 384 }
380 break; 385 break;
381#endif 386#endif
382 case 'W': 387 case 'W':
383 pbuf = pwd_buf; 388 pbuf = pwd_buf;
384 cp = strrchr(pbuf,'/'); 389 cp = strrchr(pbuf,'/');
@@ -391,7 +396,7 @@ static void parse_prompt(const char *prmt_ptr)
391 case 'e': case 'E': /* \e \E = \033 */ 396 case 'e': case 'E': /* \e \E = \033 */
392 c = '\033'; 397 c = '\033';
393 break; 398 break;
394 case 'x': case 'X': 399 case 'x': case 'X':
395 for (l = 0; l < 3;) { 400 for (l = 0; l < 3;) {
396 int h; 401 int h;
397 buf2[l++] = *prmt_ptr; 402 buf2[l++] = *prmt_ptr;
@@ -416,7 +421,7 @@ static void parse_prompt(const char *prmt_ptr)
416 } 421 }
417 break; 422 break;
418 } 423 }
419 } 424 }
420 } 425 }
421 if(pbuf == buf) 426 if(pbuf == buf)
422 *pbuf = c; 427 *pbuf = c;
@@ -437,12 +442,12 @@ static void parse_prompt(const char *prmt_ptr)
437/* draw promt, editor line, and clear tail */ 442/* draw promt, editor line, and clear tail */
438static void redraw(int y, int back_cursor) 443static void redraw(int y, int back_cursor)
439{ 444{
440 if (y > 0) /* up to start y */ 445 if (y > 0) /* up to start y */
441 printf("\033[%dA", y); 446 printf("\033[%dA", y);
442 putchar('\r'); 447 putchar('\r');
443 put_prompt(); 448 put_prompt();
444 input_end(); /* rewrite */ 449 input_end(); /* rewrite */
445 printf("\033[J"); /* destroy tail after cursor */ 450 printf("\033[J"); /* destroy tail after cursor */
446 input_backward(back_cursor); 451 input_backward(back_cursor);
447} 452}
448 453
@@ -456,9 +461,9 @@ static void input_delete(void)
456 461
457 strcpy(command_ps + j, command_ps + j + 1); 462 strcpy(command_ps + j, command_ps + j + 1);
458 len--; 463 len--;
459 input_end(); /* rewtite new line */ 464 input_end(); /* rewtite new line */
460 cmdedit_set_out_char(0); /* destroy end char */ 465 cmdedit_set_out_char(0); /* destroy end char */
461 input_backward(cursor - j); /* back to old pos cursor */ 466 input_backward(cursor - j); /* back to old pos cursor */
462} 467}
463 468
464/* Delete the char in back of the cursor */ 469/* Delete the char in back of the cursor */
@@ -496,7 +501,7 @@ static void cmdedit_setwidth(int w, int redraw_flg)
496 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); 501 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
497 fflush(stdout); 502 fflush(stdout);
498 } 503 }
499 } 504 }
500} 505}
501 506
502static void cmdedit_init(void) 507static void cmdedit_init(void)
@@ -527,9 +532,9 @@ static void cmdedit_init(void)
527#endif 532#endif
528 my_uid = getuid(); 533 my_uid = getuid();
529 my_gid = getgid(); 534 my_gid = getgid();
530#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */ 535#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
531 handlers_sets |= SET_ATEXIT; 536 handlers_sets |= SET_ATEXIT;
532 atexit(cmdedit_reset_term); /* be sure to do this only once */ 537 atexit(cmdedit_reset_term); /* be sure to do this only once */
533 } 538 }
534} 539}
535 540
@@ -553,35 +558,35 @@ static char **username_tab_completion(char *ud, int *num_matches)
553 char *temp; 558 char *temp;
554 559
555 560
556 ud++; /* ~user/... to user/... */ 561 ud++; /* ~user/... to user/... */
557 userlen = strlen(ud); 562 userlen = strlen(ud);
558 563
559 if (num_matches == 0) { /* "~/..." or "~user/..." */ 564 if (num_matches == 0) { /* "~/..." or "~user/..." */
560 char *sav_ud = ud - 1; 565 char *sav_ud = ud - 1;
561 char *home = 0; 566 char *home = 0;
562 567
563 if (*ud == '/') { /* "~/..." */ 568 if (*ud == '/') { /* "~/..." */
564 home = home_pwd_buf; 569 home = home_pwd_buf;
565 } else { 570 } else {
566 /* "~user/..." */ 571 /* "~user/..." */
567 temp = strchr(ud, '/'); 572 temp = strchr(ud, '/');
568 *temp = 0; /* ~user\0 */ 573 *temp = 0; /* ~user\0 */
569 entry = getpwnam(ud); 574 entry = getpwnam(ud);
570 *temp = '/'; /* restore ~user/... */ 575 *temp = '/'; /* restore ~user/... */
571 ud = temp; 576 ud = temp;
572 if (entry) 577 if (entry)
573 home = entry->pw_dir; 578 home = entry->pw_dir;
574 } 579 }
575 if (home) { 580 if (home) {
576 if ((userlen + strlen(home) + 1) < BUFSIZ) { 581 if ((userlen + strlen(home) + 1) < BUFSIZ) {
577 char temp2[BUFSIZ]; /* argument size */ 582 char temp2[BUFSIZ]; /* argument size */
578 583
579 /* /home/user/... */ 584 /* /home/user/... */
580 sprintf(temp2, "%s%s", home, ud); 585 sprintf(temp2, "%s%s", home, ud);
581 strcpy(sav_ud, temp2); 586 strcpy(sav_ud, temp2);
582 } 587 }
583 } 588 }
584 return 0; /* void, result save to argument :-) */ 589 return 0; /* void, result save to argument :-) */
585 } else { 590 } else {
586 /* "~[^/]*" */ 591 /* "~[^/]*" */
587 char **matches = (char **) NULL; 592 char **matches = (char **) NULL;
@@ -593,7 +598,7 @@ static char **username_tab_completion(char *ud, int *num_matches)
593 /* Null usernames should result in all users as possible completions. */ 598 /* Null usernames should result in all users as possible completions. */
594 if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) { 599 if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
595 600
596 bb_xasprintf(&temp, "~%s/", entry->pw_name); 601 bb_xasprintf(&temp, "~%s/", entry->pw_name);
597 matches = xrealloc(matches, (nm + 1) * sizeof(char *)); 602 matches = xrealloc(matches, (nm + 1) * sizeof(char *));
598 603
599 matches[nm++] = temp; 604 matches[nm++] = temp;
@@ -605,7 +610,7 @@ static char **username_tab_completion(char *ud, int *num_matches)
605 return (matches); 610 return (matches);
606 } 611 }
607} 612}
608#endif /* CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION */ 613#endif /* CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION */
609 614
610enum { 615enum {
611 FIND_EXE_ONLY = 0, 616 FIND_EXE_ONLY = 0,
@@ -630,11 +635,11 @@ static int path_parse(char ***p, int flags)
630 npth = 0; 635 npth = 0;
631 636
632 for (;;) { 637 for (;;) {
633 npth++; /* count words is + 1 count ':' */ 638 npth++; /* count words is + 1 count ':' */
634 tmp = strchr(tmp, ':'); 639 tmp = strchr(tmp, ':');
635 if (tmp) { 640 if (tmp) {
636 if (*++tmp == 0) 641 if (*++tmp == 0)
637 break; /* :<empty> */ 642 break; /* :<empty> */
638 } else 643 } else
639 break; 644 break;
640 } 645 }
@@ -643,17 +648,17 @@ static int path_parse(char ***p, int flags)
643 648
644 tmp = pth; 649 tmp = pth;
645 (*p)[0] = bb_xstrdup(tmp); 650 (*p)[0] = bb_xstrdup(tmp);
646 npth = 1; /* count words is + 1 count ':' */ 651 npth = 1; /* count words is + 1 count ':' */
647 652
648 for (;;) { 653 for (;;) {
649 tmp = strchr(tmp, ':'); 654 tmp = strchr(tmp, ':');
650 if (tmp) { 655 if (tmp) {
651 (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ 656 (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */
652 if (*++tmp == 0) 657 if (*++tmp == 0)
653 break; /* :<empty> */ 658 break; /* :<empty> */
654 } else 659 } else
655 break; 660 break;
656 (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ 661 (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */
657 } 662 }
658 663
659 return npth; 664 return npth;
@@ -703,20 +708,20 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches,
703 /* set dir only */ 708 /* set dir only */
704 dirbuf[(pfind - command) + 1] = 0; 709 dirbuf[(pfind - command) + 1] = 0;
705#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION 710#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
706 if (dirbuf[0] == '~') /* ~/... or ~user/... */ 711 if (dirbuf[0] == '~') /* ~/... or ~user/... */
707 username_tab_completion(dirbuf, 0); 712 username_tab_completion(dirbuf, 0);
708#endif 713#endif
709 /* "strip" dirname in command */ 714 /* "strip" dirname in command */
710 pfind++; 715 pfind++;
711 716
712 paths[0] = dirbuf; 717 paths[0] = dirbuf;
713 npaths = 1; /* only 1 dir */ 718 npaths = 1; /* only 1 dir */
714 } 719 }
715 720
716 for (i = 0; i < npaths; i++) { 721 for (i = 0; i < npaths; i++) {
717 722
718 dir = opendir(paths[i]); 723 dir = opendir(paths[i]);
719 if (!dir) /* Don't print an error */ 724 if (!dir) /* Don't print an error */
720 continue; 725 continue;
721 726
722 while ((next = readdir(dir)) != NULL) { 727 while ((next = readdir(dir)) != NULL) {
@@ -728,17 +733,17 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches,
728 /* not see .name without .match */ 733 /* not see .name without .match */
729 if (*str_found == '.' && *pfind == 0) { 734 if (*str_found == '.' && *pfind == 0) {
730 if (*paths[i] == '/' && paths[i][1] == 0 735 if (*paths[i] == '/' && paths[i][1] == 0
731 && str_found[1] == 0) str_found = ""; /* only "/" */ 736 && str_found[1] == 0) str_found = ""; /* only "/" */
732 else 737 else
733 continue; 738 continue;
734 } 739 }
735 found = concat_path_file(paths[i], str_found); 740 found = concat_path_file(paths[i], str_found);
736 /* hmm, remover in progress? */ 741 /* hmm, remover in progress? */
737 if (stat(found, &st) < 0) 742 if (stat(found, &st) < 0)
738 goto cont; 743 goto cont;
739 /* find with dirs ? */ 744 /* find with dirs ? */
740 if (paths[i] != dirbuf) 745 if (paths[i] != dirbuf)
741 strcpy(found, next->d_name); /* only name */ 746 strcpy(found, next->d_name); /* only name */
742 if (S_ISDIR(st.st_mode)) { 747 if (S_ISDIR(st.st_mode)) {
743 /* name is directory */ 748 /* name is directory */
744 str_found = found; 749 str_found = found;
@@ -747,7 +752,7 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches,
747 str_found = add_quote_for_spec_chars(found); 752 str_found = add_quote_for_spec_chars(found);
748 } else { 753 } else {
749 /* not put found file if search only dirs for cd */ 754 /* not put found file if search only dirs for cd */
750 if (type == FIND_DIR_ONLY) 755 if (type == FIND_DIR_ONLY)
751 goto cont; 756 goto cont;
752 str_found = add_quote_for_spec_chars(found); 757 str_found = add_quote_for_spec_chars(found);
753 if (type == FIND_FILE_ONLY || 758 if (type == FIND_FILE_ONLY ||
@@ -764,7 +769,7 @@ cont:
764 closedir(dir); 769 closedir(dir);
765 } 770 }
766 if (paths != path1) { 771 if (paths != path1) {
767 free(paths[0]); /* allocated memory only in first member */ 772 free(paths[0]); /* allocated memory only in first member */
768 free(paths); 773 free(paths);
769 } 774 }
770 *num_matches = nm; 775 *num_matches = nm;
@@ -796,7 +801,7 @@ static int find_match(char *matchBuf, int *len_with_quotes)
796 for (i = 0;; i++) { 801 for (i = 0;; i++) {
797 int_buf[i] = (int) ((unsigned char) matchBuf[i]); 802 int_buf[i] = (int) ((unsigned char) matchBuf[i]);
798 if (int_buf[i] == 0) { 803 if (int_buf[i] == 0) {
799 pos_buf[i] = -1; /* indicator end line */ 804 pos_buf[i] = -1; /* indicator end line */
800 break; 805 break;
801 } else 806 } else
802 pos_buf[i] = i; 807 pos_buf[i] = i;
@@ -809,7 +814,7 @@ static int find_match(char *matchBuf, int *len_with_quotes)
809 int_buf[j] |= QUOT; 814 int_buf[j] |= QUOT;
810 i++; 815 i++;
811#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT 816#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
812 if (matchBuf[i] == '\t') /* algorithm equivalent */ 817 if (matchBuf[i] == '\t') /* algorithm equivalent */
813 int_buf[j] = ' ' | QUOT; 818 int_buf[j] = ' ' | QUOT;
814#endif 819#endif
815 } 820 }
@@ -852,7 +857,7 @@ static int find_match(char *matchBuf, int *len_with_quotes)
852 } 857 }
853 if (command_mode) { 858 if (command_mode) {
854 collapse_pos(0, i + command_mode); 859 collapse_pos(0, i + command_mode);
855 i = -1; /* hack incremet */ 860 i = -1; /* hack incremet */
856 } 861 }
857 } 862 }
858 /* collapse `command...` */ 863 /* collapse `command...` */
@@ -869,11 +874,11 @@ static int find_match(char *matchBuf, int *len_with_quotes)
869 collapse_pos(0, i + 1); 874 collapse_pos(0, i + 1);
870 break; 875 break;
871 } else 876 } else
872 i--; /* hack incremet */ 877 i--; /* hack incremet */
873 } 878 }
874 879
875 /* collapse (command...(command...)...) or {command...{command...}...} */ 880 /* collapse (command...(command...)...) or {command...{command...}...} */
876 c = 0; /* "recursive" level */ 881 c = 0; /* "recursive" level */
877 c2 = 0; 882 c2 = 0;
878 for (i = 0; int_buf[i]; i++) 883 for (i = 0; int_buf[i]; i++)
879 if (int_buf[i] == '(' || int_buf[i] == '{') { 884 if (int_buf[i] == '(' || int_buf[i] == '{') {
@@ -882,7 +887,7 @@ static int find_match(char *matchBuf, int *len_with_quotes)
882 else 887 else
883 c2++; 888 c2++;
884 collapse_pos(0, i + 1); 889 collapse_pos(0, i + 1);
885 i = -1; /* hack incremet */ 890 i = -1; /* hack incremet */
886 } 891 }
887 for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) 892 for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
888 if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) { 893 if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
@@ -891,7 +896,7 @@ static int find_match(char *matchBuf, int *len_with_quotes)
891 else 896 else
892 c2--; 897 c2--;
893 collapse_pos(0, i + 1); 898 collapse_pos(0, i + 1);
894 i = -1; /* hack incremet */ 899 i = -1; /* hack incremet */
895 } 900 }
896 901
897 /* skip first not quote space */ 902 /* skip first not quote space */
@@ -927,7 +932,7 @@ static int find_match(char *matchBuf, int *len_with_quotes)
927 /* skip first not quoted '\'' or '"' */ 932 /* skip first not quoted '\'' or '"' */
928 for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++); 933 for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++);
929 /* collapse quote or unquote // or /~ */ 934 /* collapse quote or unquote // or /~ */
930 while ((int_buf[i] & ~QUOT) == '/' && 935 while ((int_buf[i] & ~QUOT) == '/' &&
931 ((int_buf[i + 1] & ~QUOT) == '/' 936 ((int_buf[i + 1] & ~QUOT) == '/'
932 || (int_buf[i + 1] & ~QUOT) == '~')) { 937 || (int_buf[i + 1] & ~QUOT) == '~')) {
933 i++; 938 i++;
@@ -991,7 +996,7 @@ static void input_tab(int *lastWasTab)
991 static int num_matches; 996 static int num_matches;
992 static char **matches; 997 static char **matches;
993 998
994 if (lastWasTab == 0) { /* free all memory */ 999 if (lastWasTab == 0) { /* free all memory */
995 if (matches) { 1000 if (matches) {
996 while (num_matches > 0) 1001 while (num_matches > 0)
997 free(matches[--num_matches]); 1002 free(matches[--num_matches]);
@@ -1008,7 +1013,7 @@ static void input_tab(int *lastWasTab)
1008 int find_type; 1013 int find_type;
1009 int recalc_pos; 1014 int recalc_pos;
1010 1015
1011 *lastWasTab = TRUE; /* flop trigger */ 1016 *lastWasTab = TRUE; /* flop trigger */
1012 1017
1013 /* Make a local copy of the string -- up 1018 /* Make a local copy of the string -- up
1014 * to the position of the cursor */ 1019 * to the position of the cursor */
@@ -1061,7 +1066,7 @@ static void input_tab(int *lastWasTab)
1061 1066
1062 beep(); 1067 beep();
1063 if (!matches) 1068 if (!matches)
1064 return; /* not found */ 1069 return; /* not found */
1065 /* sort */ 1070 /* sort */
1066 qsort(matches, num_matches, sizeof(char *), match_compare); 1071 qsort(matches, num_matches, sizeof(char *), match_compare);
1067 1072
@@ -1073,11 +1078,11 @@ static void input_tab(int *lastWasTab)
1073 *tmp1 = 0; 1078 *tmp1 = 0;
1074 break; 1079 break;
1075 } 1080 }
1076 if (*tmp == 0) { /* have unique */ 1081 if (*tmp == 0) { /* have unique */
1077 free(tmp); 1082 free(tmp);
1078 return; 1083 return;
1079 } 1084 }
1080 } else { /* one match */ 1085 } else { /* one match */
1081 tmp = matches[0]; 1086 tmp = matches[0];
1082 /* for next completion current found */ 1087 /* for next completion current found */
1083 *lastWasTab = FALSE; 1088 *lastWasTab = FALSE;
@@ -1111,7 +1116,7 @@ static void input_tab(int *lastWasTab)
1111 * just hit TAB again, print a list of all the 1116 * just hit TAB again, print a list of all the
1112 * available choices... */ 1117 * available choices... */
1113 if (matches && num_matches > 0) { 1118 if (matches && num_matches > 0) {
1114 int sav_cursor = cursor; /* change goto_new_line() */ 1119 int sav_cursor = cursor; /* change goto_new_line() */
1115 1120
1116 /* Go to the next line */ 1121 /* Go to the next line */
1117 goto_new_line(); 1122 goto_new_line();
@@ -1120,7 +1125,7 @@ static void input_tab(int *lastWasTab)
1120 } 1125 }
1121 } 1126 }
1122} 1127}
1123#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */ 1128#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
1124 1129
1125#if MAX_HISTORY >= 1 1130#if MAX_HISTORY >= 1
1126static void get_previous_history(void) 1131static void get_previous_history(void)
@@ -1159,7 +1164,7 @@ extern void load_history ( const char *fromfile )
1159 } 1164 }
1160 1165
1161 if (( fp = fopen ( fromfile, "r" ))) { 1166 if (( fp = fopen ( fromfile, "r" ))) {
1162 1167
1163 for ( hi = 0; hi < MAX_HISTORY; ) { 1168 for ( hi = 0; hi < MAX_HISTORY; ) {
1164 char * hl = bb_get_chomped_line_from_file(fp); 1169 char * hl = bb_get_chomped_line_from_file(fp);
1165 int l; 1170 int l;
@@ -1183,10 +1188,10 @@ extern void load_history ( const char *fromfile )
1183extern void save_history ( const char *tofile ) 1188extern void save_history ( const char *tofile )
1184{ 1189{
1185 FILE *fp = fopen ( tofile, "w" ); 1190 FILE *fp = fopen ( tofile, "w" );
1186 1191
1187 if ( fp ) { 1192 if ( fp ) {
1188 int i; 1193 int i;
1189 1194
1190 for ( i = 0; i < n_history; i++ ) { 1195 for ( i = 0; i < n_history; i++ ) {
1191 fputs ( history [i], fp ); 1196 fputs ( history [i], fp );
1192 fputc ( '\n', fp ); 1197 fputc ( '\n', fp );
@@ -1220,7 +1225,7 @@ enum {
1220 * Furthermore, the "vi" command editing keys are not implemented. 1225 * Furthermore, the "vi" command editing keys are not implemented.
1221 * 1226 *
1222 */ 1227 */
1223 1228
1224 1229
1225int cmdedit_read_input(char *prompt, char command[BUFSIZ]) 1230int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1226{ 1231{
@@ -1230,7 +1235,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1230 unsigned char c = 0; 1235 unsigned char c = 0;
1231 1236
1232 /* prepare before init handlers */ 1237 /* prepare before init handlers */
1233 cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ 1238 cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */
1234 len = 0; 1239 len = 0;
1235 command_ps = command; 1240 command_ps = command;
1236 1241
@@ -1247,7 +1252,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1247# ifndef _POSIX_VDISABLE 1252# ifndef _POSIX_VDISABLE
1248# define _POSIX_VDISABLE '\0' 1253# define _POSIX_VDISABLE '\0'
1249# endif 1254# endif
1250 new_settings.c_cc[VINTR] = _POSIX_VDISABLE; 1255 new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
1251#endif 1256#endif
1252 command[0] = 0; 1257 command[0] = 0;
1253 1258
@@ -1261,7 +1266,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1261 1266
1262 while (1) { 1267 while (1) {
1263 1268
1264 fflush(stdout); /* buffered out to fast */ 1269 fflush(stdout); /* buffered out to fast */
1265 1270
1266 if (safe_read(0, &c, 1) < 1) 1271 if (safe_read(0, &c, 1) < 1)
1267 /* if we can't read input then exit */ 1272 /* if we can't read input then exit */
@@ -1287,8 +1292,12 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1287 goto_new_line(); 1292 goto_new_line();
1288 command[0] = 0; 1293 command[0] = 0;
1289 len = 0; 1294 len = 0;
1295#if !defined(CONFIG_ASH)
1290 lastWasTab = FALSE; 1296 lastWasTab = FALSE;
1291 put_prompt(); 1297 put_prompt();
1298#else
1299 break_out = 2;
1300#endif
1292 break; 1301 break;
1293 case 4: 1302 case 4:
1294 /* Control-d -- Delete one character, or exit 1303 /* Control-d -- Delete one character, or exit
@@ -1327,14 +1336,14 @@ prepare_to_die:
1327#endif 1336#endif
1328 break; 1337 break;
1329 case 11: 1338 case 11:
1330 /* Control-k -- clear to end of line */ 1339 /* Control-k -- clear to end of line */
1331 *(command + cursor) = 0; 1340 *(command + cursor) = 0;
1332 len = cursor; 1341 len = cursor;
1333 printf("\033[J"); 1342 printf("\033[J");
1334 break; 1343 break;
1335 case 12: 1344 case 12:
1336 /* Control-l -- clear screen */ 1345 /* Control-l -- clear screen */
1337 printf("\033[H"); 1346 printf("\033[H");
1338 redraw(0, len-cursor); 1347 redraw(0, len-cursor);
1339 break; 1348 break;
1340#if MAX_HISTORY >= 1 1349#if MAX_HISTORY >= 1
@@ -1371,7 +1380,7 @@ prepare_to_die:
1371 } 1380 }
1372 switch (c) { 1381 switch (c) {
1373#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION 1382#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
1374 case '\t': /* Alt-Tab */ 1383 case '\t': /* Alt-Tab */
1375 1384
1376 input_tab(&lastWasTab); 1385 input_tab(&lastWasTab);
1377 break; 1386 break;
@@ -1433,7 +1442,7 @@ rewrite_line:
1433 break; 1442 break;
1434 } 1443 }
1435 1444
1436 default: /* If it's regular input, do the normal thing */ 1445 default: /* If it's regular input, do the normal thing */
1437#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT 1446#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
1438 /* Control-V -- Add non-printable symbol */ 1447 /* Control-V -- Add non-printable symbol */
1439 if (c == 22) { 1448 if (c == 22) {
@@ -1445,19 +1454,19 @@ rewrite_line:
1445 } 1454 }
1446 } else 1455 } else
1447#endif 1456#endif
1448 if (!Isprint(c)) /* Skip non-printable characters */ 1457 if (!Isprint(c)) /* Skip non-printable characters */
1449 break; 1458 break;
1450 1459
1451 if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ 1460 if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */
1452 break; 1461 break;
1453 1462
1454 len++; 1463 len++;
1455 1464
1456 if (cursor == (len - 1)) { /* Append if at the end of the line */ 1465 if (cursor == (len - 1)) { /* Append if at the end of the line */
1457 *(command + cursor) = c; 1466 *(command + cursor) = c;
1458 *(command + cursor + 1) = 0; 1467 *(command + cursor + 1) = 0;
1459 cmdedit_set_out_char(0); 1468 cmdedit_set_out_char(0);
1460 } else { /* Insert otherwise */ 1469 } else { /* Insert otherwise */
1461 int sc = cursor; 1470 int sc = cursor;
1462 1471
1463 memmove(command + sc + 1, command + sc, len - sc); 1472 memmove(command + sc + 1, command + sc, len - sc);
@@ -1471,7 +1480,7 @@ rewrite_line:
1471 1480
1472 break; 1481 break;
1473 } 1482 }
1474 if (break_out) /* Enter is the command terminator, no more input. */ 1483 if (break_out) /* Enter is the command terminator, no more input. */
1475 break; 1484 break;
1476 1485
1477 if (c != '\t') 1486 if (c != '\t')
@@ -1486,7 +1495,7 @@ rewrite_line:
1486 /* cleanup may be saved current command line */ 1495 /* cleanup may be saved current command line */
1487 free(history[MAX_HISTORY]); 1496 free(history[MAX_HISTORY]);
1488 history[MAX_HISTORY] = 0; 1497 history[MAX_HISTORY] = 0;
1489 if (len) { /* no put empty line */ 1498 if (len) { /* no put empty line */
1490 int i = n_history; 1499 int i = n_history;
1491 /* After max history, remove the oldest command */ 1500 /* After max history, remove the oldest command */
1492 if (i >= MAX_HISTORY) { 1501 if (i >= MAX_HISTORY) {
@@ -1508,23 +1517,27 @@ rewrite_line:
1508 } 1517 }
1509#endif 1518#endif
1510#endif /* MAX_HISTORY >= 1 */ 1519#endif /* MAX_HISTORY >= 1 */
1511 if(break_out>0) { 1520 if(break_out == 1) {
1512 command[len++] = '\n'; /* set '\n' */ 1521 command[len++] = '\n'; /* set '\n' */
1513 command[len] = 0; 1522 command[len] = 0;
1514 } 1523 }
1515#if defined(CONFIG_FEATURE_CLEAN_UP) && defined(CONFIG_FEATURE_COMMAND_TAB_COMPLETION) 1524#if defined(CONFIG_FEATURE_CLEAN_UP) && defined(CONFIG_FEATURE_COMMAND_TAB_COMPLETION)
1516 input_tab(0); /* strong free */ 1525 input_tab(0); /* strong free */
1517#endif 1526#endif
1518#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT) 1527#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1519 free(cmdedit_prompt); 1528 free(cmdedit_prompt);
1520#endif 1529#endif
1521 cmdedit_reset_term(); 1530 cmdedit_reset_term();
1531#if !defined(CONFIG_ASH)
1522 return len; 1532 return len;
1533#else
1534 return break_out < 0 ? break_out : len;
1535#endif
1523} 1536}
1524 1537
1525 1538
1526 1539
1527#endif /* CONFIG_FEATURE_COMMAND_EDITING */ 1540#endif /* CONFIG_FEATURE_COMMAND_EDITING */
1528 1541
1529 1542
1530#ifdef TEST 1543#ifdef TEST
@@ -1565,4 +1578,4 @@ int main(int argc, char **argv)
1565 return 0; 1578 return 0;
1566} 1579}
1567 1580
1568#endif /* TEST */ 1581#endif /* TEST */