blob: a0eb4e36f73309b7c9846725b004292ad1982fc5 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +00008 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
Eric Andersen81fe1232003-07-29 06:38:40 +00009 * was re-ported from NetBSD and debianized.
10 *
11 *
Eric Andersencb57d552001-06-28 07:25:16 +000012 * This code is derived from software contributed to Berkeley by
13 * Kenneth Almquist.
14 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +000015 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersendf82f612001-06-28 07:46:40 +000016 *
Eric Andersen81fe1232003-07-29 06:38:40 +000017 * Original BSD copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000018 */
19
Eric Andersenc470f442003-07-28 09:56:35 +000020/*
Eric Andersen90898442003-08-06 11:20:52 +000021 * rewrite arith.y to micro stack based cryptic algorithm by
22 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
23 *
Eric Andersenef02f822004-03-11 13:34:24 +000024 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
25 * dynamic variables.
Eric Andersen16767e22004-03-16 05:14:10 +000026 *
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000027 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
Eric Andersen16767e22004-03-16 05:14:10 +000028 * used in busybox and size optimizations,
29 * rewrote arith (see notes to this), added locale support,
30 * rewrote dynamic variables.
31 *
Eric Andersen90898442003-08-06 11:20:52 +000032 */
33
34
35/*
Eric Andersenc470f442003-07-28 09:56:35 +000036 * 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 */
Eric Andersen2870d962001-07-02 17:27:21 +000045
Eric Andersen2870d962001-07-02 17:27:21 +000046
Eric Andersen5bb16772001-09-06 18:00:41 +000047#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000048
Eric Andersenc470f442003-07-28 09:56:35 +000049#define PROFILE 0
50
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000051#include "busybox.h"
52
Eric Andersenc470f442003-07-28 09:56:35 +000053#ifdef DEBUG
54#define _GNU_SOURCE
55#endif
56
57#include <sys/types.h>
Eric Andersenc470f442003-07-28 09:56:35 +000058#include <sys/ioctl.h>
59#include <sys/param.h>
60#include <sys/resource.h>
61#include <sys/stat.h>
Eric Andersenc470f442003-07-28 09:56:35 +000062#include <sys/wait.h>
63
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67#include <unistd.h>
68
69#include <stdarg.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000070#include <stddef.h>
Eric Andersenc470f442003-07-28 09:56:35 +000071#include <assert.h>
Eric Andersencb57d552001-06-28 07:25:16 +000072#include <ctype.h>
73#include <dirent.h>
74#include <errno.h>
75#include <fcntl.h>
76#include <limits.h>
77#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000078#include <setjmp.h>
79#include <signal.h>
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000080/*#include <stdint.h>*/
Eric Andersenef02f822004-03-11 13:34:24 +000081#include <time.h>
Eric Andersenc470f442003-07-28 09:56:35 +000082#include <fnmatch.h>
Eric Andersenc470f442003-07-28 09:56:35 +000083
Eric Andersen887ca792002-07-03 23:19:26 +000084#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +000085
Eric Andersend35c5df2002-01-09 15:37:36 +000086#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000087#define JOBS 1
88#else
Eric Andersenca162042003-07-29 07:15:17 +000089#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +000090#endif
91
Paul Fox02eb9342005-09-07 16:56:02 +000092#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
Eric Andersencb57d552001-06-28 07:25:16 +000093#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +000094#endif
95
Eric Andersen2870d962001-07-02 17:27:21 +000096#include "cmdedit.h"
97
Eric Andersenc470f442003-07-28 09:56:35 +000098#ifdef __GLIBC__
99/* glibc sucks */
100static int *dash_errno;
101#undef errno
102#define errno (*dash_errno)
103#endif
104
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000105#if defined(__uClinux__)
106#error "Do not even bother, ash will not run on uClinux"
107#endif
108
Eric Andersenc470f442003-07-28 09:56:35 +0000109#ifdef DEBUG
110#define _DIAGASSERT(assert_expr) assert(assert_expr)
111#else
112#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000113#endif
114
Eric Andersen2870d962001-07-02 17:27:21 +0000115
Eric Andersenc470f442003-07-28 09:56:35 +0000116#ifdef CONFIG_ASH_ALIAS
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000117/* alias.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000118
119#define ALIASINUSE 1
120#define ALIASDEAD 2
121
122struct alias {
123 struct alias *next;
124 char *name;
125 char *val;
126 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000127};
128
Eric Andersenc470f442003-07-28 09:56:35 +0000129static struct alias *lookupalias(const char *, int);
130static int aliascmd(int, char **);
131static int unaliascmd(int, char **);
132static void rmaliases(void);
133static int unalias(const char *);
134static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000135#endif
136
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000137/* cd.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000138
139
140static void setpwd(const char *, int);
141
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000142/* error.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000143
144
145/*
146 * Types of operations (passed to the errmsg routine).
147 */
148
149
150static const char not_found_msg[] = "%s: not found";
151
152
153#define E_OPEN "No such file" /* opening a file */
154#define E_CREAT "Directory nonexistent" /* creating a file */
155#define E_EXEC not_found_msg+4 /* executing a program */
156
157/*
158 * We enclose jmp_buf in a structure so that we can declare pointers to
159 * jump locations. The global variable handler contains the location to
160 * jump to when an exception occurs, and the global variable exception
Eric Andersenaff114c2004-04-14 17:51:38 +0000161 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000162 * exception handlers, the user should save the value of handler on entry
163 * to an inner scope, set handler to point to a jmploc structure for the
164 * inner scope, and restore handler on exit from the scope.
165 */
166
167struct jmploc {
168 jmp_buf loc;
169};
170
171static struct jmploc *handler;
172static int exception;
173static volatile int suppressint;
174static volatile sig_atomic_t intpending;
175
Eric Andersenc470f442003-07-28 09:56:35 +0000176/* exceptions */
177#define EXINT 0 /* SIGINT received */
178#define EXERROR 1 /* a generic error */
179#define EXSHELLPROC 2 /* execute a shell procedure */
180#define EXEXEC 3 /* command execution failed */
181#define EXEXIT 4 /* exit the shell */
182#define EXSIG 5 /* trapped signal in wait(1) */
183
184
185/* do we generate EXSIG events */
186static int exsig;
187/* last pending signal */
188static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000189
190/*
191 * These macros allow the user to suspend the handling of interrupt signals
192 * over a period of time. This is similar to SIGHOLD to or sigblock, but
193 * much more efficient and portable. (But hacking the kernel is so much
194 * more fun than worrying about efficiency and portability. :-))
195 */
196
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000197#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
Eric Andersenc470f442003-07-28 09:56:35 +0000198#define INTOFF \
199 ({ \
200 suppressint++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000201 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000202 0; \
203 })
204#define SAVEINT(v) ((v) = suppressint)
205#define RESTOREINT(v) \
206 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000207 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000208 if ((suppressint = (v)) == 0 && intpending) onint(); \
209 0; \
210 })
211#define EXSIGON() \
212 ({ \
213 exsig++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000214 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000215 if (pendingsigs) \
216 exraise(EXSIG); \
217 0; \
218 })
219/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000220
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000221
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000222static void exraise(int) ATTRIBUTE_NORETURN;
223static void onint(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000224
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000225static void sh_error(const char *, ...) ATTRIBUTE_NORETURN;
226static void exerror(int, const char *, ...) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000227
228static void sh_warnx(const char *, ...);
229
230#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
231static void
232inton(void) {
233 if (--suppressint == 0 && intpending) {
234 onint();
235 }
236}
237#define INTON inton()
238static void forceinton(void)
239{
240 suppressint = 0;
241 if (intpending)
242 onint();
243}
Eric Andersen3102ac42001-07-06 04:26:23 +0000244#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000245#else
Eric Andersenc470f442003-07-28 09:56:35 +0000246#define INTON \
247 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000248 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000249 if (--suppressint == 0 && intpending) onint(); \
250 0; \
251 })
252#define FORCEINTON \
253 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000254 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000255 suppressint = 0; \
256 if (intpending) onint(); \
257 0; \
258 })
259#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000260
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000261/* expand.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000262
263struct strlist {
264 struct strlist *next;
265 char *text;
266};
267
268
269struct arglist {
270 struct strlist *list;
271 struct strlist **lastp;
272};
273
Eric Andersenc470f442003-07-28 09:56:35 +0000274/*
275 * expandarg() flags
276 */
277#define EXP_FULL 0x1 /* perform word splitting & file globbing */
278#define EXP_TILDE 0x2 /* do normal tilde expansion */
279#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
280#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
281#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
282#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
283#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
284#define EXP_WORD 0x80 /* expand word in parameter expansion */
285#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
286
287
288union node;
289static void expandarg(union node *, struct arglist *, int);
290#define rmescapes(p) _rmescapes((p), 0)
291static char *_rmescapes(char *, int);
292static int casematch(union node *, char *);
293
294#ifdef CONFIG_ASH_MATH_SUPPORT
295static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000296#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000297
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000298/* eval.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000299
Eric Andersenc470f442003-07-28 09:56:35 +0000300static char *commandname; /* currently executing command */
301static struct strlist *cmdenviron; /* environment for builtin command */
302static int exitstatus; /* exit status of last command */
303static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000304
Eric Andersenc470f442003-07-28 09:56:35 +0000305
306struct backcmd { /* result of evalbackcmd */
307 int fd; /* file descriptor to read from */
308 char *buf; /* buffer */
309 int nleft; /* number of chars in buffer */
310 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000311};
312
Eric Andersen62483552001-07-10 06:09:16 +0000313/*
Eric Andersenc470f442003-07-28 09:56:35 +0000314 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000315 */
Eric Andersenc470f442003-07-28 09:56:35 +0000316
317#define NCMD 0
318#define NPIPE 1
319#define NREDIR 2
320#define NBACKGND 3
321#define NSUBSHELL 4
322#define NAND 5
323#define NOR 6
324#define NSEMI 7
325#define NIF 8
326#define NWHILE 9
327#define NUNTIL 10
328#define NFOR 11
329#define NCASE 12
330#define NCLIST 13
331#define NDEFUN 14
332#define NARG 15
333#define NTO 16
334#define NCLOBBER 17
335#define NFROM 18
336#define NFROMTO 19
337#define NAPPEND 20
338#define NTOFD 21
339#define NFROMFD 22
340#define NHERE 23
341#define NXHERE 24
342#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000343
344
345
Eric Andersenc470f442003-07-28 09:56:35 +0000346struct ncmd {
347 int type;
348 union node *assign;
349 union node *args;
350 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000351};
352
353
Eric Andersenc470f442003-07-28 09:56:35 +0000354struct npipe {
355 int type;
356 int backgnd;
357 struct nodelist *cmdlist;
358};
Eric Andersen62483552001-07-10 06:09:16 +0000359
360
Eric Andersenc470f442003-07-28 09:56:35 +0000361struct nredir {
362 int type;
363 union node *n;
364 union node *redirect;
365};
Eric Andersen62483552001-07-10 06:09:16 +0000366
367
Eric Andersenc470f442003-07-28 09:56:35 +0000368struct nbinary {
369 int type;
370 union node *ch1;
371 union node *ch2;
372};
Eric Andersen2870d962001-07-02 17:27:21 +0000373
Eric Andersen2870d962001-07-02 17:27:21 +0000374
Eric Andersenc470f442003-07-28 09:56:35 +0000375struct nif {
376 int type;
377 union node *test;
378 union node *ifpart;
379 union node *elsepart;
380};
381
382
383struct nfor {
384 int type;
385 union node *args;
386 union node *body;
387 char *var;
388};
389
390
391struct ncase {
392 int type;
393 union node *expr;
394 union node *cases;
395};
396
397
398struct nclist {
399 int type;
400 union node *next;
401 union node *pattern;
402 union node *body;
403};
404
405
406struct narg {
407 int type;
408 union node *next;
409 char *text;
410 struct nodelist *backquote;
411};
412
413
414struct nfile {
415 int type;
416 union node *next;
417 int fd;
418 union node *fname;
419 char *expfname;
420};
421
422
423struct ndup {
424 int type;
425 union node *next;
426 int fd;
427 int dupfd;
428 union node *vname;
429};
430
431
432struct nhere {
433 int type;
434 union node *next;
435 int fd;
436 union node *doc;
437};
438
439
440struct nnot {
441 int type;
442 union node *com;
443};
444
445
446union node {
447 int type;
448 struct ncmd ncmd;
449 struct npipe npipe;
450 struct nredir nredir;
451 struct nbinary nbinary;
452 struct nif nif;
453 struct nfor nfor;
454 struct ncase ncase;
455 struct nclist nclist;
456 struct narg narg;
457 struct nfile nfile;
458 struct ndup ndup;
459 struct nhere nhere;
460 struct nnot nnot;
461};
462
463
464struct nodelist {
465 struct nodelist *next;
466 union node *n;
467};
468
469
470struct funcnode {
471 int count;
472 union node n;
473};
474
475
476static void freefunc(struct funcnode *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000477/* parser.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000478
479/* control characters in argument strings */
480#define CTL_FIRST '\201' /* first 'special' character */
481#define CTLESC '\201' /* escape next character */
482#define CTLVAR '\202' /* variable defn */
483#define CTLENDVAR '\203'
484#define CTLBACKQ '\204'
485#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
486/* CTLBACKQ | CTLQUOTE == '\205' */
487#define CTLARI '\206' /* arithmetic expression */
488#define CTLENDARI '\207'
489#define CTLQUOTEMARK '\210'
490#define CTL_LAST '\210' /* last 'special' character */
491
492/* variable substitution byte (follows CTLVAR) */
493#define VSTYPE 0x0f /* type of variable substitution */
494#define VSNUL 0x10 /* colon--treat the empty string as unset */
495#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
496
497/* values of VSTYPE field */
498#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
499#define VSMINUS 0x2 /* ${var-text} */
500#define VSPLUS 0x3 /* ${var+text} */
501#define VSQUESTION 0x4 /* ${var?message} */
502#define VSASSIGN 0x5 /* ${var=text} */
503#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
504#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
505#define VSTRIMLEFT 0x8 /* ${var#pattern} */
506#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
507#define VSLENGTH 0xa /* ${#var} */
508
509/* values of checkkwd variable */
510#define CHKALIAS 0x1
511#define CHKKWD 0x2
512#define CHKNL 0x4
513
514#define IBUFSIZ (BUFSIZ + 1)
515
516/*
517 * NEOF is returned by parsecmd when it encounters an end of file. It
518 * must be distinct from NULL, so we use the address of a variable that
519 * happens to be handy.
520 */
521static int plinno = 1; /* input line number */
522
523/* number of characters left in input buffer */
524static int parsenleft; /* copy of parsefile->nleft */
525static int parselleft; /* copy of parsefile->lleft */
526
527/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000528static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000529
530struct strpush {
531 struct strpush *prev; /* preceding string on stack */
532 char *prevstring;
533 int prevnleft;
534#ifdef CONFIG_ASH_ALIAS
535 struct alias *ap; /* if push was associated with an alias */
536#endif
537 char *string; /* remember the string since it may change */
538};
539
540struct parsefile {
541 struct parsefile *prev; /* preceding file on stack */
542 int linno; /* current line */
543 int fd; /* file descriptor (or -1 if string) */
544 int nleft; /* number of chars left in this line */
545 int lleft; /* number of chars left in this buffer */
546 char *nextc; /* next char in buffer */
547 char *buf; /* input buffer */
548 struct strpush *strpush; /* for pushing strings at this level */
549 struct strpush basestrpush; /* so pushing one is fast */
550};
551
Eric Andersenc470f442003-07-28 09:56:35 +0000552static struct parsefile basepf; /* top level input file */
"Vladimir N. Oleynik"6f347ef2005-10-15 10:23:55 +0000553#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
Eric Andersenc470f442003-07-28 09:56:35 +0000554static struct parsefile *parsefile = &basepf; /* current input file */
555
556
557static int tokpushback; /* last token pushed back */
558#define NEOF ((union node *)&tokpushback)
559static int parsebackquote; /* nonzero if we are inside backquotes */
560static int doprompt; /* if set, prompt the user */
561static int needprompt; /* true if interactive and at start of line */
562static int lasttoken; /* last token read */
563static char *wordtext; /* text of last word returned by readtoken */
564static int checkkwd;
565static struct nodelist *backquotelist;
566static union node *redirnode;
567static struct heredoc *heredoc;
568static int quoteflag; /* set if (part of) last token was quoted */
569static int startlinno; /* line # where last token started */
570
571static union node *parsecmd(int);
572static void fixredir(union node *, const char *, int);
573static const char *const *findkwd(const char *);
574static char *endofname(const char *);
575
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000576/* shell.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000577
578typedef void *pointer;
579
580static char nullstr[1]; /* zero length string */
581static const char spcstr[] = " ";
582static const char snlfmt[] = "%s\n";
583static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
584static const char illnum[] = "Illegal number: %s";
585static const char homestr[] = "HOME";
586
587#ifdef DEBUG
588#define TRACE(param) trace param
589#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000590#else
Eric Andersenc470f442003-07-28 09:56:35 +0000591#define TRACE(param)
592#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000593#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000594
Eric Andersenc470f442003-07-28 09:56:35 +0000595#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
596#define __builtin_expect(x, expected_value) (x)
597#endif
598
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000599#define xlikely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000600
Eric Andersenc470f442003-07-28 09:56:35 +0000601
602#define TEOF 0
603#define TNL 1
604#define TREDIR 2
605#define TWORD 3
606#define TSEMI 4
607#define TBACKGND 5
608#define TAND 6
609#define TOR 7
610#define TPIPE 8
611#define TLP 9
612#define TRP 10
613#define TENDCASE 11
614#define TENDBQUOTE 12
615#define TNOT 13
616#define TCASE 14
617#define TDO 15
618#define TDONE 16
619#define TELIF 17
620#define TELSE 18
621#define TESAC 19
622#define TFI 20
623#define TFOR 21
624#define TIF 22
625#define TIN 23
626#define TTHEN 24
627#define TUNTIL 25
628#define TWHILE 26
629#define TBEGIN 27
630#define TEND 28
631
632/* first char is indicating which tokens mark the end of a list */
633static const char *const tokname_array[] = {
634 "\1end of file",
635 "\0newline",
636 "\0redirection",
637 "\0word",
638 "\0;",
639 "\0&",
640 "\0&&",
641 "\0||",
642 "\0|",
643 "\0(",
644 "\1)",
645 "\1;;",
646 "\1`",
647#define KWDOFFSET 13
648 /* the following are keywords */
649 "\0!",
650 "\0case",
651 "\1do",
652 "\1done",
653 "\1elif",
654 "\1else",
655 "\1esac",
656 "\1fi",
657 "\0for",
658 "\0if",
659 "\0in",
660 "\1then",
661 "\0until",
662 "\0while",
663 "\0{",
664 "\1}",
665};
666
667static const char *tokname(int tok)
668{
669 static char buf[16];
670
671 if (tok >= TSEMI)
672 buf[0] = '"';
673 sprintf(buf + (tok >= TSEMI), "%s%c",
674 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
675 return buf;
676}
677
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000678/* machdep.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000679
680/*
681 * Most machines require the value returned from malloc to be aligned
682 * in some way. The following macro will get this right on many machines.
683 */
684
685#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
686/*
687 * It appears that grabstackstr() will barf with such alignments
688 * because stalloc() will return a string allocated in a new stackblock.
689 */
690#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
691
692/*
693 * This file was generated by the mksyntax program.
694 */
695
696
697/* Syntax classes */
698#define CWORD 0 /* character is nothing special */
699#define CNL 1 /* newline character */
700#define CBACK 2 /* a backslash character */
701#define CSQUOTE 3 /* single quote */
702#define CDQUOTE 4 /* double quote */
703#define CENDQUOTE 5 /* a terminating quote */
704#define CBQUOTE 6 /* backwards single quote */
705#define CVAR 7 /* a dollar sign */
706#define CENDVAR 8 /* a '}' character */
707#define CLP 9 /* a left paren in arithmetic */
708#define CRP 10 /* a right paren in arithmetic */
709#define CENDFILE 11 /* end of file */
710#define CCTL 12 /* like CWORD, except it must be escaped */
711#define CSPCL 13 /* these terminate a word */
712#define CIGN 14 /* character should be ignored */
713
714#ifdef CONFIG_ASH_ALIAS
715#define SYNBASE 130
716#define PEOF -130
717#define PEOA -129
718#define PEOA_OR_PEOF PEOA
719#else
720#define SYNBASE 129
721#define PEOF -129
722#define PEOA_OR_PEOF PEOF
723#endif
724
725#define is_digit(c) ((unsigned)((c) - '0') <= 9)
726#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
727#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
728
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000729/* C99 say: "char" declaration may be signed or unsigned default */
730#define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int)
731
Eric Andersenc470f442003-07-28 09:56:35 +0000732/*
733 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
734 * (assuming ascii char codes, as the original implementation did)
735 */
736#define is_special(c) \
737 ( (((unsigned int)c) - 33 < 32) \
738 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
739
740#define digit_val(c) ((c) - '0')
741
742/*
743 * This file was generated by the mksyntax program.
744 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000745
Eric Andersend35c5df2002-01-09 15:37:36 +0000746#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000747#define USE_SIT_FUNCTION
748#endif
749
750/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000751#define BASESYNTAX 0 /* not in quotes */
752#define DQSYNTAX 1 /* in double quotes */
753#define SQSYNTAX 2 /* in single quotes */
754#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000755
Eric Andersenc470f442003-07-28 09:56:35 +0000756#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000757static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000758#ifdef CONFIG_ASH_ALIAS
759 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
760#endif
761 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
762 {CNL, CNL, CNL, CNL}, /* 2, \n */
763 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
764 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
765 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
766 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
767 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
768 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
769 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
770 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
771 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000772#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000773 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
774 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
775 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000776#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000777};
Eric Andersenc470f442003-07-28 09:56:35 +0000778#else
779static const char S_I_T[][3] = {
780#ifdef CONFIG_ASH_ALIAS
781 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
782#endif
783 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
784 {CNL, CNL, CNL}, /* 2, \n */
785 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
786 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
787 {CVAR, CVAR, CWORD}, /* 5, $ */
788 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
789 {CSPCL, CWORD, CWORD}, /* 7, ( */
790 {CSPCL, CWORD, CWORD}, /* 8, ) */
791 {CBACK, CBACK, CCTL}, /* 9, \ */
792 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
793 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
794#ifndef USE_SIT_FUNCTION
795 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
796 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
797 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
798#endif
799};
800#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000801
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000802#ifdef USE_SIT_FUNCTION
803
804#define U_C(c) ((unsigned char)(c))
805
806static int SIT(int c, int syntax)
807{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000808 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000809#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000810 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000811 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
812 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
813 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
814 11, 3 /* "}~" */
815 };
816#else
817 static const char syntax_index_table[] = {
818 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
819 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
820 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
821 10, 2 /* "}~" */
822 };
823#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000824 const char *s;
825 int indx;
826
Eric Andersenc470f442003-07-28 09:56:35 +0000827 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000828 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000829#ifdef CONFIG_ASH_ALIAS
830 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000831 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000832 else
833#endif
834 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
835 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000836 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000837 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000838 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000839 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000840 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000841 }
842 return S_I_T[indx][syntax];
843}
844
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000845#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000846
847#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
848
Eric Andersenc470f442003-07-28 09:56:35 +0000849#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000850#define CSPCL_CIGN_CIGN_CIGN 0
851#define CSPCL_CWORD_CWORD_CWORD 1
852#define CNL_CNL_CNL_CNL 2
853#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000854#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000855#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000856#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000857#define CSPCL_CWORD_CWORD_CLP 7
858#define CSPCL_CWORD_CWORD_CRP 8
859#define CBACK_CBACK_CCTL_CBACK 9
860#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
861#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
862#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
863#define CWORD_CWORD_CWORD_CWORD 13
864#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000865#else
866#define CSPCL_CWORD_CWORD_CWORD 0
867#define CNL_CNL_CNL_CNL 1
868#define CWORD_CCTL_CCTL_CWORD 2
869#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
870#define CVAR_CVAR_CWORD_CVAR 4
871#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
872#define CSPCL_CWORD_CWORD_CLP 6
873#define CSPCL_CWORD_CWORD_CRP 7
874#define CBACK_CBACK_CCTL_CBACK 8
875#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
876#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
877#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
878#define CWORD_CWORD_CWORD_CWORD 12
879#define CCTL_CCTL_CCTL_CCTL 13
880#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000881
882static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000883 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000884 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
885#ifdef CONFIG_ASH_ALIAS
886 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
887#endif
888 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
889 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
890 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
891 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
892 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
893 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
894 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
895 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
896 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000897 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
898 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
899 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
900 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
901 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
902 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
903 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
904 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
905 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
906 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
907 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
908 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
909 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
910 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
911 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
912 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
913 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
914 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
915 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
916 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
917 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
918 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
919 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
920 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
921 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
922 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
923 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
924 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
925 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
926 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
927 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
928 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
929 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
930 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
931 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
932 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
933 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
934 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
935 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
936 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
937 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
938 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
939 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
940 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
941 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
942 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
943 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
944 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
945 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
946 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
947 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
948 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
949 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
950 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
951 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
952 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
953 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
954 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
955 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
956 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
957 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
958 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
959 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
960 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
961 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
962 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
963 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
964 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
965 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
966 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
967 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
968 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
969 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
970 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
971 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
972 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
973 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
974 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
975 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
976 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
977 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
978 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
979 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
980 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
981 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
982 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
983 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
984 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
985 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
986 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
987 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
988 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
989 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
990 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
991 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
992 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
993 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
994 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
995 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
996 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
997 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
998 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
999 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1026 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1027 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1049 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001050 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001051 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1052 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1053 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1054 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001055 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001056 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1057 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1058 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1059 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1060 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1061 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1062 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1063 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1064 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1072 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1073 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1074 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1075 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1076 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1077 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1078 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1079 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1080 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1108 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1109 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1110 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1113 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1141 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1142 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1143 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001144};
1145
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001146#endif /* USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00001147
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001148/* alias.c */
Eric Andersen2870d962001-07-02 17:27:21 +00001149
Eric Andersen2870d962001-07-02 17:27:21 +00001150
Eric Andersenc470f442003-07-28 09:56:35 +00001151#define ATABSIZE 39
1152
1153static int funcblocksize; /* size of structures in function */
1154static int funcstringsize; /* size of strings in node */
1155static pointer funcblock; /* block to allocate function from */
1156static char *funcstring; /* block to allocate strings from */
1157
1158static const short nodesize[26] = {
1159 SHELL_ALIGN(sizeof (struct ncmd)),
1160 SHELL_ALIGN(sizeof (struct npipe)),
1161 SHELL_ALIGN(sizeof (struct nredir)),
1162 SHELL_ALIGN(sizeof (struct nredir)),
1163 SHELL_ALIGN(sizeof (struct nredir)),
1164 SHELL_ALIGN(sizeof (struct nbinary)),
1165 SHELL_ALIGN(sizeof (struct nbinary)),
1166 SHELL_ALIGN(sizeof (struct nbinary)),
1167 SHELL_ALIGN(sizeof (struct nif)),
1168 SHELL_ALIGN(sizeof (struct nbinary)),
1169 SHELL_ALIGN(sizeof (struct nbinary)),
1170 SHELL_ALIGN(sizeof (struct nfor)),
1171 SHELL_ALIGN(sizeof (struct ncase)),
1172 SHELL_ALIGN(sizeof (struct nclist)),
1173 SHELL_ALIGN(sizeof (struct narg)),
1174 SHELL_ALIGN(sizeof (struct narg)),
1175 SHELL_ALIGN(sizeof (struct nfile)),
1176 SHELL_ALIGN(sizeof (struct nfile)),
1177 SHELL_ALIGN(sizeof (struct nfile)),
1178 SHELL_ALIGN(sizeof (struct nfile)),
1179 SHELL_ALIGN(sizeof (struct nfile)),
1180 SHELL_ALIGN(sizeof (struct ndup)),
1181 SHELL_ALIGN(sizeof (struct ndup)),
1182 SHELL_ALIGN(sizeof (struct nhere)),
1183 SHELL_ALIGN(sizeof (struct nhere)),
1184 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001185};
1186
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001187
Eric Andersenc470f442003-07-28 09:56:35 +00001188static void calcsize(union node *);
1189static void sizenodelist(struct nodelist *);
1190static union node *copynode(union node *);
1191static struct nodelist *copynodelist(struct nodelist *);
1192static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001193
1194
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001195static int evalstring(char *, int mask);
Eric Andersenc470f442003-07-28 09:56:35 +00001196union node; /* BLETCH for ansi C */
1197static void evaltree(union node *, int);
1198static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001199
Eric Andersenc470f442003-07-28 09:56:35 +00001200static int evalskip; /* set if we are skipping commands */
1201static int skipcount; /* number of levels to skip */
1202static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001203
1204/* reasons for skipping commands (see comment on breakcmd routine) */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001205#define SKIPBREAK (1 << 0)
1206#define SKIPCONT (1 << 1)
1207#define SKIPFUNC (1 << 2)
1208#define SKIPFILE (1 << 3)
1209#define SKIPEVAL (1 << 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001210
Eric Andersenc470f442003-07-28 09:56:35 +00001211/*
1212 * This file was generated by the mkbuiltins program.
1213 */
Eric Andersen2870d962001-07-02 17:27:21 +00001214
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001215#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001216static int bgcmd(int, char **);
1217#endif
1218static int breakcmd(int, char **);
1219static int cdcmd(int, char **);
1220#ifdef CONFIG_ASH_CMDCMD
1221static int commandcmd(int, char **);
1222#endif
1223static int dotcmd(int, char **);
1224static int evalcmd(int, char **);
Paul Fox0b621582005-08-09 19:38:05 +00001225#ifdef CONFIG_ASH_BUILTIN_ECHO
1226static int echocmd(int, char **);
1227#endif
Paul Fox6ab03782006-06-08 21:37:26 +00001228#ifdef CONFIG_ASH_BUILTIN_TEST
1229static int testcmd(int, char **);
1230#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001231static int execcmd(int, char **);
1232static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001233static int exportcmd(int, char **);
1234static int falsecmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001235#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001236static int fgcmd(int, char **);
1237#endif
1238#ifdef CONFIG_ASH_GETOPTS
1239static int getoptscmd(int, char **);
1240#endif
1241static int hashcmd(int, char **);
1242#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1243static int helpcmd(int argc, char **argv);
1244#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001245#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001246static int jobscmd(int, char **);
1247#endif
Eric Andersen90898442003-08-06 11:20:52 +00001248#ifdef CONFIG_ASH_MATH_SUPPORT
1249static int letcmd(int, char **);
1250#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001251static int localcmd(int, char **);
1252static int pwdcmd(int, char **);
1253static int readcmd(int, char **);
1254static int returncmd(int, char **);
1255static int setcmd(int, char **);
1256static int shiftcmd(int, char **);
1257static int timescmd(int, char **);
1258static int trapcmd(int, char **);
1259static int truecmd(int, char **);
1260static int typecmd(int, char **);
1261static int umaskcmd(int, char **);
1262static int unsetcmd(int, char **);
1263static int waitcmd(int, char **);
1264static int ulimitcmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001265#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001266static int killcmd(int, char **);
1267#endif
1268
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001269/* mail.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001270
1271#ifdef CONFIG_ASH_MAIL
1272static void chkmail(void);
1273static void changemail(const char *);
1274#endif
1275
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001276/* exec.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001277
1278/* values of cmdtype */
1279#define CMDUNKNOWN -1 /* no entry in table for command */
1280#define CMDNORMAL 0 /* command is an executable program */
1281#define CMDFUNCTION 1 /* command is a shell function */
1282#define CMDBUILTIN 2 /* command is a shell builtin */
1283
1284struct builtincmd {
1285 const char *name;
1286 int (*builtin)(int, char **);
1287 /* unsigned flags; */
1288};
1289
Paul Fox0b621582005-08-09 19:38:05 +00001290
1291#define COMMANDCMD (builtincmd + 5 + \
Paul Fox6ab03782006-06-08 21:37:26 +00001292 2 * ENABLE_ASH_BUILTIN_TEST + \
1293 ENABLE_ASH_ALIAS + \
1294 ENABLE_ASH_JOB_CONTROL)
Paul Fox0b621582005-08-09 19:38:05 +00001295#define EXECCMD (builtincmd + 7 + \
Paul Fox6ab03782006-06-08 21:37:26 +00001296 2 * ENABLE_ASH_BUILTIN_TEST + \
1297 ENABLE_ASH_ALIAS + \
1298 ENABLE_ASH_JOB_CONTROL + \
1299 ENABLE_ASH_CMDCMD + \
1300 ENABLE_ASH_BUILTIN_ECHO)
Eric Andersenc470f442003-07-28 09:56:35 +00001301
1302#define BUILTIN_NOSPEC "0"
1303#define BUILTIN_SPECIAL "1"
1304#define BUILTIN_REGULAR "2"
1305#define BUILTIN_SPEC_REG "3"
1306#define BUILTIN_ASSIGN "4"
1307#define BUILTIN_SPEC_ASSG "5"
1308#define BUILTIN_REG_ASSG "6"
1309#define BUILTIN_SPEC_REG_ASSG "7"
1310
1311#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1312#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
Paul Foxc3850c82005-07-20 18:23:39 +00001313#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001314
1315static const struct builtincmd builtincmd[] = {
1316 { BUILTIN_SPEC_REG ".", dotcmd },
1317 { BUILTIN_SPEC_REG ":", truecmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001318#ifdef CONFIG_ASH_BUILTIN_TEST
1319 { BUILTIN_REGULAR "[", testcmd },
1320 { BUILTIN_REGULAR "[[", testcmd },
1321#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001322#ifdef CONFIG_ASH_ALIAS
1323 { BUILTIN_REG_ASSG "alias", aliascmd },
1324#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001325#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001326 { BUILTIN_REGULAR "bg", bgcmd },
1327#endif
1328 { BUILTIN_SPEC_REG "break", breakcmd },
1329 { BUILTIN_REGULAR "cd", cdcmd },
1330 { BUILTIN_NOSPEC "chdir", cdcmd },
1331#ifdef CONFIG_ASH_CMDCMD
1332 { BUILTIN_REGULAR "command", commandcmd },
1333#endif
1334 { BUILTIN_SPEC_REG "continue", breakcmd },
Paul Fox0b621582005-08-09 19:38:05 +00001335#ifdef CONFIG_ASH_BUILTIN_ECHO
1336 { BUILTIN_REGULAR "echo", echocmd },
1337#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001338 { BUILTIN_SPEC_REG "eval", evalcmd },
1339 { BUILTIN_SPEC_REG "exec", execcmd },
1340 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001341 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1342 { BUILTIN_REGULAR "false", falsecmd },
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001343#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001344 { BUILTIN_REGULAR "fg", fgcmd },
1345#endif
1346#ifdef CONFIG_ASH_GETOPTS
1347 { BUILTIN_REGULAR "getopts", getoptscmd },
1348#endif
1349 { BUILTIN_NOSPEC "hash", hashcmd },
1350#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1351 { BUILTIN_NOSPEC "help", helpcmd },
1352#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001353#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001354 { BUILTIN_REGULAR "jobs", jobscmd },
1355 { BUILTIN_REGULAR "kill", killcmd },
1356#endif
1357#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001358 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001359#endif
1360 { BUILTIN_ASSIGN "local", localcmd },
1361 { BUILTIN_NOSPEC "pwd", pwdcmd },
1362 { BUILTIN_REGULAR "read", readcmd },
1363 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1364 { BUILTIN_SPEC_REG "return", returncmd },
1365 { BUILTIN_SPEC_REG "set", setcmd },
Rob Landley47b18382006-05-12 20:44:16 +00001366 { BUILTIN_SPEC_REG "source", dotcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001367 { BUILTIN_SPEC_REG "shift", shiftcmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001368#ifdef CONFIG_ASH_BUILTIN_TEST
1369 { BUILTIN_REGULAR "test", testcmd },
1370#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001371 { BUILTIN_SPEC_REG "times", timescmd },
1372 { BUILTIN_SPEC_REG "trap", trapcmd },
1373 { BUILTIN_REGULAR "true", truecmd },
1374 { BUILTIN_NOSPEC "type", typecmd },
1375 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1376 { BUILTIN_REGULAR "umask", umaskcmd },
1377#ifdef CONFIG_ASH_ALIAS
1378 { BUILTIN_REGULAR "unalias", unaliascmd },
1379#endif
1380 { BUILTIN_SPEC_REG "unset", unsetcmd },
1381 { BUILTIN_REGULAR "wait", waitcmd },
1382};
1383
1384#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1385
1386
1387
1388struct cmdentry {
1389 int cmdtype;
1390 union param {
1391 int index;
1392 const struct builtincmd *cmd;
1393 struct funcnode *func;
1394 } u;
1395};
1396
1397
1398/* action to find_command() */
1399#define DO_ERR 0x01 /* prints errors */
1400#define DO_ABS 0x02 /* checks absolute paths */
1401#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1402#define DO_ALTPATH 0x08 /* using alternate path */
1403#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1404
1405static const char *pathopt; /* set by padvance */
1406
1407static void shellexec(char **, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001408 ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00001409static char *padvance(const char **, const char *);
1410static void find_command(char *, struct cmdentry *, int, const char *);
1411static struct builtincmd *find_builtin(const char *);
1412static void hashcd(void);
1413static void changepath(const char *);
1414static void defun(char *, union node *);
1415static void unsetfunc(const char *);
1416
Eric Andersened9ecf72004-06-22 08:29:45 +00001417#ifdef CONFIG_ASH_MATH_SUPPORT_64
1418typedef int64_t arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001419#define arith_t_type (long long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001420#else
1421typedef long arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001422#define arith_t_type (long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001423#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001424
1425#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001426static arith_t dash_arith(const char *);
1427static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001428#endif
1429
Eric Andersen16767e22004-03-16 05:14:10 +00001430#ifdef CONFIG_ASH_RANDOM_SUPPORT
1431static unsigned long rseed;
1432static void change_random(const char *);
1433# ifndef DYNAMIC_VAR
1434# define DYNAMIC_VAR
1435# endif
1436#endif
1437
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001438/* init.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001439
1440static void reset(void);
1441
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001442/* var.h */
Eric Andersen2870d962001-07-02 17:27:21 +00001443
1444/*
1445 * Shell variables.
1446 */
1447
1448/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001449#define VEXPORT 0x01 /* variable is exported */
1450#define VREADONLY 0x02 /* variable cannot be modified */
1451#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1452#define VTEXTFIXED 0x08 /* text is statically allocated */
1453#define VSTACK 0x10 /* text is allocated on the stack */
1454#define VUNSET 0x20 /* the variable is not set */
1455#define VNOFUNC 0x40 /* don't call the callback function */
1456#define VNOSET 0x80 /* do not set variable - just readonly test */
1457#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001458#ifdef DYNAMIC_VAR
1459# define VDYNAMIC 0x200 /* dynamic variable */
1460# else
1461# define VDYNAMIC 0
1462#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001463
1464struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001465 struct var *next; /* next entry in hash list */
1466 int flags; /* flags are defined above */
1467 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001468 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001469 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001470};
1471
1472struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001473 struct localvar *next; /* next local variable in list */
1474 struct var *vp; /* the variable that was made local */
1475 int flags; /* saved flags */
1476 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001477};
1478
1479
Eric Andersen2870d962001-07-02 17:27:21 +00001480static struct localvar *localvars;
1481
Eric Andersenc470f442003-07-28 09:56:35 +00001482/*
1483 * Shell variables.
1484 */
1485
1486#ifdef CONFIG_ASH_GETOPTS
1487static void getoptsreset(const char *);
1488#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001489
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001490#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001491#include <locale.h>
1492static void change_lc_all(const char *value);
1493static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001494#endif
1495
Eric Andersenef02f822004-03-11 13:34:24 +00001496
Eric Andersen2870d962001-07-02 17:27:21 +00001497#define VTABSIZE 39
1498
Eric Andersen90898442003-08-06 11:20:52 +00001499static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001500#ifdef IFS_BROKEN
1501static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001502#define defifs (defifsvar + 4)
1503#else
Eric Andersenc470f442003-07-28 09:56:35 +00001504static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001505#endif
1506
Eric Andersenc470f442003-07-28 09:56:35 +00001507
1508static struct var varinit[] = {
1509#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001510 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001511#else
Eric Andersen16767e22004-03-16 05:14:10 +00001512 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001513#endif
1514
1515#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001516 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1517 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001518#endif
1519
Eric Andersen16767e22004-03-16 05:14:10 +00001520 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1521 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1522 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1523 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001524#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001525 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1526#endif
1527#ifdef CONFIG_ASH_RANDOM_SUPPORT
1528 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001529#endif
1530#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001531 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1532 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001533#endif
1534#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001535 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001536#endif
1537};
1538
1539#define vifs varinit[0]
1540#ifdef CONFIG_ASH_MAIL
1541#define vmail (&vifs)[1]
1542#define vmpath (&vmail)[1]
1543#else
1544#define vmpath vifs
1545#endif
1546#define vpath (&vmpath)[1]
1547#define vps1 (&vpath)[1]
1548#define vps2 (&vps1)[1]
1549#define vps4 (&vps2)[1]
1550#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001551#ifdef CONFIG_ASH_GETOPTS
1552#define vrandom (&voptind)[1]
1553#else
1554#define vrandom (&vps4)[1]
1555#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001556#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001557
1558/*
1559 * The following macros access the values of the above variables.
1560 * They have to skip over the name. They return the null string
1561 * for unset variables.
1562 */
1563
1564#define ifsval() (vifs.text + 4)
1565#define ifsset() ((vifs.flags & VUNSET) == 0)
1566#define mailval() (vmail.text + 5)
1567#define mpathval() (vmpath.text + 9)
1568#define pathval() (vpath.text + 5)
1569#define ps1val() (vps1.text + 4)
1570#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001571#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001572#define optindval() (voptind.text + 7)
1573
1574#define mpathset() ((vmpath.flags & VUNSET) == 0)
1575
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001576static void setvar(const char *, const char *, int);
1577static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001578static void listsetvar(struct strlist *, int);
1579static char *lookupvar(const char *);
1580static char *bltinlookup(const char *);
1581static char **listvars(int, int, char ***);
1582#define environment() listvars(VEXPORT, VUNSET, 0)
1583static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001584static void poplocalvars(void);
1585static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001586#ifdef CONFIG_ASH_GETOPTS
1587static int setvarsafe(const char *, const char *, int);
1588#endif
1589static int varcmp(const char *, const char *);
1590static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001591
1592
Eric Andersenc470f442003-07-28 09:56:35 +00001593static inline int varequal(const char *a, const char *b) {
1594 return !varcmp(a, b);
1595}
Eric Andersen2870d962001-07-02 17:27:21 +00001596
1597
Eric Andersenc470f442003-07-28 09:56:35 +00001598static int loopnest; /* current loop nesting level */
1599
Eric Andersenc470f442003-07-28 09:56:35 +00001600/*
1601 * The parsefile structure pointed to by the global variable parsefile
1602 * contains information about the current file being read.
1603 */
1604
1605
1606struct redirtab {
1607 struct redirtab *next;
1608 int renamed[10];
1609 int nullredirs;
1610};
1611
1612static struct redirtab *redirlist;
1613static int nullredirs;
1614
1615extern char **environ;
1616
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001617/* output.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001618
1619
1620static void outstr(const char *, FILE *);
1621static void outcslow(int, FILE *);
1622static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001623static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001624static int out1fmt(const char *, ...)
1625 __attribute__((__format__(__printf__,1,2)));
1626static int fmtstr(char *, size_t, const char *, ...)
1627 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001628
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001629static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001630
Eric Andersenc470f442003-07-28 09:56:35 +00001631
1632static void out1str(const char *p)
1633{
1634 outstr(p, stdout);
1635}
1636
1637static void out2str(const char *p)
1638{
1639 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001640 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001641}
1642
1643/*
1644 * Initialization code.
1645 */
1646
1647/*
1648 * This routine initializes the builtin variables.
1649 */
1650
1651static inline void
1652initvar(void)
1653{
1654 struct var *vp;
1655 struct var *end;
1656 struct var **vpp;
1657
1658 /*
1659 * PS1 depends on uid
1660 */
1661#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1662 vps1.text = "PS1=\\w \\$ ";
1663#else
1664 if (!geteuid())
1665 vps1.text = "PS1=# ";
1666#endif
1667 vp = varinit;
1668 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1669 do {
1670 vpp = hashvar(vp->text);
1671 vp->next = *vpp;
1672 *vpp = vp;
1673 } while (++vp < end);
1674}
1675
1676static inline void
1677init(void)
1678{
1679
1680 /* from input.c: */
1681 {
1682 basepf.nextc = basepf.buf = basebuf;
1683 }
1684
1685 /* from trap.c: */
1686 {
1687 signal(SIGCHLD, SIG_DFL);
1688 }
1689
1690 /* from var.c: */
1691 {
1692 char **envp;
1693 char ppid[32];
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001694 const char *p;
1695 struct stat st1, st2;
Eric Andersenc470f442003-07-28 09:56:35 +00001696
1697 initvar();
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001698 for (envp = environ ; envp && *envp ; envp++) {
Eric Andersenc470f442003-07-28 09:56:35 +00001699 if (strchr(*envp, '=')) {
1700 setvareq(*envp, VEXPORT|VTEXTFIXED);
1701 }
1702 }
1703
1704 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1705 setvar("PPID", ppid, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001706
1707 p = lookupvar("PWD");
1708 if (p)
1709 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1710 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1711 p = 0;
1712 setpwd(p, 0);
Eric Andersenc470f442003-07-28 09:56:35 +00001713 }
1714}
1715
1716/* PEOF (the end of file marker) */
1717
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001718enum {
1719 INPUT_PUSH_FILE = 1,
1720 INPUT_NOFILE_OK = 2,
1721};
1722
Eric Andersenc470f442003-07-28 09:56:35 +00001723/*
1724 * The input line number. Input.c just defines this variable, and saves
1725 * and restores it when files are pushed and popped. The user of this
1726 * package must set its value.
1727 */
1728
1729static int pgetc(void);
1730static int pgetc2(void);
1731static int preadbuffer(void);
1732static void pungetc(void);
1733static void pushstring(char *, void *);
1734static void popstring(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001735static void setinputfd(int, int);
1736static void setinputstring(char *);
1737static void popfile(void);
1738static void popallfiles(void);
1739static void closescript(void);
1740
1741
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001742/* jobs.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001743
1744
1745/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1746#define FORK_FG 0
1747#define FORK_BG 1
1748#define FORK_NOJOB 2
1749
1750/* mode flags for showjob(s) */
1751#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1752#define SHOW_PID 0x04 /* include process pid */
1753#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1754
1755
1756/*
1757 * A job structure contains information about a job. A job is either a
1758 * single process or a set of processes contained in a pipeline. In the
1759 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1760 * array of pids.
1761 */
1762
1763struct procstat {
1764 pid_t pid; /* process id */
1765 int status; /* last process status from wait() */
1766 char *cmd; /* text of command being run */
1767};
1768
1769struct job {
1770 struct procstat ps0; /* status of process */
1771 struct procstat *ps; /* status or processes when more than one */
1772#if JOBS
1773 int stopstatus; /* status of a stopped job */
1774#endif
1775 uint32_t
1776 nprocs: 16, /* number of processes */
1777 state: 8,
1778#define JOBRUNNING 0 /* at least one proc running */
1779#define JOBSTOPPED 1 /* all procs are stopped */
1780#define JOBDONE 2 /* all procs are completed */
1781#if JOBS
1782 sigint: 1, /* job was killed by SIGINT */
1783 jobctl: 1, /* job running under job control */
1784#endif
1785 waited: 1, /* true if this entry has been waited for */
1786 used: 1, /* true if this entry is in used */
1787 changed: 1; /* true if status has changed */
1788 struct job *prev_job; /* previous job */
1789};
1790
1791static pid_t backgndpid; /* pid of last background process */
1792static int job_warning; /* user was warned about stopped jobs */
1793#if JOBS
1794static int jobctl; /* true if doing job control */
1795#endif
1796
1797static struct job *makejob(union node *, int);
1798static int forkshell(struct job *, union node *, int);
1799static int waitforjob(struct job *);
1800static int stoppedjobs(void);
1801
1802#if ! JOBS
1803#define setjobctl(on) /* do nothing */
1804#else
1805static void setjobctl(int);
1806static void showjobs(FILE *, int);
1807#endif
1808
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001809/* main.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001810
1811
1812/* pid of main shell */
1813static int rootpid;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001814/* shell level: 0 for the main shell, 1 for its children, and so on */
1815static int shlvl;
1816#define rootshell (!shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00001817
1818static void readcmdfile(char *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001819static int cmdloop(int);
Eric Andersenc470f442003-07-28 09:56:35 +00001820
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001821/* memalloc.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001822
1823
1824struct stackmark {
1825 struct stack_block *stackp;
1826 char *stacknxt;
1827 size_t stacknleft;
1828 struct stackmark *marknext;
1829};
1830
1831/* minimum size of a block */
1832#define MINSIZE SHELL_ALIGN(504)
1833
1834struct stack_block {
1835 struct stack_block *prev;
1836 char space[MINSIZE];
1837};
1838
1839static struct stack_block stackbase;
1840static struct stack_block *stackp = &stackbase;
1841static struct stackmark *markp;
1842static char *stacknxt = stackbase.space;
1843static size_t stacknleft = MINSIZE;
1844static char *sstrend = stackbase.space + MINSIZE;
1845static int herefd = -1;
1846
1847
1848static pointer ckmalloc(size_t);
1849static pointer ckrealloc(pointer, size_t);
1850static char *savestr(const char *);
1851static pointer stalloc(size_t);
1852static void stunalloc(pointer);
1853static void setstackmark(struct stackmark *);
1854static void popstackmark(struct stackmark *);
1855static void growstackblock(void);
1856static void *growstackstr(void);
1857static char *makestrspace(size_t, char *);
1858static char *stnputs(const char *, size_t, char *);
1859static char *stputs(const char *, char *);
1860
1861
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001862static inline char *_STPUTC(int c, char *p) {
Eric Andersenc470f442003-07-28 09:56:35 +00001863 if (p == sstrend)
1864 p = growstackstr();
1865 *p++ = c;
1866 return p;
1867}
1868
1869#define stackblock() ((void *)stacknxt)
1870#define stackblocksize() stacknleft
1871#define STARTSTACKSTR(p) ((p) = stackblock())
1872#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1873#define CHECKSTRSPACE(n, p) \
1874 ({ \
1875 char *q = (p); \
1876 size_t l = (n); \
1877 size_t m = sstrend - q; \
1878 if (l > m) \
1879 (p) = makestrspace(l, q); \
1880 0; \
1881 })
1882#define USTPUTC(c, p) (*p++ = (c))
1883#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1884#define STUNPUTC(p) (--p)
1885#define STTOPC(p) p[-1]
1886#define STADJUST(amount, p) (p += (amount))
1887
1888#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1889#define ungrabstackstr(s, p) stunalloc((s))
1890#define stackstrend() ((void *)sstrend)
1891
1892#define ckfree(p) free((pointer)(p))
1893
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001894/* mystring.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001895
1896
1897#define DOLATSTRLEN 4
1898
1899static char *prefix(const char *, const char *);
1900static int number(const char *);
1901static int is_number(const char *);
1902static char *single_quote(const char *);
1903static char *sstrdup(const char *);
1904
1905#define equal(s1, s2) (strcmp(s1, s2) == 0)
1906#define scopy(s1, s2) ((void)strcpy(s2, s1))
1907
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001908/* options.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001909
1910struct shparam {
1911 int nparam; /* # of positional parameters (without $0) */
1912 unsigned char malloc; /* if parameter list dynamically allocated */
1913 char **p; /* parameter list */
1914#ifdef CONFIG_ASH_GETOPTS
1915 int optind; /* next parameter to be processed by getopts */
1916 int optoff; /* used by getopts */
1917#endif
1918};
1919
1920
1921#define eflag optlist[0]
1922#define fflag optlist[1]
1923#define Iflag optlist[2]
1924#define iflag optlist[3]
1925#define mflag optlist[4]
1926#define nflag optlist[5]
1927#define sflag optlist[6]
1928#define xflag optlist[7]
1929#define vflag optlist[8]
1930#define Cflag optlist[9]
1931#define aflag optlist[10]
1932#define bflag optlist[11]
1933#define uflag optlist[12]
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001934#define viflag optlist[13]
Eric Andersenc470f442003-07-28 09:56:35 +00001935
1936#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001937#define nolog optlist[14]
1938#define debug optlist[15]
Paul Fox3f11b1b2005-08-04 19:04:46 +00001939#endif
1940
1941#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1942#define setvimode(on) viflag = 0 /* forcibly keep the option off */
Eric Andersenc470f442003-07-28 09:56:35 +00001943#endif
1944
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001945/* options.c */
Eric Andersenc470f442003-07-28 09:56:35 +00001946
1947
Paul Fox3f11b1b2005-08-04 19:04:46 +00001948static const char *const optletters_optnames[] = {
Eric Andersenc470f442003-07-28 09:56:35 +00001949 "e" "errexit",
1950 "f" "noglob",
1951 "I" "ignoreeof",
1952 "i" "interactive",
1953 "m" "monitor",
1954 "n" "noexec",
1955 "s" "stdin",
1956 "x" "xtrace",
1957 "v" "verbose",
1958 "C" "noclobber",
1959 "a" "allexport",
1960 "b" "notify",
1961 "u" "nounset",
Paul Fox3f11b1b2005-08-04 19:04:46 +00001962 "\0" "vi",
Eric Andersenc470f442003-07-28 09:56:35 +00001963#ifdef DEBUG
1964 "\0" "nolog",
1965 "\0" "debug",
1966#endif
1967};
1968
1969#define optletters(n) optletters_optnames[(n)][0]
1970#define optnames(n) (&optletters_optnames[(n)][1])
1971
Paul Fox3f11b1b2005-08-04 19:04:46 +00001972#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001973
1974static char optlist[NOPTS];
1975
1976
1977static char *arg0; /* value of $0 */
1978static struct shparam shellparam; /* $@ current positional parameters */
1979static char **argptr; /* argument list for builtin commands */
1980static char *optionarg; /* set by nextopt (like getopt) */
1981static char *optptr; /* used by nextopt */
1982
1983static char *minusc; /* argument to -c option */
1984
1985
1986static void procargs(int, char **);
1987static void optschanged(void);
1988static void setparam(char **);
1989static void freeparam(volatile struct shparam *);
1990static int shiftcmd(int, char **);
1991static int setcmd(int, char **);
1992static int nextopt(const char *);
1993
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001994/* redir.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001995
1996/* flags passed to redirect */
1997#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001998#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00001999
2000union node;
2001static void redirect(union node *, int);
2002static void popredir(int);
2003static void clearredir(int);
2004static int copyfd(int, int);
2005static int redirectsafe(union node *, int);
2006
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002007/* show.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002008
2009
2010#ifdef DEBUG
2011static void showtree(union node *);
2012static void trace(const char *, ...);
2013static void tracev(const char *, va_list);
2014static void trargs(char **);
2015static void trputc(int);
2016static void trputs(const char *);
2017static void opentrace(void);
2018#endif
2019
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002020/* trap.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002021
2022
2023/* trap handler commands */
2024static char *trap[NSIG];
2025/* current value of signal */
2026static char sigmode[NSIG - 1];
2027/* indicates specified signal received */
2028static char gotsig[NSIG - 1];
2029
2030static void clear_traps(void);
2031static void setsignal(int);
2032static void ignoresig(int);
2033static void onsig(int);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002034static int dotrap(void);
Eric Andersenc470f442003-07-28 09:56:35 +00002035static void setinteractive(int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002036static void exitshell(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00002037static int decode_signal(const char *, int);
2038
2039/*
2040 * This routine is called when an error or an interrupt occurs in an
2041 * interactive shell and control is returned to the main command loop.
2042 */
2043
2044static void
2045reset(void)
2046{
2047 /* from eval.c: */
2048 {
2049 evalskip = 0;
2050 loopnest = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002051 }
2052
2053 /* from input.c: */
2054 {
2055 parselleft = parsenleft = 0; /* clear input buffer */
2056 popallfiles();
2057 }
2058
2059 /* from parser.c: */
2060 {
2061 tokpushback = 0;
2062 checkkwd = 0;
2063 }
2064
2065 /* from redir.c: */
2066 {
2067 clearredir(0);
2068 }
2069
2070}
2071
2072#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002073static struct alias *atab[ATABSIZE];
2074
Eric Andersenc470f442003-07-28 09:56:35 +00002075static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002076static struct alias *freealias(struct alias *);
2077static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002078
Eric Andersenc470f442003-07-28 09:56:35 +00002079static void
2080setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002081{
2082 struct alias *ap, **app;
2083
2084 app = __lookupalias(name);
2085 ap = *app;
2086 INTOFF;
2087 if (ap) {
2088 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002089 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002090 }
Eric Andersenc470f442003-07-28 09:56:35 +00002091 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002092 ap->flag &= ~ALIASDEAD;
2093 } else {
2094 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002095 ap = ckmalloc(sizeof (struct alias));
2096 ap->name = savestr(name);
2097 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002098 ap->flag = 0;
2099 ap->next = 0;
2100 *app = ap;
2101 }
2102 INTON;
2103}
2104
Eric Andersenc470f442003-07-28 09:56:35 +00002105static int
2106unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002107{
Eric Andersencb57d552001-06-28 07:25:16 +00002108 struct alias **app;
2109
2110 app = __lookupalias(name);
2111
2112 if (*app) {
2113 INTOFF;
2114 *app = freealias(*app);
2115 INTON;
2116 return (0);
2117 }
2118
2119 return (1);
2120}
2121
Eric Andersenc470f442003-07-28 09:56:35 +00002122static void
2123rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002124{
Eric Andersencb57d552001-06-28 07:25:16 +00002125 struct alias *ap, **app;
2126 int i;
2127
2128 INTOFF;
2129 for (i = 0; i < ATABSIZE; i++) {
2130 app = &atab[i];
2131 for (ap = *app; ap; ap = *app) {
2132 *app = freealias(*app);
2133 if (ap == *app) {
2134 app = &ap->next;
2135 }
2136 }
2137 }
2138 INTON;
2139}
2140
Eric Andersenc470f442003-07-28 09:56:35 +00002141static struct alias *
2142lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002143{
Eric Andersenc470f442003-07-28 09:56:35 +00002144 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002145
Eric Andersenc470f442003-07-28 09:56:35 +00002146 if (check && ap && (ap->flag & ALIASINUSE))
2147 return (NULL);
2148 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002149}
2150
Eric Andersencb57d552001-06-28 07:25:16 +00002151/*
2152 * TODO - sort output
2153 */
Eric Andersenc470f442003-07-28 09:56:35 +00002154static int
2155aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002156{
2157 char *n, *v;
2158 int ret = 0;
2159 struct alias *ap;
2160
2161 if (argc == 1) {
2162 int i;
2163
2164 for (i = 0; i < ATABSIZE; i++)
2165 for (ap = atab[i]; ap; ap = ap->next) {
2166 printalias(ap);
2167 }
2168 return (0);
2169 }
2170 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002171 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002172 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002173 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002174 ret = 1;
2175 } else
2176 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002177 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002178 *v++ = '\0';
2179 setalias(n, v);
2180 }
2181 }
2182
2183 return (ret);
2184}
2185
Eric Andersenc470f442003-07-28 09:56:35 +00002186static int
2187unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002188{
2189 int i;
2190
2191 while ((i = nextopt("a")) != '\0') {
2192 if (i == 'a') {
2193 rmaliases();
2194 return (0);
2195 }
2196 }
2197 for (i = 0; *argptr; argptr++) {
2198 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002199 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002200 i = 1;
2201 }
2202 }
2203
2204 return (i);
2205}
2206
Eric Andersenc470f442003-07-28 09:56:35 +00002207static struct alias *
2208freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002209 struct alias *next;
2210
2211 if (ap->flag & ALIASINUSE) {
2212 ap->flag |= ALIASDEAD;
2213 return ap;
2214 }
2215
2216 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002217 ckfree(ap->name);
2218 ckfree(ap->val);
2219 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002220 return next;
2221}
2222
Eric Andersenc470f442003-07-28 09:56:35 +00002223static void
2224printalias(const struct alias *ap) {
2225 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2226}
Eric Andersencb57d552001-06-28 07:25:16 +00002227
Eric Andersenc470f442003-07-28 09:56:35 +00002228static struct alias **
2229__lookupalias(const char *name) {
2230 unsigned int hashval;
2231 struct alias **app;
2232 const char *p;
2233 unsigned int ch;
2234
2235 p = name;
2236
2237 ch = (unsigned char)*p;
2238 hashval = ch << 4;
2239 while (ch) {
2240 hashval += ch;
2241 ch = (unsigned char)*++p;
2242 }
2243 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002244
2245 for (; *app; app = &(*app)->next) {
2246 if (equal(name, (*app)->name)) {
2247 break;
2248 }
2249 }
2250
2251 return app;
2252}
Eric Andersenc470f442003-07-28 09:56:35 +00002253#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002254
Eric Andersencb57d552001-06-28 07:25:16 +00002255
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002256/* cd.c */
Eric Andersen2870d962001-07-02 17:27:21 +00002257
Eric Andersencb57d552001-06-28 07:25:16 +00002258/*
Eric Andersenc470f442003-07-28 09:56:35 +00002259 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002260 */
2261
Eric Andersenc470f442003-07-28 09:56:35 +00002262#define CD_PHYSICAL 1
2263#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002264
Eric Andersenc470f442003-07-28 09:56:35 +00002265static int docd(const char *, int);
2266static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002267
Eric Andersenc470f442003-07-28 09:56:35 +00002268static char *curdir = nullstr; /* current working directory */
2269static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002270
Eric Andersenc470f442003-07-28 09:56:35 +00002271static int
2272cdopt(void)
2273{
2274 int flags = 0;
2275 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002276
Eric Andersenc470f442003-07-28 09:56:35 +00002277 j = 'L';
2278 while ((i = nextopt("LP"))) {
2279 if (i != j) {
2280 flags ^= CD_PHYSICAL;
2281 j = i;
2282 }
2283 }
Eric Andersencb57d552001-06-28 07:25:16 +00002284
Eric Andersenc470f442003-07-28 09:56:35 +00002285 return flags;
2286}
Eric Andersen2870d962001-07-02 17:27:21 +00002287
Eric Andersenc470f442003-07-28 09:56:35 +00002288static int
2289cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002290{
2291 const char *dest;
2292 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002293 const char *p;
2294 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002295 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002296 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002297
Eric Andersenc470f442003-07-28 09:56:35 +00002298 flags = cdopt();
2299 dest = *argptr;
2300 if (!dest)
2301 dest = bltinlookup(homestr);
2302 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002303 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002304 flags |= CD_PRINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002305 }
Eric Andersenc470f442003-07-28 09:56:35 +00002306 if (!dest)
2307 dest = nullstr;
2308 if (*dest == '/')
2309 goto step7;
2310 if (*dest == '.') {
2311 c = dest[1];
2312dotdot:
2313 switch (c) {
2314 case '\0':
2315 case '/':
2316 goto step6;
2317 case '.':
2318 c = dest[2];
2319 if (c != '.')
2320 goto dotdot;
2321 }
2322 }
2323 if (!*dest)
2324 dest = ".";
2325 if (!(path = bltinlookup("CDPATH"))) {
2326step6:
2327step7:
2328 p = dest;
2329 goto docd;
2330 }
2331 do {
2332 c = *path;
2333 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002334 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002335 if (c && c != ':')
2336 flags |= CD_PRINT;
2337docd:
2338 if (!docd(p, flags))
2339 goto out;
2340 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002341 }
Eric Andersenc470f442003-07-28 09:56:35 +00002342 } while (path);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002343 sh_error("can't cd to %s", dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002344 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002345out:
2346 if (flags & CD_PRINT)
2347 out1fmt(snlfmt, curdir);
2348 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002349}
2350
2351
2352/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002353 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002354 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002355 */
2356
Eric Andersenc470f442003-07-28 09:56:35 +00002357static inline const char *
2358updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002359{
Eric Andersenc470f442003-07-28 09:56:35 +00002360 char *new;
2361 char *p;
2362 char *cdcomppath;
2363 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002364
Eric Andersenc470f442003-07-28 09:56:35 +00002365 cdcomppath = sstrdup(dir);
2366 STARTSTACKSTR(new);
2367 if (*dir != '/') {
2368 if (curdir == nullstr)
2369 return 0;
2370 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002371 }
Eric Andersenc470f442003-07-28 09:56:35 +00002372 new = makestrspace(strlen(dir) + 2, new);
2373 lim = stackblock() + 1;
2374 if (*dir != '/') {
2375 if (new[-1] != '/')
2376 USTPUTC('/', new);
2377 if (new > lim && *lim == '/')
2378 lim++;
2379 } else {
2380 USTPUTC('/', new);
2381 cdcomppath++;
2382 if (dir[1] == '/' && dir[2] != '/') {
2383 USTPUTC('/', new);
2384 cdcomppath++;
2385 lim++;
2386 }
2387 }
2388 p = strtok(cdcomppath, "/");
2389 while (p) {
2390 switch(*p) {
2391 case '.':
2392 if (p[1] == '.' && p[2] == '\0') {
2393 while (new > lim) {
2394 STUNPUTC(new);
2395 if (new[-1] == '/')
2396 break;
2397 }
2398 break;
2399 } else if (p[1] == '\0')
2400 break;
2401 /* fall through */
2402 default:
2403 new = stputs(p, new);
2404 USTPUTC('/', new);
2405 }
2406 p = strtok(0, "/");
2407 }
2408 if (new > lim)
2409 STUNPUTC(new);
2410 *new = 0;
2411 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002412}
2413
2414/*
Eric Andersenc470f442003-07-28 09:56:35 +00002415 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2416 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002417 */
2418
Eric Andersenc470f442003-07-28 09:56:35 +00002419static int
2420docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002421{
Eric Andersenc470f442003-07-28 09:56:35 +00002422 const char *dir = 0;
2423 int err;
2424
2425 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2426
Eric Andersencb57d552001-06-28 07:25:16 +00002427 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002428 if (!(flags & CD_PHYSICAL)) {
2429 dir = updatepwd(dest);
2430 if (dir)
2431 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002432 }
Eric Andersenc470f442003-07-28 09:56:35 +00002433 err = chdir(dest);
2434 if (err)
2435 goto out;
2436 setpwd(dir, 1);
2437 hashcd();
2438out:
Eric Andersencb57d552001-06-28 07:25:16 +00002439 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002440 return err;
2441}
2442
2443/*
2444 * Find out what the current directory is. If we already know the current
2445 * directory, this routine returns immediately.
2446 */
2447static inline char *
2448getpwd(void)
2449{
2450 char *dir = getcwd(0, 0);
2451 return dir ? dir : nullstr;
2452}
2453
2454static int
2455pwdcmd(int argc, char **argv)
2456{
2457 int flags;
2458 const char *dir = curdir;
2459
2460 flags = cdopt();
2461 if (flags) {
2462 if (physdir == nullstr)
2463 setpwd(dir, 0);
2464 dir = physdir;
2465 }
2466 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002467 return 0;
2468}
2469
Eric Andersenc470f442003-07-28 09:56:35 +00002470static void
2471setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002472{
Eric Andersenc470f442003-07-28 09:56:35 +00002473 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002474
Eric Andersenc470f442003-07-28 09:56:35 +00002475 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002476
Eric Andersencb57d552001-06-28 07:25:16 +00002477 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002478 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002479 }
2480 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002481 if (physdir != nullstr) {
2482 if (physdir != oldcur)
2483 free(physdir);
2484 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002485 }
Eric Andersenc470f442003-07-28 09:56:35 +00002486 if (oldcur == val || !val) {
2487 char *s = getpwd();
2488 physdir = s;
2489 if (!val)
2490 dir = s;
2491 } else
2492 dir = savestr(val);
2493 if (oldcur != dir && oldcur != nullstr) {
2494 free(oldcur);
2495 }
2496 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002497 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002498 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002499}
2500
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002501/* error.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002502
Eric Andersencb57d552001-06-28 07:25:16 +00002503/*
2504 * Errors and exceptions.
2505 */
2506
2507/*
2508 * Code to handle exceptions in C.
2509 */
2510
Eric Andersen2870d962001-07-02 17:27:21 +00002511
Eric Andersencb57d552001-06-28 07:25:16 +00002512
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002513static void exverror(int, const char *, va_list)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002514 ATTRIBUTE_NORETURN;
Eric Andersencb57d552001-06-28 07:25:16 +00002515
2516/*
2517 * Called to raise an exception. Since C doesn't include exceptions, we
2518 * just do a longjmp to the exception handler. The type of exception is
2519 * stored in the global variable "exception".
2520 */
2521
Eric Andersenc470f442003-07-28 09:56:35 +00002522static void
2523exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002524{
2525#ifdef DEBUG
2526 if (handler == NULL)
2527 abort();
2528#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002529 INTOFF;
2530
Eric Andersencb57d552001-06-28 07:25:16 +00002531 exception = e;
2532 longjmp(handler->loc, 1);
2533}
2534
2535
2536/*
2537 * Called from trap.c when a SIGINT is received. (If the user specifies
2538 * that SIGINT is to be trapped or ignored using the trap builtin, then
2539 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002540 * are held using the INTOFF macro. (The test for iflag is just
2541 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002542 */
2543
Eric Andersenc470f442003-07-28 09:56:35 +00002544static void
2545onint(void) {
2546 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002547
Eric Andersencb57d552001-06-28 07:25:16 +00002548 intpending = 0;
"Vladimir N. Oleynik"e6d88ea2005-12-13 13:24:23 +00002549#if 0
2550 /* comment by vodz: its strange for me, this programm don`t use other
2551 signal block */
Eric Andersenc470f442003-07-28 09:56:35 +00002552 sigsetmask(0);
"Vladimir N. Oleynik"e6d88ea2005-12-13 13:24:23 +00002553#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002554 i = EXSIG;
2555 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2556 if (!(rootshell && iflag)) {
2557 signal(SIGINT, SIG_DFL);
2558 raise(SIGINT);
2559 }
2560 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002561 }
Eric Andersenc470f442003-07-28 09:56:35 +00002562 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002563 /* NOTREACHED */
2564}
2565
Eric Andersenc470f442003-07-28 09:56:35 +00002566static void
2567exvwarning(const char *msg, va_list ap)
2568{
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002569 FILE *errs;
Eric Andersencb57d552001-06-28 07:25:16 +00002570
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002571 errs = stderr;
2572 fprintf(errs, "%s: ", arg0);
2573 if (commandname) {
2574 const char *fmt = (!iflag || parsefile->fd) ?
2575 "%s: %d: " : "%s: ";
2576 fprintf(errs, fmt, commandname, startlinno);
2577 }
2578 vfprintf(errs, msg, ap);
2579 outcslow('\n', errs);
Eric Andersenc470f442003-07-28 09:56:35 +00002580}
Eric Andersen2870d962001-07-02 17:27:21 +00002581
Eric Andersencb57d552001-06-28 07:25:16 +00002582/*
Eric Andersenc470f442003-07-28 09:56:35 +00002583 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002584 * is not NULL then error prints an error message using printf style
2585 * formatting. It then raises the error exception.
2586 */
Eric Andersenc470f442003-07-28 09:56:35 +00002587static void
2588exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002589{
Eric Andersencb57d552001-06-28 07:25:16 +00002590#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002591 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002592 TRACE(("exverror(%d, \"", cond));
2593 TRACEV((msg, ap));
2594 TRACE(("\") pid=%d\n", getpid()));
2595 } else
2596 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2597 if (msg)
2598#endif
2599 exvwarning(msg, ap);
2600
2601 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002602 exraise(cond);
2603 /* NOTREACHED */
2604}
2605
2606
Eric Andersenc470f442003-07-28 09:56:35 +00002607static void
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002608sh_error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002609{
Eric Andersencb57d552001-06-28 07:25:16 +00002610 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002611
Eric Andersencb57d552001-06-28 07:25:16 +00002612 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002613 exverror(EXERROR, msg, ap);
2614 /* NOTREACHED */
2615 va_end(ap);
2616}
2617
2618
Eric Andersenc470f442003-07-28 09:56:35 +00002619static void
2620exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002621{
Eric Andersencb57d552001-06-28 07:25:16 +00002622 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002623
Eric Andersencb57d552001-06-28 07:25:16 +00002624 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002625 exverror(cond, msg, ap);
2626 /* NOTREACHED */
2627 va_end(ap);
2628}
2629
Eric Andersencb57d552001-06-28 07:25:16 +00002630/*
Eric Andersenc470f442003-07-28 09:56:35 +00002631 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002632 */
2633
Eric Andersenc470f442003-07-28 09:56:35 +00002634static void
2635sh_warnx(const char *fmt, ...)
2636{
2637 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002638
Eric Andersenc470f442003-07-28 09:56:35 +00002639 va_start(ap, fmt);
2640 exvwarning(fmt, ap);
2641 va_end(ap);
2642}
Eric Andersen2870d962001-07-02 17:27:21 +00002643
Eric Andersencb57d552001-06-28 07:25:16 +00002644
2645/*
2646 * Return a string describing an error. The returned string may be a
2647 * pointer to a static buffer that will be overwritten on the next call.
2648 * Action describes the operation that got the error.
2649 */
2650
Eric Andersenc470f442003-07-28 09:56:35 +00002651static const char *
2652errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002653{
Eric Andersenc470f442003-07-28 09:56:35 +00002654 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002655
Eric Andersenc470f442003-07-28 09:56:35 +00002656 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002657 }
Eric Andersenc470f442003-07-28 09:56:35 +00002658 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002659}
2660
2661
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002662/* eval.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002663
2664/*
2665 * Evaluate a command.
2666 */
Eric Andersencb57d552001-06-28 07:25:16 +00002667
2668/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002669#define EV_EXIT 01 /* exit after evaluating tree */
2670#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2671#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002672
2673
Eric Andersenc470f442003-07-28 09:56:35 +00002674static void evalloop(union node *, int);
2675static void evalfor(union node *, int);
2676static void evalcase(union node *, int);
2677static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002678static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002679static void evalpipe(union node *, int);
2680static void evalcommand(union node *, int);
2681static int evalbltin(const struct builtincmd *, int, char **);
2682static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002683static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002684static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002685
Eric Andersenc470f442003-07-28 09:56:35 +00002686
2687static const struct builtincmd bltin = {
2688 "\0\0", bltincmd
2689};
2690
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002691
Eric Andersencb57d552001-06-28 07:25:16 +00002692/*
2693 * Called to reset things after an exception.
2694 */
2695
Eric Andersencb57d552001-06-28 07:25:16 +00002696/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002697 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002698 */
2699
Eric Andersenc470f442003-07-28 09:56:35 +00002700static int
2701evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002702{
Eric Andersen2870d962001-07-02 17:27:21 +00002703 char *p;
2704 char *concat;
2705 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002706
Eric Andersen2870d962001-07-02 17:27:21 +00002707 if (argc > 1) {
2708 p = argv[1];
2709 if (argc > 2) {
2710 STARTSTACKSTR(concat);
2711 ap = argv + 2;
2712 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002713 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002714 if ((p = *ap++) == NULL)
2715 break;
2716 STPUTC(' ', concat);
2717 }
2718 STPUTC('\0', concat);
2719 p = grabstackstr(concat);
2720 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002721 evalstring(p, ~SKIPEVAL);
2722
Eric Andersen2870d962001-07-02 17:27:21 +00002723 }
2724 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002725}
2726
Eric Andersenc470f442003-07-28 09:56:35 +00002727
Eric Andersencb57d552001-06-28 07:25:16 +00002728/*
2729 * Execute a command or commands contained in a string.
2730 */
2731
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002732static int
2733evalstring(char *s, int mask)
Eric Andersen2870d962001-07-02 17:27:21 +00002734{
Eric Andersencb57d552001-06-28 07:25:16 +00002735 union node *n;
2736 struct stackmark smark;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002737 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002738
Eric Andersencb57d552001-06-28 07:25:16 +00002739 setinputstring(s);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002740 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002741
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002742 skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002743 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002744 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002745 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002746 skip = evalskip;
2747 if (skip)
Eric Andersenc470f442003-07-28 09:56:35 +00002748 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002749 }
2750 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002751
2752 skip &= mask;
2753 evalskip = skip;
2754 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002755}
2756
Eric Andersenc470f442003-07-28 09:56:35 +00002757
Eric Andersen62483552001-07-10 06:09:16 +00002758
2759/*
Eric Andersenc470f442003-07-28 09:56:35 +00002760 * Evaluate a parse tree. The value is left in the global variable
2761 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002762 */
2763
Eric Andersenc470f442003-07-28 09:56:35 +00002764static void
2765evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002766{
Eric Andersenc470f442003-07-28 09:56:35 +00002767 int checkexit = 0;
2768 void (*evalfn)(union node *, int);
2769 unsigned isor;
2770 int status;
2771 if (n == NULL) {
2772 TRACE(("evaltree(NULL) called\n"));
2773 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002774 }
Eric Andersenc470f442003-07-28 09:56:35 +00002775 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2776 getpid(), n, n->type, flags));
2777 switch (n->type) {
2778 default:
2779#ifdef DEBUG
2780 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002781 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002782 break;
2783#endif
2784 case NNOT:
2785 evaltree(n->nnot.com, EV_TESTED);
2786 status = !exitstatus;
2787 goto setstatus;
2788 case NREDIR:
2789 expredir(n->nredir.redirect);
2790 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2791 if (!status) {
2792 evaltree(n->nredir.n, flags & EV_TESTED);
2793 status = exitstatus;
2794 }
2795 popredir(0);
2796 goto setstatus;
2797 case NCMD:
2798 evalfn = evalcommand;
2799checkexit:
2800 if (eflag && !(flags & EV_TESTED))
2801 checkexit = ~0;
2802 goto calleval;
2803 case NFOR:
2804 evalfn = evalfor;
2805 goto calleval;
2806 case NWHILE:
2807 case NUNTIL:
2808 evalfn = evalloop;
2809 goto calleval;
2810 case NSUBSHELL:
2811 case NBACKGND:
2812 evalfn = evalsubshell;
2813 goto calleval;
2814 case NPIPE:
2815 evalfn = evalpipe;
2816 goto checkexit;
2817 case NCASE:
2818 evalfn = evalcase;
2819 goto calleval;
2820 case NAND:
2821 case NOR:
2822 case NSEMI:
2823#if NAND + 1 != NOR
2824#error NAND + 1 != NOR
2825#endif
2826#if NOR + 1 != NSEMI
2827#error NOR + 1 != NSEMI
2828#endif
2829 isor = n->type - NAND;
2830 evaltree(
2831 n->nbinary.ch1,
2832 (flags | ((isor >> 1) - 1)) & EV_TESTED
2833 );
2834 if (!exitstatus == isor)
2835 break;
2836 if (!evalskip) {
2837 n = n->nbinary.ch2;
2838evaln:
2839 evalfn = evaltree;
2840calleval:
2841 evalfn(n, flags);
2842 break;
2843 }
2844 break;
2845 case NIF:
2846 evaltree(n->nif.test, EV_TESTED);
2847 if (evalskip)
2848 break;
2849 if (exitstatus == 0) {
2850 n = n->nif.ifpart;
2851 goto evaln;
2852 } else if (n->nif.elsepart) {
2853 n = n->nif.elsepart;
2854 goto evaln;
2855 }
2856 goto success;
2857 case NDEFUN:
2858 defun(n->narg.text, n->narg.next);
2859success:
2860 status = 0;
2861setstatus:
2862 exitstatus = status;
2863 break;
2864 }
2865out:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002866 if ((checkexit & exitstatus))
2867 evalskip |= SKIPEVAL;
2868 else if (pendingsigs && dotrap())
2869 goto exexit;
2870
2871 if (flags & EV_EXIT) {
2872exexit:
Eric Andersenc470f442003-07-28 09:56:35 +00002873 exraise(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002874 }
Eric Andersen62483552001-07-10 06:09:16 +00002875}
2876
Eric Andersenc470f442003-07-28 09:56:35 +00002877
2878#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2879static
2880#endif
2881void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2882
2883
2884static void
2885evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002886{
2887 int status;
2888
2889 loopnest++;
2890 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002891 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002892 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002893 int i;
2894
Eric Andersencb57d552001-06-28 07:25:16 +00002895 evaltree(n->nbinary.ch1, EV_TESTED);
2896 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002897skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002898 evalskip = 0;
2899 continue;
2900 }
2901 if (evalskip == SKIPBREAK && --skipcount <= 0)
2902 evalskip = 0;
2903 break;
2904 }
Eric Andersenc470f442003-07-28 09:56:35 +00002905 i = exitstatus;
2906 if (n->type != NWHILE)
2907 i = !i;
2908 if (i != 0)
2909 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002910 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002911 status = exitstatus;
2912 if (evalskip)
2913 goto skipping;
2914 }
2915 loopnest--;
2916 exitstatus = status;
2917}
2918
Eric Andersenc470f442003-07-28 09:56:35 +00002919
2920
2921static void
2922evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002923{
2924 struct arglist arglist;
2925 union node *argp;
2926 struct strlist *sp;
2927 struct stackmark smark;
2928
2929 setstackmark(&smark);
2930 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002931 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002932 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002933 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002934 if (evalskip)
2935 goto out;
2936 }
2937 *arglist.lastp = NULL;
2938
2939 exitstatus = 0;
2940 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002941 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002942 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002943 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002944 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002945 if (evalskip) {
2946 if (evalskip == SKIPCONT && --skipcount <= 0) {
2947 evalskip = 0;
2948 continue;
2949 }
2950 if (evalskip == SKIPBREAK && --skipcount <= 0)
2951 evalskip = 0;
2952 break;
2953 }
2954 }
2955 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002956out:
Eric Andersencb57d552001-06-28 07:25:16 +00002957 popstackmark(&smark);
2958}
2959
Eric Andersenc470f442003-07-28 09:56:35 +00002960
2961
2962static void
2963evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002964{
2965 union node *cp;
2966 union node *patp;
2967 struct arglist arglist;
2968 struct stackmark smark;
2969
2970 setstackmark(&smark);
2971 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002972 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002973 exitstatus = 0;
2974 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2975 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002976 if (casematch(patp, arglist.list->text)) {
2977 if (evalskip == 0) {
2978 evaltree(cp->nclist.body, flags);
2979 }
2980 goto out;
2981 }
2982 }
2983 }
Eric Andersenc470f442003-07-28 09:56:35 +00002984out:
Eric Andersencb57d552001-06-28 07:25:16 +00002985 popstackmark(&smark);
2986}
2987
Eric Andersenc470f442003-07-28 09:56:35 +00002988
2989
2990/*
2991 * Kick off a subshell to evaluate a tree.
2992 */
2993
2994static void
2995evalsubshell(union node *n, int flags)
2996{
2997 struct job *jp;
2998 int backgnd = (n->type == NBACKGND);
2999 int status;
3000
3001 expredir(n->nredir.redirect);
3002 if (!backgnd && flags & EV_EXIT && !trap[0])
3003 goto nofork;
3004 INTOFF;
3005 jp = makejob(n, 1);
3006 if (forkshell(jp, n, backgnd) == 0) {
3007 INTON;
3008 flags |= EV_EXIT;
3009 if (backgnd)
3010 flags &=~ EV_TESTED;
3011nofork:
3012 redirect(n->nredir.redirect, 0);
3013 evaltreenr(n->nredir.n, flags);
3014 /* never returns */
3015 }
3016 status = 0;
3017 if (! backgnd)
3018 status = waitforjob(jp);
3019 exitstatus = status;
3020 INTON;
3021}
3022
3023
3024
3025/*
3026 * Compute the names of the files in a redirection list.
3027 */
3028
3029static void
3030expredir(union node *n)
3031{
3032 union node *redir;
3033
3034 for (redir = n ; redir ; redir = redir->nfile.next) {
3035 struct arglist fn;
3036 fn.lastp = &fn.list;
3037 switch (redir->type) {
3038 case NFROMTO:
3039 case NFROM:
3040 case NTO:
3041 case NCLOBBER:
3042 case NAPPEND:
3043 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3044 redir->nfile.expfname = fn.list->text;
3045 break;
3046 case NFROMFD:
3047 case NTOFD:
3048 if (redir->ndup.vname) {
3049 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3050 fixredir(redir, fn.list->text, 1);
3051 }
3052 break;
3053 }
3054 }
3055}
3056
3057
3058
Eric Andersencb57d552001-06-28 07:25:16 +00003059/*
Eric Andersencb57d552001-06-28 07:25:16 +00003060 * Evaluate a pipeline. All the processes in the pipeline are children
3061 * of the process creating the pipeline. (This differs from some versions
3062 * of the shell, which make the last process in a pipeline the parent
3063 * of all the rest.)
3064 */
3065
Eric Andersenc470f442003-07-28 09:56:35 +00003066static void
3067evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003068{
3069 struct job *jp;
3070 struct nodelist *lp;
3071 int pipelen;
3072 int prevfd;
3073 int pip[2];
3074
Eric Andersenc470f442003-07-28 09:56:35 +00003075 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003076 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003077 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003078 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003079 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003080 INTOFF;
3081 jp = makejob(n, pipelen);
3082 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003083 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003084 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003085 pip[1] = -1;
3086 if (lp->next) {
3087 if (pipe(pip) < 0) {
3088 close(prevfd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003089 sh_error("Pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00003090 }
3091 }
3092 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3093 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003094 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003095 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003096 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003097 if (prevfd > 0) {
3098 dup2(prevfd, 0);
3099 close(prevfd);
3100 }
3101 if (pip[1] > 1) {
3102 dup2(pip[1], 1);
3103 close(pip[1]);
3104 }
Eric Andersenc470f442003-07-28 09:56:35 +00003105 evaltreenr(lp->n, flags);
3106 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003107 }
3108 if (prevfd >= 0)
3109 close(prevfd);
3110 prevfd = pip[0];
3111 close(pip[1]);
3112 }
Eric Andersencb57d552001-06-28 07:25:16 +00003113 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003114 exitstatus = waitforjob(jp);
3115 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003116 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003117 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003118}
3119
Eric Andersen62483552001-07-10 06:09:16 +00003120
3121
3122/*
3123 * Execute a command inside back quotes. If it's a builtin command, we
3124 * want to save its output in a block obtained from malloc. Otherwise
3125 * we fork off a subprocess and get the output of the command via a pipe.
3126 * Should be called with interrupts off.
3127 */
3128
Eric Andersenc470f442003-07-28 09:56:35 +00003129static void
3130evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003131{
Eric Andersenc470f442003-07-28 09:56:35 +00003132 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003133
Eric Andersen62483552001-07-10 06:09:16 +00003134 result->fd = -1;
3135 result->buf = NULL;
3136 result->nleft = 0;
3137 result->jp = NULL;
3138 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003139 goto out;
3140 }
Eric Andersenc470f442003-07-28 09:56:35 +00003141
3142 saveherefd = herefd;
3143 herefd = -1;
3144
3145 {
3146 int pip[2];
3147 struct job *jp;
3148
3149 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003150 sh_error("Pipe call failed");
Eric Andersenc470f442003-07-28 09:56:35 +00003151 jp = makejob(n, 1);
3152 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3153 FORCEINTON;
3154 close(pip[0]);
3155 if (pip[1] != 1) {
3156 close(1);
3157 copyfd(pip[1], 1);
3158 close(pip[1]);
3159 }
3160 eflag = 0;
3161 evaltreenr(n, EV_EXIT);
3162 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003163 }
Eric Andersenc470f442003-07-28 09:56:35 +00003164 close(pip[1]);
3165 result->fd = pip[0];
3166 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003167 }
Eric Andersenc470f442003-07-28 09:56:35 +00003168 herefd = saveherefd;
3169out:
Eric Andersen62483552001-07-10 06:09:16 +00003170 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003171 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003172}
3173
Eric Andersenc470f442003-07-28 09:56:35 +00003174#ifdef CONFIG_ASH_CMDCMD
3175static inline char **
3176parse_command_args(char **argv, const char **path)
3177{
3178 char *cp, c;
3179
3180 for (;;) {
3181 cp = *++argv;
3182 if (!cp)
3183 return 0;
3184 if (*cp++ != '-')
3185 break;
3186 if (!(c = *cp++))
3187 break;
3188 if (c == '-' && !*cp) {
3189 argv++;
3190 break;
3191 }
3192 do {
3193 switch (c) {
3194 case 'p':
3195 *path = defpath;
3196 break;
3197 default:
3198 /* run 'typecmd' for other options */
3199 return 0;
3200 }
3201 } while ((c = *cp++));
3202 }
3203 return argv;
3204}
3205#endif
3206
Paul Foxc3850c82005-07-20 18:23:39 +00003207static inline int
3208isassignment(const char *p)
3209{
3210 const char *q = endofname(p);
3211 if (p == q)
3212 return 0;
3213 return *q == '=';
3214}
Eric Andersen62483552001-07-10 06:09:16 +00003215
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003216#ifdef CONFIG_ASH_EXPAND_PRMT
3217static const char *expandstr(const char *ps);
3218#else
3219#define expandstr(s) s
3220#endif
3221
Eric Andersen62483552001-07-10 06:09:16 +00003222/*
3223 * Execute a simple command.
3224 */
Eric Andersencb57d552001-06-28 07:25:16 +00003225
Eric Andersenc470f442003-07-28 09:56:35 +00003226static void
3227evalcommand(union node *cmd, int flags)
3228{
3229 struct stackmark smark;
3230 union node *argp;
3231 struct arglist arglist;
3232 struct arglist varlist;
3233 char **argv;
3234 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003235 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003236 struct cmdentry cmdentry;
3237 struct job *jp;
3238 char *lastarg;
3239 const char *path;
3240 int spclbltin;
3241 int cmd_is_exec;
3242 int status;
3243 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003244 struct builtincmd *bcmd;
3245 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003246
3247 /* First expand the arguments. */
3248 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3249 setstackmark(&smark);
3250 back_exitstatus = 0;
3251
3252 cmdentry.cmdtype = CMDBUILTIN;
3253 cmdentry.u.cmd = &bltin;
3254 varlist.lastp = &varlist.list;
3255 *varlist.lastp = NULL;
3256 arglist.lastp = &arglist.list;
3257 *arglist.lastp = NULL;
3258
3259 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003260 if (cmd->ncmd.args)
3261 {
3262 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3263 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3264 }
3265
Eric Andersenc470f442003-07-28 09:56:35 +00003266 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3267 struct strlist **spp;
3268
3269 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003270 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00003271 expandarg(argp, &arglist, EXP_VARTILDE);
3272 else
3273 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3274
Eric Andersenc470f442003-07-28 09:56:35 +00003275 for (sp = *spp; sp; sp = sp->next)
3276 argc++;
3277 }
3278
3279 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3280 for (sp = arglist.list ; sp ; sp = sp->next) {
3281 TRACE(("evalcommand arg: %s\n", sp->text));
3282 *nargv++ = sp->text;
3283 }
3284 *nargv = NULL;
3285
3286 lastarg = NULL;
3287 if (iflag && funcnest == 0 && argc > 0)
3288 lastarg = nargv[-1];
3289
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003290 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003291 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003292 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003293
3294 path = vpath.text;
3295 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3296 struct strlist **spp;
3297 char *p;
3298
3299 spp = varlist.lastp;
3300 expandarg(argp, &varlist, EXP_VARTILDE);
3301
3302 /*
3303 * Modify the command lookup path, if a PATH= assignment
3304 * is present
3305 */
3306 p = (*spp)->text;
3307 if (varequal(p, path))
3308 path = p;
3309 }
3310
3311 /* Print the command if xflag is set. */
3312 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003313 int n;
3314 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003315
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003316 p++;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003317 dprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003318
3319 sp = varlist.list;
3320 for(n = 0; n < 2; n++) {
3321 while (sp) {
3322 dprintf(preverrout_fd, p, sp->text);
3323 sp = sp->next;
3324 if(*p == '%') {
3325 p--;
3326 }
3327 }
3328 sp = arglist.list;
3329 }
Eric Andersen16767e22004-03-16 05:14:10 +00003330 bb_full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003331 }
3332
3333 cmd_is_exec = 0;
3334 spclbltin = -1;
3335
3336 /* Now locate the command. */
3337 if (argc) {
3338 const char *oldpath;
3339 int cmd_flag = DO_ERR;
3340
3341 path += 5;
3342 oldpath = path;
3343 for (;;) {
3344 find_command(argv[0], &cmdentry, cmd_flag, path);
3345 if (cmdentry.cmdtype == CMDUNKNOWN) {
3346 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003347 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003348 goto bail;
3349 }
3350
3351 /* implement bltin and command here */
3352 if (cmdentry.cmdtype != CMDBUILTIN)
3353 break;
3354 if (spclbltin < 0)
3355 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3356 if (cmdentry.u.cmd == EXECCMD)
3357 cmd_is_exec++;
3358#ifdef CONFIG_ASH_CMDCMD
3359 if (cmdentry.u.cmd == COMMANDCMD) {
3360
3361 path = oldpath;
3362 nargv = parse_command_args(argv, &path);
3363 if (!nargv)
3364 break;
3365 argc -= nargv - argv;
3366 argv = nargv;
3367 cmd_flag |= DO_NOFUNC;
3368 } else
3369#endif
3370 break;
3371 }
3372 }
3373
3374 if (status) {
3375 /* We have a redirection error. */
3376 if (spclbltin > 0)
3377 exraise(EXERROR);
3378bail:
3379 exitstatus = status;
3380 goto out;
3381 }
3382
3383 /* Execute the command. */
3384 switch (cmdentry.cmdtype) {
3385 default:
3386 /* Fork off a child process if necessary. */
3387 if (!(flags & EV_EXIT) || trap[0]) {
3388 INTOFF;
3389 jp = makejob(cmd, 1);
3390 if (forkshell(jp, cmd, FORK_FG) != 0) {
3391 exitstatus = waitforjob(jp);
3392 INTON;
3393 break;
3394 }
3395 FORCEINTON;
3396 }
3397 listsetvar(varlist.list, VEXPORT|VSTACK);
3398 shellexec(argv, path, cmdentry.u.index);
3399 /* NOTREACHED */
3400
3401 case CMDBUILTIN:
3402 cmdenviron = varlist.list;
3403 if (cmdenviron) {
3404 struct strlist *list = cmdenviron;
3405 int i = VNOSET;
3406 if (spclbltin > 0 || argc == 0) {
3407 i = 0;
3408 if (cmd_is_exec && argc > 1)
3409 i = VEXPORT;
3410 }
3411 listsetvar(list, i);
3412 }
3413 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3414 int exit_status;
3415 int i, j;
3416
3417 i = exception;
3418 if (i == EXEXIT)
3419 goto raise;
3420
3421 exit_status = 2;
3422 j = 0;
3423 if (i == EXINT)
3424 j = SIGINT;
3425 if (i == EXSIG)
3426 j = pendingsigs;
3427 if (j)
3428 exit_status = j + 128;
3429 exitstatus = exit_status;
3430
3431 if (i == EXINT || spclbltin > 0) {
3432raise:
3433 longjmp(handler->loc, 1);
3434 }
3435 FORCEINTON;
3436 }
3437 break;
3438
3439 case CMDFUNCTION:
3440 listsetvar(varlist.list, 0);
3441 if (evalfun(cmdentry.u.func, argc, argv, flags))
3442 goto raise;
3443 break;
3444 }
3445
3446out:
3447 popredir(cmd_is_exec);
3448 if (lastarg)
3449 /* dsl: I think this is intended to be used to support
3450 * '_' in 'vi' command mode during line editing...
3451 * However I implemented that within libedit itself.
3452 */
3453 setvar("_", lastarg, 0);
3454 popstackmark(&smark);
3455}
3456
3457static int
3458evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3459 char *volatile savecmdname;
3460 struct jmploc *volatile savehandler;
3461 struct jmploc jmploc;
3462 int i;
3463
3464 savecmdname = commandname;
3465 if ((i = setjmp(jmploc.loc)))
3466 goto cmddone;
3467 savehandler = handler;
3468 handler = &jmploc;
3469 commandname = argv[0];
3470 argptr = argv + 1;
3471 optptr = NULL; /* initialize nextopt */
3472 exitstatus = (*cmd->builtin)(argc, argv);
3473 flushall();
3474cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003475 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003476 commandname = savecmdname;
3477 exsig = 0;
3478 handler = savehandler;
3479
3480 return i;
3481}
3482
3483static int
3484evalfun(struct funcnode *func, int argc, char **argv, int flags)
3485{
3486 volatile struct shparam saveparam;
3487 struct localvar *volatile savelocalvars;
3488 struct jmploc *volatile savehandler;
3489 struct jmploc jmploc;
3490 int e;
3491
3492 saveparam = shellparam;
3493 savelocalvars = localvars;
3494 if ((e = setjmp(jmploc.loc))) {
3495 goto funcdone;
3496 }
3497 INTOFF;
3498 savehandler = handler;
3499 handler = &jmploc;
3500 localvars = NULL;
3501 shellparam.malloc = 0;
3502 func->count++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003503 funcnest++;
Eric Andersenc470f442003-07-28 09:56:35 +00003504 INTON;
3505 shellparam.nparam = argc - 1;
3506 shellparam.p = argv + 1;
3507#ifdef CONFIG_ASH_GETOPTS
3508 shellparam.optind = 1;
3509 shellparam.optoff = -1;
3510#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003511 evaltree(&func->n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00003512funcdone:
3513 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003514 funcnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00003515 freefunc(func);
3516 poplocalvars();
3517 localvars = savelocalvars;
3518 freeparam(&shellparam);
3519 shellparam = saveparam;
3520 handler = savehandler;
3521 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003522 evalskip &= ~SKIPFUNC;
Eric Andersenc470f442003-07-28 09:56:35 +00003523 return e;
3524}
3525
3526
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003527static inline int
3528goodname(const char *p)
3529{
3530 return !*endofname(p);
3531}
3532
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003533/*
3534 * Search for a command. This is called before we fork so that the
3535 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003536 * the child. The check for "goodname" is an overly conservative
3537 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003538 */
3539
Eric Andersenc470f442003-07-28 09:56:35 +00003540static void
3541prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003542{
3543 struct cmdentry entry;
3544
3545 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003546 if (goodname(n->ncmd.args->narg.text))
3547 find_command(n->ncmd.args->narg.text, &entry, 0,
3548 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003549}
3550
Eric Andersencb57d552001-06-28 07:25:16 +00003551
Eric Andersenc470f442003-07-28 09:56:35 +00003552
Eric Andersencb57d552001-06-28 07:25:16 +00003553/*
3554 * Builtin commands. Builtin commands whose functions are closely
3555 * tied to evaluation are implemented here.
3556 */
3557
3558/*
Eric Andersenc470f442003-07-28 09:56:35 +00003559 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003560 */
3561
Eric Andersenc470f442003-07-28 09:56:35 +00003562static int
3563bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003564{
3565 /*
3566 * Preserve exitstatus of a previous possible redirection
3567 * as POSIX mandates
3568 */
Eric Andersenc470f442003-07-28 09:56:35 +00003569 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003570}
3571
3572
3573/*
3574 * Handle break and continue commands. Break, continue, and return are
3575 * all handled by setting the evalskip flag. The evaluation routines
3576 * above all check this flag, and if it is set they start skipping
3577 * commands rather than executing them. The variable skipcount is
3578 * the number of loops to break/continue, or the number of function
3579 * levels to return. (The latter is always 1.) It should probably
3580 * be an error to break out of more loops than exist, but it isn't
3581 * in the standard shell so we don't make it one here.
3582 */
3583
Eric Andersenc470f442003-07-28 09:56:35 +00003584static int
3585breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003586{
3587 int n = argc > 1 ? number(argv[1]) : 1;
3588
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003589 if (n <= 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003590 sh_error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003591 if (n > loopnest)
3592 n = loopnest;
3593 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003594 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003595 skipcount = n;
3596 }
3597 return 0;
3598}
3599
3600
3601/*
3602 * The return command.
3603 */
3604
Eric Andersenc470f442003-07-28 09:56:35 +00003605static int
3606returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003607{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003608 /*
3609 * If called outside a function, do what ksh does;
3610 * skip the rest of the file.
3611 */
3612 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
3613 return argv[1] ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003614}
3615
3616
Eric Andersenc470f442003-07-28 09:56:35 +00003617static int
3618falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003619{
3620 return 1;
3621}
3622
Eric Andersenc470f442003-07-28 09:56:35 +00003623
3624static int
3625truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003626{
3627 return 0;
3628}
Eric Andersen2870d962001-07-02 17:27:21 +00003629
Eric Andersencb57d552001-06-28 07:25:16 +00003630
Eric Andersenc470f442003-07-28 09:56:35 +00003631static int
3632execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003633{
3634 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003635 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003636 mflag = 0;
3637 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003638 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003639 }
3640 return 0;
3641}
3642
Eric Andersenc470f442003-07-28 09:56:35 +00003643
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003644/* exec.c */
Eric Andersenc470f442003-07-28 09:56:35 +00003645
3646/*
3647 * When commands are first encountered, they are entered in a hash table.
3648 * This ensures that a full path search will not have to be done for them
3649 * on each invocation.
3650 *
3651 * We should investigate converting to a linear search, even though that
3652 * would make the command name "hash" a misnomer.
3653 */
3654
3655#define CMDTABLESIZE 31 /* should be prime */
3656#define ARB 1 /* actual size determined at run time */
3657
3658
3659
3660struct tblentry {
3661 struct tblentry *next; /* next entry in hash chain */
3662 union param param; /* definition of builtin function */
3663 short cmdtype; /* index identifying command */
3664 char rehash; /* if set, cd done since entry created */
3665 char cmdname[ARB]; /* name of command */
3666};
3667
3668
3669static struct tblentry *cmdtable[CMDTABLESIZE];
3670static int builtinloc = -1; /* index in path of %builtin, or -1 */
3671
3672
3673static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003674static void clearcmdentry(int);
3675static struct tblentry *cmdlookup(const char *, int);
3676static void delete_cmd_entry(void);
3677
Eric Andersencb57d552001-06-28 07:25:16 +00003678
3679/*
3680 * Exec a program. Never returns. If you change this routine, you may
3681 * have to change the find_command routine as well.
3682 */
3683
Eric Andersenc470f442003-07-28 09:56:35 +00003684static void
3685shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003686{
3687 char *cmdname;
3688 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003689 char **envp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003690 int exerrno;
Eric Andersencb57d552001-06-28 07:25:16 +00003691
Eric Andersenc470f442003-07-28 09:56:35 +00003692 clearredir(1);
3693 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003694 if (strchr(argv[0], '/') != NULL
3695#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3696 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003697#endif
3698 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003699 tryexec(argv[0], argv, envp);
3700 e = errno;
3701 } else {
3702 e = ENOENT;
3703 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3704 if (--idx < 0 && pathopt == NULL) {
3705 tryexec(cmdname, argv, envp);
3706 if (errno != ENOENT && errno != ENOTDIR)
3707 e = errno;
3708 }
3709 stunalloc(cmdname);
3710 }
3711 }
3712
3713 /* Map to POSIX errors */
3714 switch (e) {
3715 case EACCES:
3716 exerrno = 126;
3717 break;
3718 case ENOENT:
3719 exerrno = 127;
3720 break;
3721 default:
3722 exerrno = 2;
3723 break;
3724 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003725 exitstatus = exerrno;
Eric Andersenc470f442003-07-28 09:56:35 +00003726 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3727 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003728 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3729 /* NOTREACHED */
3730}
3731
Eric Andersen2870d962001-07-02 17:27:21 +00003732
Eric Andersenc470f442003-07-28 09:56:35 +00003733static void
3734tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003735{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003736 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003737#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003738 if(find_applet_by_name(cmd) != NULL) {
3739 /* re-exec ourselves with the new arguments */
Rob Landleya34b48a2006-06-14 01:27:01 +00003740 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp);
Rob Landley0fcd9432005-05-07 08:27:34 +00003741 /* If they called chroot or otherwise made the binary no longer
3742 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003743 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003744#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003745
3746repeat:
3747#ifdef SYSV
3748 do {
3749 execve(cmd, argv, envp);
3750 } while (errno == EINTR);
3751#else
Eric Andersencb57d552001-06-28 07:25:16 +00003752 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003753#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003754 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003755 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003756 } else if (errno == ENOEXEC) {
3757 char **ap;
3758 char **new;
3759
Eric Andersenc470f442003-07-28 09:56:35 +00003760 for (ap = argv; *ap; ap++)
3761 ;
3762 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003763 ap[1] = cmd;
3764 *ap = cmd = (char *)DEFAULT_SHELL;
3765 ap += 2;
3766 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003767 while ((*ap++ = *argv++))
3768 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003769 argv = new;
3770 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003771 }
Eric Andersencb57d552001-06-28 07:25:16 +00003772}
3773
Eric Andersenc470f442003-07-28 09:56:35 +00003774
Eric Andersencb57d552001-06-28 07:25:16 +00003775
3776/*
3777 * Do a path search. The variable path (passed by reference) should be
3778 * set to the start of the path before the first call; padvance will update
3779 * this value as it proceeds. Successive calls to padvance will return
3780 * the possible path expansions in sequence. If an option (indicated by
3781 * a percent sign) appears in the path entry then the global variable
3782 * pathopt will be set to point to it; otherwise pathopt will be set to
3783 * NULL.
3784 */
3785
Eric Andersenc470f442003-07-28 09:56:35 +00003786static char *
3787padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003788{
Eric Andersencb57d552001-06-28 07:25:16 +00003789 const char *p;
3790 char *q;
3791 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003792 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003793
3794 if (*path == NULL)
3795 return NULL;
3796 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003797 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3798 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003799 while (stackblocksize() < len)
3800 growstackblock();
3801 q = stackblock();
3802 if (p != start) {
3803 memcpy(q, start, p - start);
3804 q += p - start;
3805 *q++ = '/';
3806 }
3807 strcpy(q, name);
3808 pathopt = NULL;
3809 if (*p == '%') {
3810 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003811 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003812 }
3813 if (*p == ':')
3814 *path = p + 1;
3815 else
3816 *path = NULL;
3817 return stalloc(len);
3818}
3819
3820
Eric Andersencb57d552001-06-28 07:25:16 +00003821/*** Command hashing code ***/
3822
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003823static void
3824printentry(struct tblentry *cmdp)
3825{
3826 int idx;
3827 const char *path;
3828 char *name;
3829
3830 idx = cmdp->param.index;
3831 path = pathval();
3832 do {
3833 name = padvance(&path, cmdp->cmdname);
3834 stunalloc(name);
3835 } while (--idx >= 0);
3836 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3837}
3838
Eric Andersenc470f442003-07-28 09:56:35 +00003839
3840static int
3841hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003842{
3843 struct tblentry **pp;
3844 struct tblentry *cmdp;
3845 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003846 struct cmdentry entry;
3847 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003848
Eric Andersenc470f442003-07-28 09:56:35 +00003849 while ((c = nextopt("r")) != '\0') {
3850 clearcmdentry(0);
3851 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003852 }
3853 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003854 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3855 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3856 if (cmdp->cmdtype == CMDNORMAL)
3857 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003858 }
3859 }
3860 return 0;
3861 }
3862 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003863 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003864 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003865 && (cmdp->cmdtype == CMDNORMAL
3866 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003867 delete_cmd_entry();
3868 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003869 if (entry.cmdtype == CMDUNKNOWN)
3870 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003871 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003872 }
3873 return c;
3874}
3875
Eric Andersenc470f442003-07-28 09:56:35 +00003876
Eric Andersencb57d552001-06-28 07:25:16 +00003877/*
3878 * Resolve a command name. If you change this routine, you may have to
3879 * change the shellexec routine as well.
3880 */
3881
3882static void
Eric Andersenc470f442003-07-28 09:56:35 +00003883find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003884{
3885 struct tblentry *cmdp;
3886 int idx;
3887 int prev;
3888 char *fullname;
3889 struct stat statb;
3890 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003891 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003892 struct builtincmd *bcmd;
3893
Eric Andersenc470f442003-07-28 09:56:35 +00003894 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003895 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003896 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003897 if (act & DO_ABS) {
3898 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003899#ifdef SYSV
3900 if (errno == EINTR)
3901 continue;
3902#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003903 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003904 return;
3905 }
Eric Andersencb57d552001-06-28 07:25:16 +00003906 }
3907 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003908 return;
3909 }
3910
Eric Andersenbf8bf102002-09-17 08:41:08 +00003911#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3912 if (find_applet_by_name(name)) {
3913 entry->cmdtype = CMDNORMAL;
3914 entry->u.index = -1;
3915 return;
3916 }
3917#endif
3918
Eric Andersenc470f442003-07-28 09:56:35 +00003919 updatetbl = (path == pathval());
3920 if (!updatetbl) {
3921 act |= DO_ALTPATH;
3922 if (strstr(path, "%builtin") != NULL)
3923 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003924 }
3925
Eric Andersenc470f442003-07-28 09:56:35 +00003926 /* If name is in the table, check answer will be ok */
3927 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3928 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003929
Eric Andersenc470f442003-07-28 09:56:35 +00003930 switch (cmdp->cmdtype) {
3931 default:
3932#if DEBUG
3933 abort();
3934#endif
3935 case CMDNORMAL:
3936 bit = DO_ALTPATH;
3937 break;
3938 case CMDFUNCTION:
3939 bit = DO_NOFUNC;
3940 break;
3941 case CMDBUILTIN:
3942 bit = DO_ALTBLTIN;
3943 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003944 }
Eric Andersenc470f442003-07-28 09:56:35 +00003945 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003946 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003947 cmdp = NULL;
3948 } else if (cmdp->rehash == 0)
3949 /* if not invalidated by cd, we're done */
3950 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003951 }
3952
3953 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003954 bcmd = find_builtin(name);
3955 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3956 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3957 )))
3958 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003959
3960 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003961 prev = -1; /* where to start */
3962 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003963 if (cmdp->cmdtype == CMDBUILTIN)
3964 prev = builtinloc;
3965 else
3966 prev = cmdp->param.index;
3967 }
3968
3969 e = ENOENT;
3970 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003971loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003972 while ((fullname = padvance(&path, name)) != NULL) {
3973 stunalloc(fullname);
3974 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003975 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003976 if (prefix(pathopt, "builtin")) {
3977 if (bcmd)
3978 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003979 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003980 } else if (!(act & DO_NOFUNC) &&
3981 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003982 /* handled below */
3983 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003984 /* ignore unimplemented options */
3985 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003986 }
3987 }
3988 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003989 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003990 if (idx < prev)
3991 continue;
3992 TRACE(("searchexec \"%s\": no change\n", name));
3993 goto success;
3994 }
3995 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003996#ifdef SYSV
3997 if (errno == EINTR)
3998 continue;
3999#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004000 if (errno != ENOENT && errno != ENOTDIR)
4001 e = errno;
4002 goto loop;
4003 }
Eric Andersenc470f442003-07-28 09:56:35 +00004004 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004005 if (!S_ISREG(statb.st_mode))
4006 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004007 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004008 stalloc(strlen(fullname) + 1);
4009 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004010 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4011 cmdp->cmdtype != CMDFUNCTION)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004012 sh_error("%s not defined in %s", name, fullname);
Eric Andersencb57d552001-06-28 07:25:16 +00004013 stunalloc(fullname);
4014 goto success;
4015 }
Eric Andersencb57d552001-06-28 07:25:16 +00004016 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004017 if (!updatetbl) {
4018 entry->cmdtype = CMDNORMAL;
4019 entry->u.index = idx;
4020 return;
4021 }
4022 INTOFF;
4023 cmdp = cmdlookup(name, 1);
4024 cmdp->cmdtype = CMDNORMAL;
4025 cmdp->param.index = idx;
4026 INTON;
4027 goto success;
4028 }
4029
4030 /* We failed. If there was an entry for this command, delete it */
4031 if (cmdp && updatetbl)
4032 delete_cmd_entry();
4033 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004034 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004035 entry->cmdtype = CMDUNKNOWN;
4036 return;
4037
Eric Andersenc470f442003-07-28 09:56:35 +00004038builtin_success:
4039 if (!updatetbl) {
4040 entry->cmdtype = CMDBUILTIN;
4041 entry->u.cmd = bcmd;
4042 return;
4043 }
4044 INTOFF;
4045 cmdp = cmdlookup(name, 1);
4046 cmdp->cmdtype = CMDBUILTIN;
4047 cmdp->param.cmd = bcmd;
4048 INTON;
4049success:
Eric Andersencb57d552001-06-28 07:25:16 +00004050 cmdp->rehash = 0;
4051 entry->cmdtype = cmdp->cmdtype;
4052 entry->u = cmdp->param;
4053}
4054
4055
Eric Andersenc470f442003-07-28 09:56:35 +00004056/*
4057 * Wrapper around strcmp for qsort/bsearch/...
4058 */
4059static int pstrcmp(const void *a, const void *b)
4060{
4061 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4062}
Eric Andersencb57d552001-06-28 07:25:16 +00004063
4064/*
4065 * Search the table of builtin commands.
4066 */
4067
Eric Andersenc470f442003-07-28 09:56:35 +00004068static struct builtincmd *
4069find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004070{
4071 struct builtincmd *bp;
4072
Eric Andersenc470f442003-07-28 09:56:35 +00004073 bp = bsearch(
4074 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4075 pstrcmp
4076 );
Eric Andersencb57d552001-06-28 07:25:16 +00004077 return bp;
4078}
4079
4080
Eric Andersenc470f442003-07-28 09:56:35 +00004081
Eric Andersencb57d552001-06-28 07:25:16 +00004082/*
4083 * Called when a cd is done. Marks all commands so the next time they
4084 * are executed they will be rehashed.
4085 */
4086
Eric Andersenc470f442003-07-28 09:56:35 +00004087static void
4088hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004089{
Eric Andersencb57d552001-06-28 07:25:16 +00004090 struct tblentry **pp;
4091 struct tblentry *cmdp;
4092
Eric Andersenc470f442003-07-28 09:56:35 +00004093 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4094 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4095 if (cmdp->cmdtype == CMDNORMAL || (
4096 cmdp->cmdtype == CMDBUILTIN &&
4097 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4098 builtinloc > 0
4099 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004100 cmdp->rehash = 1;
4101 }
4102 }
4103}
4104
4105
4106
4107/*
Eric Andersenc470f442003-07-28 09:56:35 +00004108 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004109 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004110 * pathval() still returns the old value at this point.
4111 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004112 */
4113
Eric Andersenc470f442003-07-28 09:56:35 +00004114static void
4115changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004116{
Eric Andersenc470f442003-07-28 09:56:35 +00004117 const char *old, *new;
4118 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004119 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004120 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004121
Eric Andersenc470f442003-07-28 09:56:35 +00004122 old = pathval();
4123 new = newval;
4124 firstchange = 9999; /* assume no change */
4125 idx = 0;
4126 idx_bltin = -1;
4127 for (;;) {
4128 if (*old != *new) {
4129 firstchange = idx;
4130 if ((*old == '\0' && *new == ':')
4131 || (*old == ':' && *new == '\0'))
4132 firstchange++;
4133 old = new; /* ignore subsequent differences */
4134 }
4135 if (*new == '\0')
4136 break;
4137 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4138 idx_bltin = idx;
4139 if (*new == ':') {
4140 idx++;
4141 }
4142 new++, old++;
4143 }
4144 if (builtinloc < 0 && idx_bltin >= 0)
4145 builtinloc = idx_bltin; /* zap builtins */
4146 if (builtinloc >= 0 && idx_bltin < 0)
4147 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004148 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004149 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004150}
4151
4152
4153/*
4154 * Clear out command entries. The argument specifies the first entry in
4155 * PATH which has changed.
4156 */
4157
Eric Andersenc470f442003-07-28 09:56:35 +00004158static void
4159clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004160{
4161 struct tblentry **tblp;
4162 struct tblentry **pp;
4163 struct tblentry *cmdp;
4164
4165 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004166 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004167 pp = tblp;
4168 while ((cmdp = *pp) != NULL) {
4169 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004170 cmdp->param.index >= firstchange)
4171 || (cmdp->cmdtype == CMDBUILTIN &&
4172 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004173 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004174 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004175 } else {
4176 pp = &cmdp->next;
4177 }
4178 }
4179 }
4180 INTON;
4181}
4182
4183
Eric Andersenc470f442003-07-28 09:56:35 +00004184
Eric Andersencb57d552001-06-28 07:25:16 +00004185/*
Eric Andersencb57d552001-06-28 07:25:16 +00004186 * Locate a command in the command hash table. If "add" is nonzero,
4187 * add the command to the table if it is not already present. The
4188 * variable "lastcmdentry" is set to point to the address of the link
4189 * pointing to the entry, so that delete_cmd_entry can delete the
4190 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004191 *
4192 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004193 */
4194
Eric Andersen2870d962001-07-02 17:27:21 +00004195static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004196
Eric Andersenc470f442003-07-28 09:56:35 +00004197
4198static struct tblentry *
4199cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004200{
Eric Andersenc470f442003-07-28 09:56:35 +00004201 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004202 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004203 struct tblentry *cmdp;
4204 struct tblentry **pp;
4205
4206 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004207 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004208 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004209 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004210 hashval &= 0x7FFF;
4211 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004212 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004213 if (equal(cmdp->cmdname, name))
4214 break;
4215 pp = &cmdp->next;
4216 }
4217 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004218 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4219 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004220 cmdp->next = NULL;
4221 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004222 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004223 }
4224 lastcmdentry = pp;
4225 return cmdp;
4226}
4227
4228/*
4229 * Delete the command entry returned on the last lookup.
4230 */
4231
Eric Andersenc470f442003-07-28 09:56:35 +00004232static void
4233delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004234{
Eric Andersencb57d552001-06-28 07:25:16 +00004235 struct tblentry *cmdp;
4236
4237 INTOFF;
4238 cmdp = *lastcmdentry;
4239 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004240 if (cmdp->cmdtype == CMDFUNCTION)
4241 freefunc(cmdp->param.func);
4242 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004243 INTON;
4244}
4245
4246
Eric Andersenc470f442003-07-28 09:56:35 +00004247/*
4248 * Add a new command entry, replacing any existing command entry for
4249 * the same name - except special builtins.
4250 */
Eric Andersencb57d552001-06-28 07:25:16 +00004251
Eric Andersenc470f442003-07-28 09:56:35 +00004252static inline void
4253addcmdentry(char *name, struct cmdentry *entry)
4254{
4255 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004256
Eric Andersenc470f442003-07-28 09:56:35 +00004257 cmdp = cmdlookup(name, 1);
4258 if (cmdp->cmdtype == CMDFUNCTION) {
4259 freefunc(cmdp->param.func);
4260 }
4261 cmdp->cmdtype = entry->cmdtype;
4262 cmdp->param = entry->u;
4263 cmdp->rehash = 0;
4264}
Eric Andersencb57d552001-06-28 07:25:16 +00004265
Eric Andersenc470f442003-07-28 09:56:35 +00004266/*
4267 * Make a copy of a parse tree.
4268 */
Eric Andersencb57d552001-06-28 07:25:16 +00004269
Eric Andersenc470f442003-07-28 09:56:35 +00004270static inline struct funcnode *
4271copyfunc(union node *n)
4272{
4273 struct funcnode *f;
4274 size_t blocksize;
4275
4276 funcblocksize = offsetof(struct funcnode, n);
4277 funcstringsize = 0;
4278 calcsize(n);
4279 blocksize = funcblocksize;
4280 f = ckmalloc(blocksize + funcstringsize);
4281 funcblock = (char *) f + offsetof(struct funcnode, n);
4282 funcstring = (char *) f + blocksize;
4283 copynode(n);
4284 f->count = 0;
4285 return f;
4286}
4287
4288/*
4289 * Define a shell function.
4290 */
4291
4292static void
4293defun(char *name, union node *func)
4294{
4295 struct cmdentry entry;
4296
4297 INTOFF;
4298 entry.cmdtype = CMDFUNCTION;
4299 entry.u.func = copyfunc(func);
4300 addcmdentry(name, &entry);
4301 INTON;
4302}
Eric Andersencb57d552001-06-28 07:25:16 +00004303
4304
4305/*
4306 * Delete a function if it exists.
4307 */
4308
Eric Andersenc470f442003-07-28 09:56:35 +00004309static void
4310unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004311{
Eric Andersencb57d552001-06-28 07:25:16 +00004312 struct tblentry *cmdp;
4313
Eric Andersenc470f442003-07-28 09:56:35 +00004314 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4315 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004316 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004317}
4318
Eric Andersen2870d962001-07-02 17:27:21 +00004319/*
Eric Andersencb57d552001-06-28 07:25:16 +00004320 * Locate and print what a word is...
4321 */
4322
Eric Andersenc470f442003-07-28 09:56:35 +00004323
4324#ifdef CONFIG_ASH_CMDCMD
4325static int
4326describe_command(char *command, int describe_command_verbose)
4327#else
4328#define describe_command_verbose 1
4329static int
4330describe_command(char *command)
4331#endif
4332{
4333 struct cmdentry entry;
4334 struct tblentry *cmdp;
4335#ifdef CONFIG_ASH_ALIAS
4336 const struct alias *ap;
4337#endif
4338 const char *path = pathval();
4339
4340 if (describe_command_verbose) {
4341 out1str(command);
4342 }
4343
4344 /* First look at the keywords */
4345 if (findkwd(command)) {
4346 out1str(describe_command_verbose ? " is a shell keyword" : command);
4347 goto out;
4348 }
4349
4350#ifdef CONFIG_ASH_ALIAS
4351 /* Then look at the aliases */
4352 if ((ap = lookupalias(command, 0)) != NULL) {
4353 if (describe_command_verbose) {
4354 out1fmt(" is an alias for %s", ap->val);
4355 } else {
4356 out1str("alias ");
4357 printalias(ap);
4358 return 0;
4359 }
4360 goto out;
4361 }
4362#endif
4363 /* Then check if it is a tracked alias */
4364 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4365 entry.cmdtype = cmdp->cmdtype;
4366 entry.u = cmdp->param;
4367 } else {
4368 /* Finally use brute force */
4369 find_command(command, &entry, DO_ABS, path);
4370 }
4371
4372 switch (entry.cmdtype) {
4373 case CMDNORMAL: {
4374 int j = entry.u.index;
4375 char *p;
4376 if (j == -1) {
4377 p = command;
4378 } else {
4379 do {
4380 p = padvance(&path, command);
4381 stunalloc(p);
4382 } while (--j >= 0);
4383 }
4384 if (describe_command_verbose) {
4385 out1fmt(" is%s %s",
4386 (cmdp ? " a tracked alias for" : nullstr), p
4387 );
4388 } else {
4389 out1str(p);
4390 }
4391 break;
4392 }
4393
4394 case CMDFUNCTION:
4395 if (describe_command_verbose) {
4396 out1str(" is a shell function");
4397 } else {
4398 out1str(command);
4399 }
4400 break;
4401
4402 case CMDBUILTIN:
4403 if (describe_command_verbose) {
4404 out1fmt(" is a %sshell builtin",
4405 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4406 "special " : nullstr
4407 );
4408 } else {
4409 out1str(command);
4410 }
4411 break;
4412
4413 default:
4414 if (describe_command_verbose) {
4415 out1str(": not found\n");
4416 }
4417 return 127;
4418 }
4419
4420out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004421 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004422 return 0;
4423}
4424
4425static int
4426typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004427{
4428 int i;
4429 int err = 0;
4430
4431 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004432#ifdef CONFIG_ASH_CMDCMD
4433 err |= describe_command(argv[i], 1);
4434#else
4435 err |= describe_command(argv[i]);
4436#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004437 }
4438 return err;
4439}
4440
Eric Andersend35c5df2002-01-09 15:37:36 +00004441#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004442static int
4443commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004444{
4445 int c;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004446 enum {
4447 VERIFY_BRIEF = 1,
4448 VERIFY_VERBOSE = 2,
4449 } verify = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004450
4451 while ((c = nextopt("pvV")) != '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004452 if (c == 'V')
4453 verify |= VERIFY_VERBOSE;
4454 else if (c == 'v')
4455 verify |= VERIFY_BRIEF;
Eric Andersenc470f442003-07-28 09:56:35 +00004456#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004457 else if (c != 'p')
4458 abort();
Eric Andersenc470f442003-07-28 09:56:35 +00004459#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004460 if (verify)
4461 return describe_command(*argptr, verify - VERIFY_BRIEF);
Eric Andersencb57d552001-06-28 07:25:16 +00004462
4463 return 0;
4464}
Eric Andersen2870d962001-07-02 17:27:21 +00004465#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004466
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004467/* expand.c */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004468
Eric Andersencb57d552001-06-28 07:25:16 +00004469/*
4470 * Routines to expand arguments to commands. We have to deal with
4471 * backquotes, shell variables, and file metacharacters.
4472 */
Eric Andersenc470f442003-07-28 09:56:35 +00004473
Eric Andersencb57d552001-06-28 07:25:16 +00004474/*
4475 * _rmescape() flags
4476 */
Eric Andersenc470f442003-07-28 09:56:35 +00004477#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4478#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4479#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4480#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4481#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004482
4483/*
4484 * Structure specifying which parts of the string should be searched
4485 * for IFS characters.
4486 */
4487
4488struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004489 struct ifsregion *next; /* next region in list */
4490 int begoff; /* offset of start of region */
4491 int endoff; /* offset of end of region */
4492 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004493};
4494
Eric Andersenc470f442003-07-28 09:56:35 +00004495/* output of current string */
4496static char *expdest;
4497/* list of back quote expressions */
4498static struct nodelist *argbackq;
4499/* first struct in list of ifs regions */
4500static struct ifsregion ifsfirst;
4501/* last struct in list */
4502static struct ifsregion *ifslastp;
4503/* holds expanded arg list */
4504static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004505
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004506static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004507static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004508static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004509static const char *subevalvar(char *, char *, int, int, int, int, int);
4510static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004511static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004512static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004513static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004514static void recordregion(int, int, int);
4515static void removerecordregions(int);
4516static void ifsbreakup(char *, struct arglist *);
4517static void ifsfree(void);
4518static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004519static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004520
Eric Andersened9ecf72004-06-22 08:29:45 +00004521static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004522static size_t esclen(const char *, const char *);
4523static char *scanleft(char *, char *, char *, char *, int, int);
4524static char *scanright(char *, char *, char *, char *, int, int);
4525static void varunset(const char *, const char *, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00004526 ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004527
Eric Andersenc470f442003-07-28 09:56:35 +00004528
4529#define pmatch(a, b) !fnmatch((a), (b), 0)
4530/*
Eric Andersen90898442003-08-06 11:20:52 +00004531 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004532 *
4533 * Returns an stalloced string.
4534 */
4535
4536static inline char *
4537preglob(const char *pattern, int quoted, int flag) {
4538 flag |= RMESCAPE_GLOB;
4539 if (quoted) {
4540 flag |= RMESCAPE_QUOTED;
4541 }
4542 return _rmescapes((char *)pattern, flag);
4543}
4544
4545
4546static size_t
4547esclen(const char *start, const char *p) {
4548 size_t esc = 0;
4549
4550 while (p > start && *--p == CTLESC) {
4551 esc++;
4552 }
4553 return esc;
4554}
4555
Eric Andersencb57d552001-06-28 07:25:16 +00004556
4557/*
4558 * Expand shell variables and backquotes inside a here document.
4559 */
4560
Eric Andersenc470f442003-07-28 09:56:35 +00004561static inline void
4562expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004563{
Eric Andersencb57d552001-06-28 07:25:16 +00004564 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004565 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004566 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004567}
4568
4569
4570/*
4571 * Perform variable substitution and command substitution on an argument,
4572 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4573 * perform splitting and file name expansion. When arglist is NULL, perform
4574 * here document expansion.
4575 */
4576
Eric Andersenc470f442003-07-28 09:56:35 +00004577void
4578expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004579{
4580 struct strlist *sp;
4581 char *p;
4582
4583 argbackq = arg->narg.backquote;
4584 STARTSTACKSTR(expdest);
4585 ifsfirst.next = NULL;
4586 ifslastp = NULL;
4587 argstr(arg->narg.text, flag);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004588 p = _STPUTC('\0', expdest);
4589 expdest = p - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004590 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004591 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004592 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004593 p = grabstackstr(p);
Eric Andersencb57d552001-06-28 07:25:16 +00004594 exparg.lastp = &exparg.list;
4595 /*
4596 * TODO - EXP_REDIR
4597 */
4598 if (flag & EXP_FULL) {
4599 ifsbreakup(p, &exparg);
4600 *exparg.lastp = NULL;
4601 exparg.lastp = &exparg.list;
4602 expandmeta(exparg.list, flag);
4603 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004604 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004605 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004606 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004607 sp->text = p;
4608 *exparg.lastp = sp;
4609 exparg.lastp = &sp->next;
4610 }
Eric Andersenc470f442003-07-28 09:56:35 +00004611 if (ifsfirst.next)
4612 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004613 *exparg.lastp = NULL;
4614 if (exparg.list) {
4615 *arglist->lastp = exparg.list;
4616 arglist->lastp = exparg.lastp;
4617 }
4618}
4619
4620
Eric Andersenc470f442003-07-28 09:56:35 +00004621/*
4622 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4623 * characters to allow for further processing. Otherwise treat
4624 * $@ like $* since no splitting will be performed.
4625 */
4626
4627static void
4628argstr(char *p, int flag)
4629{
4630 static const char spclchars[] = {
4631 '=',
4632 ':',
4633 CTLQUOTEMARK,
4634 CTLENDVAR,
4635 CTLESC,
4636 CTLVAR,
4637 CTLBACKQ,
4638 CTLBACKQ | CTLQUOTE,
4639#ifdef CONFIG_ASH_MATH_SUPPORT
4640 CTLENDARI,
4641#endif
4642 0
4643 };
4644 const char *reject = spclchars;
4645 int c;
4646 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4647 int breakall = flag & EXP_WORD;
4648 int inquotes;
4649 size_t length;
4650 int startloc;
4651
4652 if (!(flag & EXP_VARTILDE)) {
4653 reject += 2;
4654 } else if (flag & EXP_VARTILDE2) {
4655 reject++;
4656 }
4657 inquotes = 0;
4658 length = 0;
4659 if (flag & EXP_TILDE) {
4660 char *q;
4661
4662 flag &= ~EXP_TILDE;
4663tilde:
4664 q = p;
4665 if (*q == CTLESC && (flag & EXP_QWORD))
4666 q++;
4667 if (*q == '~')
4668 p = exptilde(p, q, flag);
4669 }
4670start:
4671 startloc = expdest - (char *)stackblock();
4672 for (;;) {
4673 length += strcspn(p + length, reject);
4674 c = p[length];
4675 if (c && (!(c & 0x80)
4676#ifdef CONFIG_ASH_MATH_SUPPORT
4677 || c == CTLENDARI
4678#endif
4679 )) {
4680 /* c == '=' || c == ':' || c == CTLENDARI */
4681 length++;
4682 }
4683 if (length > 0) {
4684 int newloc;
4685 expdest = stnputs(p, length, expdest);
4686 newloc = expdest - (char *)stackblock();
4687 if (breakall && !inquotes && newloc > startloc) {
4688 recordregion(startloc, newloc, 0);
4689 }
4690 startloc = newloc;
4691 }
4692 p += length + 1;
4693 length = 0;
4694
4695 switch (c) {
4696 case '\0':
4697 goto breakloop;
4698 case '=':
4699 if (flag & EXP_VARTILDE2) {
4700 p--;
4701 continue;
4702 }
4703 flag |= EXP_VARTILDE2;
4704 reject++;
4705 /* fall through */
4706 case ':':
4707 /*
4708 * sort of a hack - expand tildes in variable
4709 * assignments (after the first '=' and after ':'s).
4710 */
4711 if (*--p == '~') {
4712 goto tilde;
4713 }
4714 continue;
4715 }
4716
4717 switch (c) {
4718 case CTLENDVAR: /* ??? */
4719 goto breakloop;
4720 case CTLQUOTEMARK:
4721 /* "$@" syntax adherence hack */
4722 if (
4723 !inquotes &&
4724 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4725 (p[4] == CTLQUOTEMARK || (
4726 p[4] == CTLENDVAR &&
4727 p[5] == CTLQUOTEMARK
4728 ))
4729 ) {
4730 p = evalvar(p + 1, flag) + 1;
4731 goto start;
4732 }
4733 inquotes = !inquotes;
4734addquote:
4735 if (quotes) {
4736 p--;
4737 length++;
4738 startloc++;
4739 }
4740 break;
4741 case CTLESC:
4742 startloc++;
4743 length++;
4744 goto addquote;
4745 case CTLVAR:
4746 p = evalvar(p, flag);
4747 goto start;
4748 case CTLBACKQ:
4749 c = 0;
4750 case CTLBACKQ|CTLQUOTE:
4751 expbackq(argbackq->n, c, quotes);
4752 argbackq = argbackq->next;
4753 goto start;
4754#ifdef CONFIG_ASH_MATH_SUPPORT
4755 case CTLENDARI:
4756 p--;
4757 expari(quotes);
4758 goto start;
4759#endif
4760 }
4761 }
4762breakloop:
4763 ;
4764}
4765
4766static char *
4767exptilde(char *startp, char *p, int flag)
4768{
4769 char c;
4770 char *name;
4771 struct passwd *pw;
4772 const char *home;
4773 int quotes = flag & (EXP_FULL | EXP_CASE);
4774 int startloc;
4775
4776 name = p + 1;
4777
4778 while ((c = *++p) != '\0') {
4779 switch(c) {
4780 case CTLESC:
4781 return (startp);
4782 case CTLQUOTEMARK:
4783 return (startp);
4784 case ':':
4785 if (flag & EXP_VARTILDE)
4786 goto done;
4787 break;
4788 case '/':
4789 case CTLENDVAR:
4790 goto done;
4791 }
4792 }
4793done:
4794 *p = '\0';
4795 if (*name == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004796 home = lookupvar(homestr);
Eric Andersenc470f442003-07-28 09:56:35 +00004797 } else {
4798 if ((pw = getpwnam(name)) == NULL)
4799 goto lose;
4800 home = pw->pw_dir;
4801 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004802 if (!home || !*home)
Eric Andersenc470f442003-07-28 09:56:35 +00004803 goto lose;
4804 *p = c;
4805 startloc = expdest - (char *)stackblock();
4806 strtodest(home, SQSYNTAX, quotes);
4807 recordregion(startloc, expdest - (char *)stackblock(), 0);
4808 return (p);
4809lose:
4810 *p = c;
4811 return (startp);
4812}
4813
4814
4815static void
4816removerecordregions(int endoff)
4817{
4818 if (ifslastp == NULL)
4819 return;
4820
4821 if (ifsfirst.endoff > endoff) {
4822 while (ifsfirst.next != NULL) {
4823 struct ifsregion *ifsp;
4824 INTOFF;
4825 ifsp = ifsfirst.next->next;
4826 ckfree(ifsfirst.next);
4827 ifsfirst.next = ifsp;
4828 INTON;
4829 }
4830 if (ifsfirst.begoff > endoff)
4831 ifslastp = NULL;
4832 else {
4833 ifslastp = &ifsfirst;
4834 ifsfirst.endoff = endoff;
4835 }
4836 return;
4837 }
4838
4839 ifslastp = &ifsfirst;
4840 while (ifslastp->next && ifslastp->next->begoff < endoff)
4841 ifslastp=ifslastp->next;
4842 while (ifslastp->next != NULL) {
4843 struct ifsregion *ifsp;
4844 INTOFF;
4845 ifsp = ifslastp->next->next;
4846 ckfree(ifslastp->next);
4847 ifslastp->next = ifsp;
4848 INTON;
4849 }
4850 if (ifslastp->endoff > endoff)
4851 ifslastp->endoff = endoff;
4852}
4853
4854
4855#ifdef CONFIG_ASH_MATH_SUPPORT
4856/*
4857 * Expand arithmetic expression. Backup to start of expression,
4858 * evaluate, place result in (backed up) result, adjust string position.
4859 */
4860void
4861expari(int quotes)
4862{
4863 char *p, *start;
4864 int begoff;
4865 int flag;
4866 int len;
4867
4868 /* ifsfree(); */
4869
4870 /*
4871 * This routine is slightly over-complicated for
4872 * efficiency. Next we scan backwards looking for the
4873 * start of arithmetic.
4874 */
4875 start = stackblock();
4876 p = expdest - 1;
4877 *p = '\0';
4878 p--;
4879 do {
4880 int esc;
4881
4882 while (*p != CTLARI) {
4883 p--;
4884#ifdef DEBUG
4885 if (p < start) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004886 sh_error("missing CTLARI (shouldn't happen)");
Eric Andersenc470f442003-07-28 09:56:35 +00004887 }
4888#endif
4889 }
4890
4891 esc = esclen(start, p);
4892 if (!(esc % 2)) {
4893 break;
4894 }
4895
4896 p -= esc + 1;
4897 } while (1);
4898
4899 begoff = p - start;
4900
4901 removerecordregions(begoff);
4902
4903 flag = p[1];
4904
4905 expdest = p;
4906
4907 if (quotes)
4908 rmescapes(p + 2);
4909
4910 len = cvtnum(dash_arith(p + 2));
4911
4912 if (flag != '"')
4913 recordregion(begoff, begoff + len, 0);
4914}
4915#endif
4916
4917/*
4918 * Expand stuff in backwards quotes.
4919 */
4920
4921static void
4922expbackq(union node *cmd, int quoted, int quotes)
4923{
4924 struct backcmd in;
4925 int i;
4926 char buf[128];
4927 char *p;
4928 char *dest;
4929 int startloc;
4930 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4931 struct stackmark smark;
4932
4933 INTOFF;
4934 setstackmark(&smark);
4935 dest = expdest;
4936 startloc = dest - (char *)stackblock();
4937 grabstackstr(dest);
4938 evalbackcmd(cmd, (struct backcmd *) &in);
4939 popstackmark(&smark);
4940
4941 p = in.buf;
4942 i = in.nleft;
4943 if (i == 0)
4944 goto read;
4945 for (;;) {
4946 memtodest(p, i, syntax, quotes);
4947read:
4948 if (in.fd < 0)
4949 break;
4950 i = safe_read(in.fd, buf, sizeof buf);
4951 TRACE(("expbackq: read returns %d\n", i));
4952 if (i <= 0)
4953 break;
4954 p = buf;
4955 }
4956
4957 if (in.buf)
4958 ckfree(in.buf);
4959 if (in.fd >= 0) {
4960 close(in.fd);
4961 back_exitstatus = waitforjob(in.jp);
4962 }
4963 INTON;
4964
4965 /* Eat all trailing newlines */
4966 dest = expdest;
4967 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4968 STUNPUTC(dest);
4969 expdest = dest;
4970
4971 if (quoted == 0)
4972 recordregion(startloc, dest - (char *)stackblock(), 0);
4973 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4974 (dest - (char *)stackblock()) - startloc,
4975 (dest - (char *)stackblock()) - startloc,
4976 stackblock() + startloc));
4977}
4978
4979
4980static char *
Eric Andersen90898442003-08-06 11:20:52 +00004981scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4982 int zero)
4983{
Eric Andersenc470f442003-07-28 09:56:35 +00004984 char *loc;
4985 char *loc2;
4986 char c;
4987
4988 loc = startp;
4989 loc2 = rmesc;
4990 do {
4991 int match;
4992 const char *s = loc2;
4993 c = *loc2;
4994 if (zero) {
4995 *loc2 = '\0';
4996 s = rmesc;
4997 }
4998 match = pmatch(str, s);
4999 *loc2 = c;
5000 if (match)
5001 return loc;
5002 if (quotes && *loc == CTLESC)
5003 loc++;
5004 loc++;
5005 loc2++;
5006 } while (c);
5007 return 0;
5008}
5009
5010
5011static char *
Eric Andersen90898442003-08-06 11:20:52 +00005012scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5013 int zero)
5014{
Eric Andersenc470f442003-07-28 09:56:35 +00005015 int esc = 0;
5016 char *loc;
5017 char *loc2;
5018
5019 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5020 int match;
5021 char c = *loc2;
5022 const char *s = loc2;
5023 if (zero) {
5024 *loc2 = '\0';
5025 s = rmesc;
5026 }
5027 match = pmatch(str, s);
5028 *loc2 = c;
5029 if (match)
5030 return loc;
5031 loc--;
5032 if (quotes) {
5033 if (--esc < 0) {
5034 esc = esclen(startp, loc);
5035 }
5036 if (esc % 2) {
5037 esc--;
5038 loc--;
5039 }
5040 }
5041 }
5042 return 0;
5043}
5044
5045static const char *
5046subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5047{
5048 char *startp;
5049 char *loc;
5050 int saveherefd = herefd;
5051 struct nodelist *saveargbackq = argbackq;
5052 int amount;
5053 char *rmesc, *rmescend;
5054 int zero;
5055 char *(*scan)(char *, char *, char *, char *, int , int);
5056
5057 herefd = -1;
5058 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5059 STPUTC('\0', expdest);
5060 herefd = saveherefd;
5061 argbackq = saveargbackq;
5062 startp = stackblock() + startloc;
5063
5064 switch (subtype) {
5065 case VSASSIGN:
5066 setvar(str, startp, 0);
5067 amount = startp - expdest;
5068 STADJUST(amount, expdest);
5069 return startp;
5070
5071 case VSQUESTION:
5072 varunset(p, str, startp, varflags);
5073 /* NOTREACHED */
5074 }
5075
5076 subtype -= VSTRIMRIGHT;
5077#ifdef DEBUG
5078 if (subtype < 0 || subtype > 3)
5079 abort();
5080#endif
5081
5082 rmesc = startp;
5083 rmescend = stackblock() + strloc;
5084 if (quotes) {
5085 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5086 if (rmesc != startp) {
5087 rmescend = expdest;
5088 startp = stackblock() + startloc;
5089 }
5090 }
5091 rmescend--;
5092 str = stackblock() + strloc;
5093 preglob(str, varflags & VSQUOTE, 0);
5094
5095 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5096 zero = subtype >> 1;
5097 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5098 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5099
5100 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5101 if (loc) {
5102 if (zero) {
5103 memmove(startp, loc, str - loc);
5104 loc = startp + (str - loc) - 1;
5105 }
5106 *loc = '\0';
5107 amount = loc - expdest;
5108 STADJUST(amount, expdest);
5109 }
5110 return loc;
5111}
5112
5113
Eric Andersen62483552001-07-10 06:09:16 +00005114/*
5115 * Expand a variable, and return a pointer to the next character in the
5116 * input string.
5117 */
Eric Andersenc470f442003-07-28 09:56:35 +00005118static char *
5119evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005120{
5121 int subtype;
5122 int varflags;
5123 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005124 int patloc;
5125 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005126 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005127 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005128 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005129 int quotes;
5130 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005131
Eric Andersenc470f442003-07-28 09:56:35 +00005132 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005133 varflags = *p++;
5134 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005135 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005136 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005137 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005138 startloc = expdest - (char *)stackblock();
5139 p = strchr(p, '=') + 1;
5140
Eric Andersenc470f442003-07-28 09:56:35 +00005141again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005142 varlen = varvalue(var, varflags, flag);
5143 if (varflags & VSNUL)
5144 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005145
Glenn L McGrath76620622004-01-13 10:19:37 +00005146 if (subtype == VSPLUS) {
5147 varlen = -1 - varlen;
5148 goto vsplus;
5149 }
Eric Andersen62483552001-07-10 06:09:16 +00005150
Eric Andersenc470f442003-07-28 09:56:35 +00005151 if (subtype == VSMINUS) {
5152vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005153 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005154 argstr(
5155 p, flag | EXP_TILDE |
5156 (quoted ? EXP_QWORD : EXP_WORD)
5157 );
5158 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005159 }
5160 if (easy)
5161 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005162 goto end;
5163 }
Eric Andersen62483552001-07-10 06:09:16 +00005164
Eric Andersenc470f442003-07-28 09:56:35 +00005165 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005166 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005167 if (subevalvar(p, var, 0, subtype, startloc,
5168 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005169 varflags &= ~VSNUL;
5170 /*
5171 * Remove any recorded regions beyond
5172 * start of variable
5173 */
5174 removerecordregions(startloc);
5175 goto again;
5176 }
Eric Andersenc470f442003-07-28 09:56:35 +00005177 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005178 }
5179 if (easy)
5180 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005181 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005182 }
5183
Glenn L McGrath76620622004-01-13 10:19:37 +00005184 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005185 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005186
Eric Andersenc470f442003-07-28 09:56:35 +00005187 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005188 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005189 goto record;
5190 }
5191
5192 if (subtype == VSNORMAL) {
5193 if (!easy)
5194 goto end;
5195record:
5196 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5197 goto end;
5198 }
5199
5200#ifdef DEBUG
5201 switch (subtype) {
5202 case VSTRIMLEFT:
5203 case VSTRIMLEFTMAX:
5204 case VSTRIMRIGHT:
5205 case VSTRIMRIGHTMAX:
5206 break;
5207 default:
5208 abort();
5209 }
5210#endif
5211
Glenn L McGrath76620622004-01-13 10:19:37 +00005212 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005213 /*
5214 * Terminate the string and start recording the pattern
5215 * right after it
5216 */
5217 STPUTC('\0', expdest);
5218 patloc = expdest - (char *)stackblock();
5219 if (subevalvar(p, NULL, patloc, subtype,
5220 startloc, varflags, quotes) == 0) {
5221 int amount = expdest - (
5222 (char *)stackblock() + patloc - 1
5223 );
5224 STADJUST(-amount, expdest);
5225 }
5226 /* Remove any recorded regions beyond start of variable */
5227 removerecordregions(startloc);
5228 goto record;
5229 }
5230
5231end:
5232 if (subtype != VSNORMAL) { /* skip to end of alternative */
5233 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005234 for (;;) {
5235 if ((c = *p++) == CTLESC)
5236 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005237 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005238 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005239 argbackq = argbackq->next;
5240 } else if (c == CTLVAR) {
5241 if ((*p++ & VSTYPE) != VSNORMAL)
5242 nesting++;
5243 } else if (c == CTLENDVAR) {
5244 if (--nesting == 0)
5245 break;
5246 }
5247 }
5248 }
5249 return p;
5250}
5251
Eric Andersencb57d552001-06-28 07:25:16 +00005252
Eric Andersencb57d552001-06-28 07:25:16 +00005253/*
5254 * Put a string on the stack.
5255 */
5256
Eric Andersenc470f442003-07-28 09:56:35 +00005257static void
5258memtodest(const char *p, size_t len, int syntax, int quotes) {
5259 char *q = expdest;
5260
5261 q = makestrspace(len * 2, q);
5262
5263 while (len--) {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005264 int c = SC2INT(*p++);
Eric Andersenc470f442003-07-28 09:56:35 +00005265 if (!c)
5266 continue;
5267 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5268 USTPUTC(CTLESC, q);
5269 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005270 }
Eric Andersenc470f442003-07-28 09:56:35 +00005271
5272 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005273}
5274
Eric Andersenc470f442003-07-28 09:56:35 +00005275
5276static void
5277strtodest(const char *p, int syntax, int quotes)
5278{
5279 memtodest(p, strlen(p), syntax, quotes);
5280}
5281
5282
Eric Andersencb57d552001-06-28 07:25:16 +00005283/*
5284 * Add the value of a specialized variable to the stack string.
5285 */
5286
Glenn L McGrath76620622004-01-13 10:19:37 +00005287static ssize_t
5288varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005289{
5290 int num;
5291 char *p;
5292 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005293 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005294 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005295 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005296 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005297 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005298 int quoted = varflags & VSQUOTE;
5299 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005300 int quotes = flags & (EXP_FULL | EXP_CASE);
5301
Glenn L McGrath76620622004-01-13 10:19:37 +00005302 if (quoted && (flags & EXP_FULL))
5303 sep = 1 << CHAR_BIT;
5304
Eric Andersencb57d552001-06-28 07:25:16 +00005305 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5306 switch (*name) {
5307 case '$':
5308 num = rootpid;
5309 goto numvar;
5310 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005311 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005312 goto numvar;
5313 case '#':
5314 num = shellparam.nparam;
5315 goto numvar;
5316 case '!':
5317 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005318 if (num == 0)
5319 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005320numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005321 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005322 break;
5323 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005324 p = makestrspace(NOPTS, expdest);
5325 for (i = NOPTS - 1; i >= 0; i--) {
5326 if (optlist[i]) {
5327 USTPUTC(optletters(i), p);
5328 len++;
5329 }
Eric Andersencb57d552001-06-28 07:25:16 +00005330 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005331 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005332 break;
5333 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005334 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005335 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005336 /* fall through */
5337 case '*':
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005338 sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005339 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5340 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005341param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005342 if (!(ap = shellparam.p))
5343 return -1;
5344 while ((p = *ap++)) {
5345 size_t partlen;
5346
5347 partlen = strlen(p);
Glenn L McGrath76620622004-01-13 10:19:37 +00005348 len += partlen;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00005349
5350 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5351 memtodest(p, partlen, syntax, quotes);
5352
5353 if (*ap && sep) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005354 char *q;
5355
5356 len++;
5357 if (subtype == VSPLUS || subtype == VSLENGTH) {
5358 continue;
5359 }
5360 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005361 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005362 STPUTC(CTLESC, q);
5363 STPUTC(sep, q);
5364 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005365 }
5366 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005367 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005368 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005369 case '1':
5370 case '2':
5371 case '3':
5372 case '4':
5373 case '5':
5374 case '6':
5375 case '7':
5376 case '8':
5377 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005378 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005379 if (num < 0 || num > shellparam.nparam)
5380 return -1;
5381 p = num ? shellparam.p[num - 1] : arg0;
5382 goto value;
5383 default:
5384 p = lookupvar(name);
5385value:
5386 if (!p)
5387 return -1;
5388
5389 len = strlen(p);
5390 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5391 memtodest(p, len, syntax, quotes);
5392 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005393 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005394
5395 if (subtype == VSPLUS || subtype == VSLENGTH)
5396 STADJUST(-len, expdest);
5397 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005398}
5399
5400
Eric Andersencb57d552001-06-28 07:25:16 +00005401/*
5402 * Record the fact that we have to scan this region of the
5403 * string for IFS characters.
5404 */
5405
Eric Andersenc470f442003-07-28 09:56:35 +00005406static void
5407recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005408{
5409 struct ifsregion *ifsp;
5410
5411 if (ifslastp == NULL) {
5412 ifsp = &ifsfirst;
5413 } else {
5414 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005415 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005416 ifsp->next = NULL;
5417 ifslastp->next = ifsp;
5418 INTON;
5419 }
5420 ifslastp = ifsp;
5421 ifslastp->begoff = start;
5422 ifslastp->endoff = end;
5423 ifslastp->nulonly = nulonly;
5424}
5425
5426
Eric Andersencb57d552001-06-28 07:25:16 +00005427/*
5428 * Break the argument string into pieces based upon IFS and add the
5429 * strings to the argument list. The regions of the string to be
5430 * searched for IFS characters have been stored by recordregion.
5431 */
Eric Andersenc470f442003-07-28 09:56:35 +00005432static void
5433ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005434{
Eric Andersencb57d552001-06-28 07:25:16 +00005435 struct ifsregion *ifsp;
5436 struct strlist *sp;
5437 char *start;
5438 char *p;
5439 char *q;
5440 const char *ifs, *realifs;
5441 int ifsspc;
5442 int nulonly;
5443
5444
5445 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005446 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005447 ifsspc = 0;
5448 nulonly = 0;
5449 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005450 ifsp = &ifsfirst;
5451 do {
5452 p = string + ifsp->begoff;
5453 nulonly = ifsp->nulonly;
5454 ifs = nulonly ? nullstr : realifs;
5455 ifsspc = 0;
5456 while (p < string + ifsp->endoff) {
5457 q = p;
5458 if (*p == CTLESC)
5459 p++;
5460 if (strchr(ifs, *p)) {
5461 if (!nulonly)
5462 ifsspc = (strchr(defifs, *p) != NULL);
5463 /* Ignore IFS whitespace at start */
5464 if (q == start && ifsspc) {
5465 p++;
5466 start = p;
5467 continue;
5468 }
5469 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005470 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005471 sp->text = start;
5472 *arglist->lastp = sp;
5473 arglist->lastp = &sp->next;
5474 p++;
5475 if (!nulonly) {
5476 for (;;) {
5477 if (p >= string + ifsp->endoff) {
5478 break;
5479 }
5480 q = p;
5481 if (*p == CTLESC)
5482 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005483 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005484 p = q;
5485 break;
5486 } else if (strchr(defifs, *p) == NULL) {
5487 if (ifsspc) {
5488 p++;
5489 ifsspc = 0;
5490 } else {
5491 p = q;
5492 break;
5493 }
5494 } else
5495 p++;
5496 }
5497 }
5498 start = p;
5499 } else
5500 p++;
5501 }
5502 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005503 if (nulonly)
5504 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005505 }
5506
Eric Andersenc470f442003-07-28 09:56:35 +00005507 if (!*start)
5508 return;
5509
5510add:
5511 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005512 sp->text = start;
5513 *arglist->lastp = sp;
5514 arglist->lastp = &sp->next;
5515}
5516
Eric Andersenc470f442003-07-28 09:56:35 +00005517static void
5518ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005519{
Eric Andersenc470f442003-07-28 09:56:35 +00005520 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005521
Eric Andersenc470f442003-07-28 09:56:35 +00005522 INTOFF;
5523 p = ifsfirst.next;
5524 do {
5525 struct ifsregion *ifsp;
5526 ifsp = p->next;
5527 ckfree(p);
5528 p = ifsp;
5529 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005530 ifslastp = NULL;
5531 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005532 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005533}
5534
Eric Andersen90898442003-08-06 11:20:52 +00005535static void expmeta(char *, char *);
5536static struct strlist *expsort(struct strlist *);
5537static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005538
Eric Andersen90898442003-08-06 11:20:52 +00005539static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005540
Eric Andersencb57d552001-06-28 07:25:16 +00005541
Eric Andersenc470f442003-07-28 09:56:35 +00005542static void
Eric Andersen90898442003-08-06 11:20:52 +00005543expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005544{
Eric Andersen90898442003-08-06 11:20:52 +00005545 static const char metachars[] = {
5546 '*', '?', '[', 0
5547 };
Eric Andersencb57d552001-06-28 07:25:16 +00005548 /* TODO - EXP_REDIR */
5549
5550 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005551 struct strlist **savelastp;
5552 struct strlist *sp;
5553 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005554
Eric Andersencb57d552001-06-28 07:25:16 +00005555 if (fflag)
5556 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005557 if (!strpbrk(str->text, metachars))
5558 goto nometa;
5559 savelastp = exparg.lastp;
5560
Eric Andersencb57d552001-06-28 07:25:16 +00005561 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005562 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005563 {
5564 int i = strlen(str->text);
5565 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5566 }
5567
5568 expmeta(expdir, p);
5569 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005570 if (p != str->text)
5571 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005572 INTON;
5573 if (exparg.lastp == savelastp) {
5574 /*
5575 * no matches
5576 */
Eric Andersenc470f442003-07-28 09:56:35 +00005577nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005578 *exparg.lastp = str;
5579 rmescapes(str->text);
5580 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005581 } else {
5582 *exparg.lastp = NULL;
5583 *savelastp = sp = expsort(*savelastp);
5584 while (sp->next != NULL)
5585 sp = sp->next;
5586 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005587 }
5588 str = str->next;
5589 }
5590}
5591
Eric Andersencb57d552001-06-28 07:25:16 +00005592/*
Eric Andersenc470f442003-07-28 09:56:35 +00005593 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005594 */
5595
Eric Andersenc470f442003-07-28 09:56:35 +00005596static void
Eric Andersen90898442003-08-06 11:20:52 +00005597addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005598{
Eric Andersencb57d552001-06-28 07:25:16 +00005599 struct strlist *sp;
5600
Eric Andersenc470f442003-07-28 09:56:35 +00005601 sp = (struct strlist *)stalloc(sizeof *sp);
5602 sp->text = sstrdup(name);
5603 *exparg.lastp = sp;
5604 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005605}
5606
5607
Eric Andersencb57d552001-06-28 07:25:16 +00005608/*
Eric Andersen90898442003-08-06 11:20:52 +00005609 * Do metacharacter (i.e. *, ?, [...]) expansion.
5610 */
5611
5612static void
5613expmeta(char *enddir, char *name)
5614{
5615 char *p;
5616 const char *cp;
5617 char *start;
5618 char *endname;
5619 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005620 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005621 DIR *dirp;
5622 struct dirent *dp;
5623 int atend;
5624 int matchdot;
5625
5626 metaflag = 0;
5627 start = name;
5628 for (p = name; *p; p++) {
5629 if (*p == '*' || *p == '?')
5630 metaflag = 1;
5631 else if (*p == '[') {
5632 char *q = p + 1;
5633 if (*q == '!')
5634 q++;
5635 for (;;) {
5636 if (*q == '\\')
5637 q++;
5638 if (*q == '/' || *q == '\0')
5639 break;
5640 if (*++q == ']') {
5641 metaflag = 1;
5642 break;
5643 }
5644 }
5645 } else if (*p == '\\')
5646 p++;
5647 else if (*p == '/') {
5648 if (metaflag)
5649 goto out;
5650 start = p + 1;
5651 }
5652 }
5653out:
5654 if (metaflag == 0) { /* we've reached the end of the file name */
5655 if (enddir != expdir)
5656 metaflag++;
5657 p = name;
5658 do {
5659 if (*p == '\\')
5660 p++;
5661 *enddir++ = *p;
5662 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005663 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005664 addfname(expdir);
5665 return;
5666 }
5667 endname = p;
5668 if (name < start) {
5669 p = name;
5670 do {
5671 if (*p == '\\')
5672 p++;
5673 *enddir++ = *p++;
5674 } while (p < start);
5675 }
5676 if (enddir == expdir) {
5677 cp = ".";
5678 } else if (enddir == expdir + 1 && *expdir == '/') {
5679 cp = "/";
5680 } else {
5681 cp = expdir;
5682 enddir[-1] = '\0';
5683 }
5684 if ((dirp = opendir(cp)) == NULL)
5685 return;
5686 if (enddir != expdir)
5687 enddir[-1] = '/';
5688 if (*endname == 0) {
5689 atend = 1;
5690 } else {
5691 atend = 0;
5692 *endname++ = '\0';
5693 }
5694 matchdot = 0;
5695 p = start;
5696 if (*p == '\\')
5697 p++;
5698 if (*p == '.')
5699 matchdot++;
5700 while (! intpending && (dp = readdir(dirp)) != NULL) {
5701 if (dp->d_name[0] == '.' && ! matchdot)
5702 continue;
5703 if (pmatch(start, dp->d_name)) {
5704 if (atend) {
5705 scopy(dp->d_name, enddir);
5706 addfname(expdir);
5707 } else {
5708 for (p = enddir, cp = dp->d_name;
5709 (*p++ = *cp++) != '\0';)
5710 continue;
5711 p[-1] = '/';
5712 expmeta(p, endname);
5713 }
5714 }
5715 }
5716 closedir(dirp);
5717 if (! atend)
5718 endname[-1] = '/';
5719}
5720
5721/*
5722 * Sort the results of file name expansion. It calculates the number of
5723 * strings to sort and then calls msort (short for merge sort) to do the
5724 * work.
5725 */
5726
5727static struct strlist *
5728expsort(struct strlist *str)
5729{
5730 int len;
5731 struct strlist *sp;
5732
5733 len = 0;
5734 for (sp = str ; sp ; sp = sp->next)
5735 len++;
5736 return msort(str, len);
5737}
5738
5739
5740static struct strlist *
5741msort(struct strlist *list, int len)
5742{
5743 struct strlist *p, *q = NULL;
5744 struct strlist **lpp;
5745 int half;
5746 int n;
5747
5748 if (len <= 1)
5749 return list;
5750 half = len >> 1;
5751 p = list;
5752 for (n = half ; --n >= 0 ; ) {
5753 q = p;
5754 p = p->next;
5755 }
5756 q->next = NULL; /* terminate first half of list */
5757 q = msort(list, half); /* sort first half of list */
5758 p = msort(p, len - half); /* sort second half */
5759 lpp = &list;
5760 for (;;) {
5761#ifdef CONFIG_LOCALE_SUPPORT
5762 if (strcoll(p->text, q->text) < 0)
5763#else
5764 if (strcmp(p->text, q->text) < 0)
5765#endif
5766 {
5767 *lpp = p;
5768 lpp = &p->next;
5769 if ((p = *lpp) == NULL) {
5770 *lpp = q;
5771 break;
5772 }
5773 } else {
5774 *lpp = q;
5775 lpp = &q->next;
5776 if ((q = *lpp) == NULL) {
5777 *lpp = p;
5778 break;
5779 }
5780 }
5781 }
5782 return list;
5783}
5784
5785
5786/*
Eric Andersencb57d552001-06-28 07:25:16 +00005787 * Returns true if the pattern matches the string.
5788 */
5789
Eric Andersenc470f442003-07-28 09:56:35 +00005790static inline int
5791patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005792{
Eric Andersenc470f442003-07-28 09:56:35 +00005793 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005794}
5795
5796
Eric Andersencb57d552001-06-28 07:25:16 +00005797/*
5798 * Remove any CTLESC characters from a string.
5799 */
5800
Eric Andersenc470f442003-07-28 09:56:35 +00005801static char *
5802_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005803{
5804 char *p, *q, *r;
5805 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005806 unsigned inquotes;
5807 int notescaped;
5808 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005809
5810 p = strpbrk(str, qchars);
5811 if (!p) {
5812 return str;
5813 }
5814 q = p;
5815 r = str;
5816 if (flag & RMESCAPE_ALLOC) {
5817 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005818 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005819
Eric Andersenc470f442003-07-28 09:56:35 +00005820 if (flag & RMESCAPE_GROW) {
5821 r = makestrspace(fulllen, expdest);
5822 } else if (flag & RMESCAPE_HEAP) {
5823 r = ckmalloc(fulllen);
5824 } else {
5825 r = stalloc(fulllen);
5826 }
5827 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005828 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005829 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005830 }
5831 }
Eric Andersenc470f442003-07-28 09:56:35 +00005832 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5833 globbing = flag & RMESCAPE_GLOB;
5834 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005835 while (*p) {
5836 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005837 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005838 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005839 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005840 continue;
5841 }
Eric Andersenc470f442003-07-28 09:56:35 +00005842 if (*p == '\\') {
5843 /* naked back slash */
5844 notescaped = 0;
5845 goto copy;
5846 }
Eric Andersencb57d552001-06-28 07:25:16 +00005847 if (*p == CTLESC) {
5848 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005849 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005850 *q++ = '\\';
5851 }
5852 }
Eric Andersenc470f442003-07-28 09:56:35 +00005853 notescaped = globbing;
5854copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005855 *q++ = *p++;
5856 }
5857 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005858 if (flag & RMESCAPE_GROW) {
5859 expdest = r;
5860 STADJUST(q - r + 1, expdest);
5861 }
Eric Andersencb57d552001-06-28 07:25:16 +00005862 return r;
5863}
Eric Andersencb57d552001-06-28 07:25:16 +00005864
5865
Eric Andersencb57d552001-06-28 07:25:16 +00005866/*
5867 * See if a pattern matches in a case statement.
5868 */
5869
Eric Andersenc470f442003-07-28 09:56:35 +00005870int
5871casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005872{
Eric Andersencb57d552001-06-28 07:25:16 +00005873 struct stackmark smark;
5874 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005875
5876 setstackmark(&smark);
5877 argbackq = pattern->narg.backquote;
5878 STARTSTACKSTR(expdest);
5879 ifslastp = NULL;
5880 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005881 STACKSTRNUL(expdest);
5882 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005883 popstackmark(&smark);
5884 return result;
5885}
5886
5887/*
5888 * Our own itoa().
5889 */
5890
Eric Andersenc470f442003-07-28 09:56:35 +00005891static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005892cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005893{
Eric Andersencb57d552001-06-28 07:25:16 +00005894 int len;
5895
Eric Andersenc470f442003-07-28 09:56:35 +00005896 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005897#ifdef CONFIG_ASH_MATH_SUPPORT_64
5898 len = fmtstr(expdest, 32, "%lld", (long long) num);
5899#else
Eric Andersenc470f442003-07-28 09:56:35 +00005900 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005901#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005902 STADJUST(len, expdest);
5903 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005904}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005905
Eric Andersenc470f442003-07-28 09:56:35 +00005906static void
5907varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005908{
Eric Andersenc470f442003-07-28 09:56:35 +00005909 const char *msg;
5910 const char *tail;
5911
5912 tail = nullstr;
5913 msg = "parameter not set";
5914 if (umsg) {
5915 if (*end == CTLENDVAR) {
5916 if (varflags & VSNUL)
5917 tail = " or null";
5918 } else
5919 msg = umsg;
5920 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005921 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005922}
Eric Andersen90898442003-08-06 11:20:52 +00005923
5924
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005925/* input.c */
Eric Andersencb57d552001-06-28 07:25:16 +00005926
Eric Andersencb57d552001-06-28 07:25:16 +00005927/*
Eric Andersen90898442003-08-06 11:20:52 +00005928 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005929 */
5930
Eric Andersenc470f442003-07-28 09:56:35 +00005931#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005932
Eric Andersenc470f442003-07-28 09:56:35 +00005933static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005934
Eric Andersencb57d552001-06-28 07:25:16 +00005935/*
Eric Andersenc470f442003-07-28 09:56:35 +00005936 * Read a character from the script, returning PEOF on end of file.
5937 * Nul characters in the input are silently discarded.
5938 */
5939
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005940
5941#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
Eric Andersenc470f442003-07-28 09:56:35 +00005942
5943#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5944#define pgetc_macro() pgetc()
5945static int
5946pgetc(void)
5947{
5948 return pgetc_as_macro();
5949}
5950#else
5951#define pgetc_macro() pgetc_as_macro()
5952static int
5953pgetc(void)
5954{
5955 return pgetc_macro();
5956}
5957#endif
5958
5959
5960/*
5961 * Same as pgetc(), but ignores PEOA.
5962 */
5963#ifdef CONFIG_ASH_ALIAS
5964static int pgetc2(void)
5965{
5966 int c;
5967
5968 do {
5969 c = pgetc_macro();
5970 } while (c == PEOA);
5971 return c;
5972}
5973#else
5974static inline int pgetc2(void)
5975{
5976 return pgetc_macro();
5977}
5978#endif
5979
Glenn L McGrath28939ad2004-07-21 10:20:19 +00005980/*
5981 * Read a line from the script.
5982 */
5983
5984static inline char *
5985pfgets(char *line, int len)
5986{
5987 char *p = line;
5988 int nleft = len;
5989 int c;
5990
5991 while (--nleft > 0) {
5992 c = pgetc2();
5993 if (c == PEOF) {
5994 if (p == line)
5995 return NULL;
5996 break;
5997 }
5998 *p++ = c;
5999 if (c == '\n')
6000 break;
6001 }
6002 *p = '\0';
6003 return line;
6004}
6005
6006
Eric Andersenc470f442003-07-28 09:56:35 +00006007
6008#ifdef CONFIG_FEATURE_COMMAND_EDITING
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006009#ifdef CONFIG_ASH_EXPAND_PRMT
6010static char *cmdedit_prompt;
6011#else
Eric Andersenc470f442003-07-28 09:56:35 +00006012static const char *cmdedit_prompt;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006013#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006014static inline void putprompt(const char *s)
6015{
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006016#ifdef CONFIG_ASH_EXPAND_PRMT
6017 free(cmdedit_prompt);
6018 cmdedit_prompt = bb_xstrdup(s);
6019#else
Eric Andersenc470f442003-07-28 09:56:35 +00006020 cmdedit_prompt = s;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006021#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006022}
6023#else
6024static inline void putprompt(const char *s)
6025{
6026 out2str(s);
6027}
6028#endif
6029
6030static inline int
6031preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006032{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006033 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006034 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006035 parsenextc = buf;
6036
Eric Andersenc470f442003-07-28 09:56:35 +00006037retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006038#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006039 if (!iflag || parsefile->fd)
6040 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6041 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006042#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006043 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006044#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006045 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6046 if(nr == 0) {
6047 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006048 if(trap[SIGINT]) {
6049 buf[0] = '\n';
6050 buf[1] = 0;
6051 raise(SIGINT);
6052 return 1;
6053 }
Eric Andersenc470f442003-07-28 09:56:35 +00006054 goto retry;
6055 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006056 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006057 /* Ctrl+D presend */
6058 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006059 }
Eric Andersencb57d552001-06-28 07:25:16 +00006060 }
6061#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006062 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006063#endif
6064
6065 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006066 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6067 int flags = fcntl(0, F_GETFL, 0);
6068 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006069 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006070 if (fcntl(0, F_SETFL, flags) >= 0) {
6071 out2str("sh: turning off NDELAY mode\n");
6072 goto retry;
6073 }
6074 }
6075 }
6076 }
6077 return nr;
6078}
6079
6080/*
6081 * Refill the input buffer and return the next input character:
6082 *
6083 * 1) If a string was pushed back on the input, pop it;
6084 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6085 * from a string so we can't refill the buffer, return EOF.
6086 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6087 * 4) Process input up to the next newline, deleting nul characters.
6088 */
6089
Eric Andersenc470f442003-07-28 09:56:35 +00006090int
6091preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006092{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006093 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00006094 int more;
6095 char savec;
6096
6097 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006098#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006099 if (parsenleft == -1 && parsefile->strpush->ap &&
6100 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006101 return PEOA;
6102 }
Eric Andersen2870d962001-07-02 17:27:21 +00006103#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006104 popstring();
6105 if (--parsenleft >= 0)
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006106 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006107 }
6108 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6109 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006110 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006111
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006112 more = parselleft;
6113 if (more <= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006114again:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006115 if ((more = preadfd()) <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006116 parselleft = parsenleft = EOF_NLEFT;
6117 return PEOF;
6118 }
6119 }
6120
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006121 q = parsenextc;
Eric Andersencb57d552001-06-28 07:25:16 +00006122
6123 /* delete nul characters */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006124 for (;;) {
6125 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00006126
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006127 more--;
6128 c = *q;
Eric Andersenc470f442003-07-28 09:56:35 +00006129
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006130 if (!c)
6131 memmove(q, q + 1, more);
6132 else {
6133 q++;
6134 if (c == '\n') {
6135 parsenleft = q - parsenextc - 1;
6136 break;
6137 }
Eric Andersencb57d552001-06-28 07:25:16 +00006138 }
6139
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006140 if (more <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006141 parsenleft = q - parsenextc - 1;
6142 if (parsenleft < 0)
6143 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006144 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006145 }
6146 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006147 parselleft = more;
Eric Andersencb57d552001-06-28 07:25:16 +00006148
6149 savec = *q;
6150 *q = '\0';
6151
6152 if (vflag) {
6153 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006154 }
6155
6156 *q = savec;
6157
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006158 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006159}
6160
Eric Andersenc470f442003-07-28 09:56:35 +00006161/*
6162 * Undo the last call to pgetc. Only one character may be pushed back.
6163 * PEOF may be pushed back.
6164 */
6165
6166void
6167pungetc(void)
6168{
6169 parsenleft++;
6170 parsenextc--;
6171}
Eric Andersencb57d552001-06-28 07:25:16 +00006172
6173/*
6174 * Push a string back onto the input at this current parsefile level.
6175 * We handle aliases this way.
6176 */
Eric Andersenc470f442003-07-28 09:56:35 +00006177void
6178pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006179{
Eric Andersencb57d552001-06-28 07:25:16 +00006180 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006181 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006182
Eric Andersenc470f442003-07-28 09:56:35 +00006183 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006184 INTOFF;
6185/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6186 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006187 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006188 sp->prev = parsefile->strpush;
6189 parsefile->strpush = sp;
6190 } else
6191 sp = parsefile->strpush = &(parsefile->basestrpush);
6192 sp->prevstring = parsenextc;
6193 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006194#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006195 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006196 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006197 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006198 sp->string = s;
6199 }
Eric Andersen2870d962001-07-02 17:27:21 +00006200#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006201 parsenextc = s;
6202 parsenleft = len;
6203 INTON;
6204}
6205
Eric Andersenc470f442003-07-28 09:56:35 +00006206void
6207popstring(void)
6208{
6209 struct strpush *sp = parsefile->strpush;
6210
6211 INTOFF;
6212#ifdef CONFIG_ASH_ALIAS
6213 if (sp->ap) {
6214 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6215 checkkwd |= CHKALIAS;
6216 }
6217 if (sp->string != sp->ap->val) {
6218 ckfree(sp->string);
6219 }
6220 sp->ap->flag &= ~ALIASINUSE;
6221 if (sp->ap->flag & ALIASDEAD) {
6222 unalias(sp->ap->name);
6223 }
6224 }
6225#endif
6226 parsenextc = sp->prevstring;
6227 parsenleft = sp->prevnleft;
6228/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6229 parsefile->strpush = sp->prev;
6230 if (sp != &(parsefile->basestrpush))
6231 ckfree(sp);
6232 INTON;
6233}
6234
6235/*
6236 * Set the input to take input from a file. If push is set, push the
6237 * old input onto the stack first.
6238 */
6239
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006240static int
6241setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00006242{
6243 int fd;
6244 int fd2;
6245
6246 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006247 if ((fd = open(fname, O_RDONLY)) < 0) {
6248 if (flags & INPUT_NOFILE_OK)
6249 goto out;
6250 sh_error("Can't open %s", fname);
6251 }
Eric Andersenc470f442003-07-28 09:56:35 +00006252 if (fd < 10) {
6253 fd2 = copyfd(fd, 10);
6254 close(fd);
6255 if (fd2 < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006256 sh_error("Out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +00006257 fd = fd2;
6258 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006259 setinputfd(fd, flags & INPUT_PUSH_FILE);
6260out:
Eric Andersenc470f442003-07-28 09:56:35 +00006261 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006262 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +00006263}
6264
6265
6266/*
6267 * Like setinputfile, but takes an open file descriptor. Call this with
6268 * interrupts off.
6269 */
6270
6271static void
6272setinputfd(int fd, int push)
6273{
6274 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6275 if (push) {
6276 pushfile();
6277 parsefile->buf = 0;
6278 }
6279 parsefile->fd = fd;
6280 if (parsefile->buf == NULL)
6281 parsefile->buf = ckmalloc(IBUFSIZ);
6282 parselleft = parsenleft = 0;
6283 plinno = 1;
6284}
6285
Eric Andersencb57d552001-06-28 07:25:16 +00006286
Eric Andersencb57d552001-06-28 07:25:16 +00006287/*
6288 * Like setinputfile, but takes input from a string.
6289 */
6290
Eric Andersenc470f442003-07-28 09:56:35 +00006291static void
6292setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006293{
Eric Andersencb57d552001-06-28 07:25:16 +00006294 INTOFF;
6295 pushfile();
6296 parsenextc = string;
6297 parsenleft = strlen(string);
6298 parsefile->buf = NULL;
6299 plinno = 1;
6300 INTON;
6301}
6302
6303
Eric Andersencb57d552001-06-28 07:25:16 +00006304/*
6305 * To handle the "." command, a stack of input files is used. Pushfile
6306 * adds a new entry to the stack and popfile restores the previous level.
6307 */
6308
Eric Andersenc470f442003-07-28 09:56:35 +00006309static void
6310pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006311{
Eric Andersencb57d552001-06-28 07:25:16 +00006312 struct parsefile *pf;
6313
6314 parsefile->nleft = parsenleft;
6315 parsefile->lleft = parselleft;
6316 parsefile->nextc = parsenextc;
6317 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006318 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006319 pf->prev = parsefile;
6320 pf->fd = -1;
6321 pf->strpush = NULL;
6322 pf->basestrpush.prev = NULL;
6323 parsefile = pf;
6324}
6325
Eric Andersenc470f442003-07-28 09:56:35 +00006326
6327static void
6328popfile(void)
6329{
6330 struct parsefile *pf = parsefile;
6331
6332 INTOFF;
6333 if (pf->fd >= 0)
6334 close(pf->fd);
6335 if (pf->buf)
6336 ckfree(pf->buf);
6337 while (pf->strpush)
6338 popstring();
6339 parsefile = pf->prev;
6340 ckfree(pf);
6341 parsenleft = parsefile->nleft;
6342 parselleft = parsefile->lleft;
6343 parsenextc = parsefile->nextc;
6344 plinno = parsefile->linno;
6345 INTON;
6346}
Eric Andersencb57d552001-06-28 07:25:16 +00006347
6348
Eric Andersen2870d962001-07-02 17:27:21 +00006349/*
Eric Andersenc470f442003-07-28 09:56:35 +00006350 * Return to top level.
6351 */
Eric Andersen2870d962001-07-02 17:27:21 +00006352
Eric Andersenc470f442003-07-28 09:56:35 +00006353static void
6354popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006355{
Eric Andersenc470f442003-07-28 09:56:35 +00006356 while (parsefile != &basepf)
6357 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006358}
6359
Eric Andersen2870d962001-07-02 17:27:21 +00006360
Eric Andersenc470f442003-07-28 09:56:35 +00006361/*
6362 * Close the file(s) that the shell is reading commands from. Called
6363 * after a fork is done.
6364 */
6365
6366static void
6367closescript(void)
6368{
6369 popallfiles();
6370 if (parsefile->fd > 0) {
6371 close(parsefile->fd);
6372 parsefile->fd = 0;
6373 }
6374}
Eric Andersenc470f442003-07-28 09:56:35 +00006375
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006376/* jobs.c */
Eric Andersenc470f442003-07-28 09:56:35 +00006377
6378/* mode flags for set_curjob */
6379#define CUR_DELETE 2
6380#define CUR_RUNNING 1
6381#define CUR_STOPPED 0
6382
6383/* mode flags for dowait */
6384#define DOWAIT_NORMAL 0
6385#define DOWAIT_BLOCK 1
6386
6387/* array of jobs */
6388static struct job *jobtab;
6389/* size of array */
6390static unsigned njobs;
6391#if JOBS
6392/* pgrp of shell on invocation */
6393static int initialpgrp;
6394static int ttyfd = -1;
6395#endif
6396/* current job */
6397static struct job *curjob;
6398/* number of presumed living untracked jobs */
6399static int jobless;
6400
6401static void set_curjob(struct job *, unsigned);
6402#if JOBS
6403static int restartjob(struct job *, int);
6404static void xtcsetpgrp(int, pid_t);
6405static char *commandtext(union node *);
6406static void cmdlist(union node *, int);
6407static void cmdtxt(union node *);
6408static void cmdputs(const char *);
6409static void showpipe(struct job *, FILE *);
6410#endif
6411static int sprint_status(char *, int, int);
6412static void freejob(struct job *);
6413static struct job *getjob(const char *, int);
6414static struct job *growjobtab(void);
6415static void forkchild(struct job *, union node *, int);
6416static void forkparent(struct job *, union node *, int, pid_t);
6417static int dowait(int, struct job *);
6418static int getstatus(struct job *);
6419
6420static void
6421set_curjob(struct job *jp, unsigned mode)
6422{
6423 struct job *jp1;
6424 struct job **jpp, **curp;
6425
6426 /* first remove from list */
6427 jpp = curp = &curjob;
6428 do {
6429 jp1 = *jpp;
6430 if (jp1 == jp)
6431 break;
6432 jpp = &jp1->prev_job;
6433 } while (1);
6434 *jpp = jp1->prev_job;
6435
6436 /* Then re-insert in correct position */
6437 jpp = curp;
6438 switch (mode) {
6439 default:
6440#ifdef DEBUG
6441 abort();
6442#endif
6443 case CUR_DELETE:
6444 /* job being deleted */
6445 break;
6446 case CUR_RUNNING:
6447 /* newly created job or backgrounded job,
6448 put after all stopped jobs. */
6449 do {
6450 jp1 = *jpp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006451#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006452 if (!jp1 || jp1->state != JOBSTOPPED)
6453#endif
6454 break;
6455 jpp = &jp1->prev_job;
6456 } while (1);
6457 /* FALLTHROUGH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006458#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006459 case CUR_STOPPED:
6460#endif
6461 /* newly stopped job - becomes curjob */
6462 jp->prev_job = *jpp;
6463 *jpp = jp;
6464 break;
6465 }
6466}
6467
6468#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006469/*
6470 * Turn job control on and off.
6471 *
6472 * Note: This code assumes that the third arg to ioctl is a character
6473 * pointer, which is true on Berkeley systems but not System V. Since
6474 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006475 *
6476 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006477 */
6478
Eric Andersenc470f442003-07-28 09:56:35 +00006479void
6480setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006481{
Eric Andersenc470f442003-07-28 09:56:35 +00006482 int fd;
6483 int pgrp;
6484
6485 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006486 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006487 if (on) {
6488 int ofd;
6489 ofd = fd = open(_PATH_TTY, O_RDWR);
6490 if (fd < 0) {
6491 fd += 3;
6492 while (!isatty(fd) && --fd >= 0)
6493 ;
6494 }
6495 fd = fcntl(fd, F_DUPFD, 10);
6496 close(ofd);
6497 if (fd < 0)
6498 goto out;
6499 fcntl(fd, F_SETFD, FD_CLOEXEC);
6500 do { /* while we are in the background */
6501 if ((pgrp = tcgetpgrp(fd)) < 0) {
6502out:
6503 sh_warnx("can't access tty; job control turned off");
6504 mflag = on = 0;
6505 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006506 }
Eric Andersenc470f442003-07-28 09:56:35 +00006507 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006508 break;
6509 killpg(0, SIGTTIN);
6510 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006511 initialpgrp = pgrp;
6512
Eric Andersencb57d552001-06-28 07:25:16 +00006513 setsignal(SIGTSTP);
6514 setsignal(SIGTTOU);
6515 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006516 pgrp = rootpid;
6517 setpgid(0, pgrp);
6518 xtcsetpgrp(fd, pgrp);
6519 } else {
6520 /* turning job control off */
6521 fd = ttyfd;
6522 pgrp = initialpgrp;
6523 xtcsetpgrp(fd, pgrp);
6524 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006525 setsignal(SIGTSTP);
6526 setsignal(SIGTTOU);
6527 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006528close:
6529 close(fd);
6530 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006531 }
Eric Andersenc470f442003-07-28 09:56:35 +00006532 ttyfd = fd;
6533 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006534}
Eric Andersencb57d552001-06-28 07:25:16 +00006535
Eric Andersenc470f442003-07-28 09:56:35 +00006536static int
Eric Andersen90898442003-08-06 11:20:52 +00006537killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006538{
6539 int signo = -1;
6540 int list = 0;
6541 int i;
6542 pid_t pid;
6543 struct job *jp;
6544
6545 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006546usage:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006547 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006548"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6549"kill -l [exitstatus]"
6550 );
Eric Andersencb57d552001-06-28 07:25:16 +00006551 }
6552
Eric Andersenc470f442003-07-28 09:56:35 +00006553 if (**++argv == '-') {
6554 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006555 if (signo < 0) {
6556 int c;
6557
6558 while ((c = nextopt("ls:")) != '\0')
6559 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006560 default:
6561#ifdef DEBUG
6562 abort();
6563#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006564 case 'l':
6565 list = 1;
6566 break;
6567 case 's':
6568 signo = decode_signal(optionarg, 1);
6569 if (signo < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006570 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006571 "invalid signal number or name: %s",
6572 optionarg
6573 );
Eric Andersencb57d552001-06-28 07:25:16 +00006574 }
Eric Andersen2870d962001-07-02 17:27:21 +00006575 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006576 }
Eric Andersenc470f442003-07-28 09:56:35 +00006577 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006578 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006579 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006580 }
6581
6582 if (!list && signo < 0)
6583 signo = SIGTERM;
6584
Eric Andersenc470f442003-07-28 09:56:35 +00006585 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006586 goto usage;
6587 }
6588
6589 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006590 const char *name;
6591
Eric Andersenc470f442003-07-28 09:56:35 +00006592 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006593 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006594 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006595 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006596 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006597 }
6598 return 0;
6599 }
Eric Andersen34506362001-08-02 05:02:46 +00006600 name = u_signal_names(*argptr, &signo, -1);
6601 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006602 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006603 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006604 sh_error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006605 return 0;
6606 }
6607
Eric Andersenc470f442003-07-28 09:56:35 +00006608 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006609 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006610 if (**argv == '%') {
6611 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006612 pid = -jp->ps[0].pid;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006613 } else {
6614 pid = **argv == '-' ?
6615 -number(*argv + 1) : number(*argv);
6616 }
Eric Andersenc470f442003-07-28 09:56:35 +00006617 if (kill(pid, signo) != 0) {
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006618 sh_warnx("(%d) - %m", pid);
Eric Andersenc470f442003-07-28 09:56:35 +00006619 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006620 }
Eric Andersenc470f442003-07-28 09:56:35 +00006621 } while (*++argv);
6622
6623 return i;
6624}
6625#endif /* JOBS */
6626
6627#if defined(JOBS) || defined(DEBUG)
6628static int
6629jobno(const struct job *jp)
6630{
6631 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006632}
6633#endif
6634
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006635#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006636static int
6637fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006638{
Eric Andersenc470f442003-07-28 09:56:35 +00006639 struct job *jp;
6640 FILE *out;
6641 int mode;
6642 int retval;
6643
6644 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6645 nextopt(nullstr);
6646 argv = argptr;
6647 out = stdout;
6648 do {
6649 jp = getjob(*argv, 1);
6650 if (mode == FORK_BG) {
6651 set_curjob(jp, CUR_RUNNING);
6652 fprintf(out, "[%d] ", jobno(jp));
6653 }
6654 outstr(jp->ps->cmd, out);
6655 showpipe(jp, out);
6656 retval = restartjob(jp, mode);
6657 } while (*argv && *++argv);
6658 return retval;
6659}
6660
6661static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6662
6663
6664static int
6665restartjob(struct job *jp, int mode)
6666{
6667 struct procstat *ps;
6668 int i;
6669 int status;
6670 pid_t pgid;
6671
6672 INTOFF;
6673 if (jp->state == JOBDONE)
6674 goto out;
6675 jp->state = JOBRUNNING;
6676 pgid = jp->ps->pid;
6677 if (mode == FORK_FG)
6678 xtcsetpgrp(ttyfd, pgid);
6679 killpg(pgid, SIGCONT);
6680 ps = jp->ps;
6681 i = jp->nprocs;
6682 do {
6683 if (WIFSTOPPED(ps->status)) {
6684 ps->status = -1;
6685 }
6686 } while (ps++, --i);
6687out:
6688 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6689 INTON;
6690 return status;
6691}
6692#endif
6693
6694static int
6695sprint_status(char *s, int status, int sigonly)
6696{
6697 int col;
6698 int st;
6699
6700 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006701 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006702#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006703 if (WIFSTOPPED(status))
6704 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006705 else
Eric Andersenc470f442003-07-28 09:56:35 +00006706#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006707 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006708 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006709 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006710 goto out;
6711#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006712 if (WIFSTOPPED(status))
6713 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006714#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006715 }
6716 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006717 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006718 if (WCOREDUMP(status)) {
6719 col += fmtstr(s + col, 16, " (core dumped)");
6720 }
6721 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006722 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006723 if (st)
6724 col = fmtstr(s, 16, "Done(%d)", st);
6725 else
6726 col = fmtstr(s, 16, "Done");
6727 }
6728
6729out:
6730 return col;
6731}
6732
6733#if JOBS
6734static void
6735showjob(FILE *out, struct job *jp, int mode)
6736{
6737 struct procstat *ps;
6738 struct procstat *psend;
6739 int col;
6740 int indent;
6741 char s[80];
6742
6743 ps = jp->ps;
6744
6745 if (mode & SHOW_PGID) {
6746 /* just output process (group) id of pipeline */
6747 fprintf(out, "%d\n", ps->pid);
6748 return;
6749 }
6750
6751 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6752 indent = col;
6753
6754 if (jp == curjob)
6755 s[col - 2] = '+';
6756 else if (curjob && jp == curjob->prev_job)
6757 s[col - 2] = '-';
6758
6759 if (mode & SHOW_PID)
6760 col += fmtstr(s + col, 16, "%d ", ps->pid);
6761
6762 psend = ps + jp->nprocs;
6763
6764 if (jp->state == JOBRUNNING) {
6765 scopy("Running", s + col);
6766 col += strlen("Running");
6767 } else {
6768 int status = psend[-1].status;
6769#if JOBS
6770 if (jp->state == JOBSTOPPED)
6771 status = jp->stopstatus;
6772#endif
6773 col += sprint_status(s + col, status, 0);
6774 }
6775
6776 goto start;
6777
6778 do {
6779 /* for each process */
6780 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6781
6782start:
Eric Andersen90898442003-08-06 11:20:52 +00006783 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006784 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6785 );
6786 if (!(mode & SHOW_PID)) {
6787 showpipe(jp, out);
6788 break;
6789 }
6790 if (++ps == psend) {
6791 outcslow('\n', out);
6792 break;
6793 }
6794 } while (1);
6795
6796 jp->changed = 0;
6797
6798 if (jp->state == JOBDONE) {
6799 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6800 freejob(jp);
6801 }
6802}
6803
6804
6805static int
6806jobscmd(int argc, char **argv)
6807{
6808 int mode, m;
6809 FILE *out;
6810
6811 mode = 0;
6812 while ((m = nextopt("lp")))
6813 if (m == 'l')
6814 mode = SHOW_PID;
6815 else
6816 mode = SHOW_PGID;
6817
6818 out = stdout;
6819 argv = argptr;
6820 if (*argv)
6821 do
6822 showjob(out, getjob(*argv,0), mode);
6823 while (*++argv);
6824 else
6825 showjobs(out, mode);
6826
Eric Andersencb57d552001-06-28 07:25:16 +00006827 return 0;
6828}
6829
6830
6831/*
6832 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6833 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006834 */
6835
Eric Andersenc470f442003-07-28 09:56:35 +00006836static void
6837showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006838{
Eric Andersencb57d552001-06-28 07:25:16 +00006839 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006840
Eric Andersenc470f442003-07-28 09:56:35 +00006841 TRACE(("showjobs(%x) called\n", mode));
6842
6843 /* If not even one one job changed, there is nothing to do */
6844 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6845 continue;
6846
6847 for (jp = curjob; jp; jp = jp->prev_job) {
6848 if (!(mode & SHOW_CHANGED) || jp->changed)
6849 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006850 }
6851}
Eric Andersenc470f442003-07-28 09:56:35 +00006852#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006853
6854/*
6855 * Mark a job structure as unused.
6856 */
6857
Eric Andersenc470f442003-07-28 09:56:35 +00006858static void
6859freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006860{
Eric Andersenc470f442003-07-28 09:56:35 +00006861 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006862 int i;
6863
6864 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006865 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006866 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006867 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006868 }
6869 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006870 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006871 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006872 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006873 INTON;
6874}
6875
6876
Eric Andersenc470f442003-07-28 09:56:35 +00006877static int
6878waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006879{
6880 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006881 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006882 struct job *jp;
6883
Eric Andersenc470f442003-07-28 09:56:35 +00006884 EXSIGON();
6885
6886 nextopt(nullstr);
6887 retval = 0;
6888
6889 argv = argptr;
6890 if (!*argv) {
6891 /* wait for all jobs */
6892 for (;;) {
6893 jp = curjob;
6894 while (1) {
6895 if (!jp) {
6896 /* no running procs */
6897 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006898 }
Eric Andersenc470f442003-07-28 09:56:35 +00006899 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006900 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006901 jp->waited = 1;
6902 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006903 }
Eric Andersenc470f442003-07-28 09:56:35 +00006904 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006905 }
6906 }
Eric Andersenc470f442003-07-28 09:56:35 +00006907
6908 retval = 127;
6909 do {
6910 if (**argv != '%') {
6911 pid_t pid = number(*argv);
6912 job = curjob;
6913 goto start;
6914 do {
6915 if (job->ps[job->nprocs - 1].pid == pid)
6916 break;
6917 job = job->prev_job;
6918start:
6919 if (!job)
6920 goto repeat;
6921 } while (1);
6922 } else
6923 job = getjob(*argv, 0);
6924 /* loop until process terminated or stopped */
6925 while (job->state == JOBRUNNING)
6926 dowait(DOWAIT_BLOCK, 0);
6927 job->waited = 1;
6928 retval = getstatus(job);
6929repeat:
6930 ;
6931 } while (*++argv);
6932
6933out:
6934 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006935}
6936
6937
Eric Andersencb57d552001-06-28 07:25:16 +00006938/*
6939 * Convert a job name to a job structure.
6940 */
6941
Eric Andersenc470f442003-07-28 09:56:35 +00006942static struct job *
6943getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006944{
Eric Andersencb57d552001-06-28 07:25:16 +00006945 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006946 struct job *found;
6947 const char *err_msg = "No such job: %s";
6948 unsigned num;
6949 int c;
6950 const char *p;
6951 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006952
Eric Andersenc470f442003-07-28 09:56:35 +00006953 jp = curjob;
6954 p = name;
6955 if (!p)
6956 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006957
Eric Andersenc470f442003-07-28 09:56:35 +00006958 if (*p != '%')
6959 goto err;
6960
6961 c = *++p;
6962 if (!c)
6963 goto currentjob;
6964
6965 if (!p[1]) {
6966 if (c == '+' || c == '%') {
6967currentjob:
6968 err_msg = "No current job";
6969 goto check;
6970 } else if (c == '-') {
6971 if (jp)
6972 jp = jp->prev_job;
6973 err_msg = "No previous job";
6974check:
6975 if (!jp)
6976 goto err;
6977 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006978 }
6979 }
Eric Andersenc470f442003-07-28 09:56:35 +00006980
6981 if (is_number(p)) {
6982 num = atoi(p);
6983 if (num < njobs) {
6984 jp = jobtab + num - 1;
6985 if (jp->used)
6986 goto gotit;
6987 goto err;
6988 }
6989 }
6990
6991 match = prefix;
6992 if (*p == '?') {
6993 match = strstr;
6994 p++;
6995 }
6996
6997 found = 0;
6998 while (1) {
6999 if (!jp)
7000 goto err;
7001 if (match(jp->ps[0].cmd, p)) {
7002 if (found)
7003 goto err;
7004 found = jp;
7005 err_msg = "%s: ambiguous";
7006 }
7007 jp = jp->prev_job;
7008 }
7009
7010gotit:
7011#if JOBS
7012 err_msg = "job %s not created under job control";
7013 if (getctl && jp->jobctl == 0)
7014 goto err;
7015#endif
7016 return jp;
7017err:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007018 sh_error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007019}
7020
7021
Eric Andersencb57d552001-06-28 07:25:16 +00007022/*
Eric Andersenc470f442003-07-28 09:56:35 +00007023 * Return a new job structure.
7024 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007025 */
7026
Eric Andersenc470f442003-07-28 09:56:35 +00007027static struct job *
7028makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007029{
7030 int i;
7031 struct job *jp;
7032
Eric Andersenc470f442003-07-28 09:56:35 +00007033 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007034 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007035 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007036 break;
7037 }
7038 if (jp->used == 0)
7039 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007040 if (jp->state != JOBDONE || !jp->waited)
7041 continue;
7042#if JOBS
7043 if (jobctl)
7044 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007045#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007046 freejob(jp);
7047 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007048 }
Eric Andersenc470f442003-07-28 09:56:35 +00007049 memset(jp, 0, sizeof(*jp));
7050#if JOBS
7051 if (jobctl)
7052 jp->jobctl = 1;
7053#endif
7054 jp->prev_job = curjob;
7055 curjob = jp;
7056 jp->used = 1;
7057 jp->ps = &jp->ps0;
7058 if (nprocs > 1) {
7059 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7060 }
7061 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7062 jobno(jp)));
7063 return jp;
7064}
7065
7066static struct job *
7067growjobtab(void)
7068{
7069 size_t len;
7070 ptrdiff_t offset;
7071 struct job *jp, *jq;
7072
7073 len = njobs * sizeof(*jp);
7074 jq = jobtab;
7075 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7076
7077 offset = (char *)jp - (char *)jq;
7078 if (offset) {
7079 /* Relocate pointers */
7080 size_t l = len;
7081
7082 jq = (struct job *)((char *)jq + l);
7083 while (l) {
7084 l -= sizeof(*jp);
7085 jq--;
7086#define joff(p) ((struct job *)((char *)(p) + l))
7087#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007088 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007089 jmove(joff(jp)->ps);
7090 if (joff(jp)->prev_job)
7091 jmove(joff(jp)->prev_job);
7092 }
7093 if (curjob)
7094 jmove(curjob);
7095#undef joff
7096#undef jmove
7097 }
7098
7099 njobs += 4;
7100 jobtab = jp;
7101 jp = (struct job *)((char *)jp + len);
7102 jq = jp + 3;
7103 do {
7104 jq->used = 0;
7105 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007106 return jp;
7107}
7108
7109
7110/*
Eric Andersenc470f442003-07-28 09:56:35 +00007111 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007112 * own process group. Jp is a job structure that the job is to be added to.
7113 * N is the command that will be evaluated by the child. Both jp and n may
7114 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007115 * FORK_FG - Fork off a foreground process.
7116 * FORK_BG - Fork off a background process.
7117 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7118 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007119 *
7120 * When job control is turned off, background processes have their standard
7121 * input redirected to /dev/null (except for the second and later processes
7122 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007123 *
7124 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007125 */
7126
Eric Andersenc470f442003-07-28 09:56:35 +00007127static inline void
7128forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007129{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007130 int oldlvl;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007131
Eric Andersenc470f442003-07-28 09:56:35 +00007132 TRACE(("Child shell %d\n", getpid()));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007133 oldlvl = shlvl;
7134 shlvl++;
Eric Andersenc470f442003-07-28 09:56:35 +00007135
7136 closescript();
7137 clear_traps();
7138#if JOBS
7139 /* do job control only in root shell */
7140 jobctl = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007141 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007142 pid_t pgrp;
7143
7144 if (jp->nprocs == 0)
7145 pgrp = getpid();
7146 else
7147 pgrp = jp->ps[0].pid;
7148 /* This can fail because we are doing it in the parent also */
7149 (void)setpgid(0, pgrp);
7150 if (mode == FORK_FG)
7151 xtcsetpgrp(ttyfd, pgrp);
7152 setsignal(SIGTSTP);
7153 setsignal(SIGTTOU);
7154 } else
Eric Andersen62483552001-07-10 06:09:16 +00007155#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007156 if (mode == FORK_BG) {
7157 ignoresig(SIGINT);
7158 ignoresig(SIGQUIT);
7159 if (jp->nprocs == 0) {
7160 close(0);
Bernhard Reutner-Fischer0a8812b2006-05-19 13:12:21 +00007161 if (open(bb_dev_null, O_RDONLY) != 0)
7162 sh_error("Can't open %s", bb_dev_null);
Eric Andersencb57d552001-06-28 07:25:16 +00007163 }
Eric Andersencb57d552001-06-28 07:25:16 +00007164 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007165 if (!oldlvl && iflag) {
Eric Andersenc470f442003-07-28 09:56:35 +00007166 setsignal(SIGINT);
7167 setsignal(SIGQUIT);
7168 setsignal(SIGTERM);
7169 }
7170 for (jp = curjob; jp; jp = jp->prev_job)
7171 freejob(jp);
7172 jobless = 0;
7173}
7174
7175static inline void
7176forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7177{
7178 TRACE(("In parent shell: child = %d\n", pid));
7179 if (!jp) {
7180 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7181 jobless++;
7182 return;
7183 }
7184#if JOBS
7185 if (mode != FORK_NOJOB && jp->jobctl) {
7186 int pgrp;
7187
7188 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007189 pgrp = pid;
7190 else
7191 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007192 /* This can fail because we are doing it in the child also */
7193 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007194 }
Eric Andersen62483552001-07-10 06:09:16 +00007195#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007196 if (mode == FORK_BG) {
7197 backgndpid = pid; /* set $! */
7198 set_curjob(jp, CUR_RUNNING);
7199 }
Eric Andersencb57d552001-06-28 07:25:16 +00007200 if (jp) {
7201 struct procstat *ps = &jp->ps[jp->nprocs++];
7202 ps->pid = pid;
7203 ps->status = -1;
7204 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007205#if JOBS
7206 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007207 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007208#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007209 }
Eric Andersencb57d552001-06-28 07:25:16 +00007210}
7211
Eric Andersenc470f442003-07-28 09:56:35 +00007212static int
7213forkshell(struct job *jp, union node *n, int mode)
7214{
7215 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007216
Eric Andersenc470f442003-07-28 09:56:35 +00007217 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7218 pid = fork();
7219 if (pid < 0) {
7220 TRACE(("Fork failed, errno=%d", errno));
7221 if (jp)
7222 freejob(jp);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007223 sh_error("Cannot fork");
Eric Andersenc470f442003-07-28 09:56:35 +00007224 }
7225 if (pid == 0)
7226 forkchild(jp, n, mode);
7227 else
7228 forkparent(jp, n, mode, pid);
7229 return pid;
7230}
Eric Andersencb57d552001-06-28 07:25:16 +00007231
7232/*
7233 * Wait for job to finish.
7234 *
7235 * Under job control we have the problem that while a child process is
7236 * running interrupts generated by the user are sent to the child but not
7237 * to the shell. This means that an infinite loop started by an inter-
7238 * active user may be hard to kill. With job control turned off, an
7239 * interactive user may place an interactive program inside a loop. If
7240 * the interactive program catches interrupts, the user doesn't want
7241 * these interrupts to also abort the loop. The approach we take here
7242 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007243 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007244 * signal if the child process was terminated by an interrupt signal.
7245 * Unfortunately, some programs want to do a bit of cleanup and then
7246 * exit on interrupt; unless these processes terminate themselves by
7247 * sending a signal to themselves (instead of calling exit) they will
7248 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007249 *
7250 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007251 */
7252
Eric Andersenc470f442003-07-28 09:56:35 +00007253int
7254waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007255{
Eric Andersencb57d552001-06-28 07:25:16 +00007256 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007257
Eric Andersenc470f442003-07-28 09:56:35 +00007258 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7259 while (jp->state == JOBRUNNING) {
7260 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007261 }
Eric Andersenc470f442003-07-28 09:56:35 +00007262 st = getstatus(jp);
7263#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007264 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007265 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007266 /*
7267 * This is truly gross.
7268 * If we're doing job control, then we did a TIOCSPGRP which
7269 * caused us (the shell) to no longer be in the controlling
7270 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7271 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007272 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007273 */
Eric Andersenc470f442003-07-28 09:56:35 +00007274 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007275 raise(SIGINT);
7276 }
Eric Andersen2870d962001-07-02 17:27:21 +00007277 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007278#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007279 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007280 return st;
7281}
7282
7283
Eric Andersen62483552001-07-10 06:09:16 +00007284/*
7285 * Do a wait system call. If job control is compiled in, we accept
7286 * stopped processes. If block is zero, we return a value of zero
7287 * rather than blocking.
7288 *
7289 * System V doesn't have a non-blocking wait system call. It does
7290 * have a SIGCLD signal that is sent to a process when one of it's
7291 * children dies. The obvious way to use SIGCLD would be to install
7292 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7293 * was received, and have waitproc bump another counter when it got
7294 * the status of a process. Waitproc would then know that a wait
7295 * system call would not block if the two counters were different.
7296 * This approach doesn't work because if a process has children that
7297 * have not been waited for, System V will send it a SIGCLD when it
7298 * installs a signal handler for SIGCLD. What this means is that when
7299 * a child exits, the shell will be sent SIGCLD signals continuously
7300 * until is runs out of stack space, unless it does a wait call before
7301 * restoring the signal handler. The code below takes advantage of
7302 * this (mis)feature by installing a signal handler for SIGCLD and
7303 * then checking to see whether it was called. If there are any
7304 * children to be waited for, it will be.
7305 *
Eric Andersenc470f442003-07-28 09:56:35 +00007306 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7307 * waits at all. In this case, the user will not be informed when
7308 * a background process until the next time she runs a real program
7309 * (as opposed to running a builtin command or just typing return),
7310 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007311 */
7312
Eric Andersenc470f442003-07-28 09:56:35 +00007313static inline int
7314waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007315{
Eric Andersenc470f442003-07-28 09:56:35 +00007316 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007317
Eric Andersenc470f442003-07-28 09:56:35 +00007318#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007319 if (jobctl)
7320 flags |= WUNTRACED;
7321#endif
7322 if (block == 0)
7323 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007324 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007325}
7326
Eric Andersenc470f442003-07-28 09:56:35 +00007327/*
7328 * Wait for a process to terminate.
7329 */
7330
7331static int
7332dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007333{
7334 int pid;
7335 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007336 struct job *jp;
7337 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007338 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007339
7340 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007341 pid = waitproc(block, &status);
7342 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007343 if (pid <= 0)
7344 return pid;
7345 INTOFF;
7346 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007347 for (jp = curjob; jp; jp = jp->prev_job) {
7348 struct procstat *sp;
7349 struct procstat *spend;
7350 if (jp->state == JOBDONE)
7351 continue;
7352 state = JOBDONE;
7353 spend = jp->ps + jp->nprocs;
7354 sp = jp->ps;
7355 do {
7356 if (sp->pid == pid) {
7357 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7358 sp->status = status;
7359 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007360 }
Eric Andersenc470f442003-07-28 09:56:35 +00007361 if (sp->status == -1)
7362 state = JOBRUNNING;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007363#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007364 if (state == JOBRUNNING)
7365 continue;
7366 if (WIFSTOPPED(sp->status)) {
7367 jp->stopstatus = sp->status;
7368 state = JOBSTOPPED;
7369 }
Eric Andersencb57d552001-06-28 07:25:16 +00007370#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007371 } while (++sp < spend);
7372 if (thisjob)
7373 goto gotjob;
7374 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007375#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007376 if (!WIFSTOPPED(status))
7377#endif
7378
7379 jobless--;
7380 goto out;
7381
7382gotjob:
7383 if (state != JOBRUNNING) {
7384 thisjob->changed = 1;
7385
7386 if (thisjob->state != state) {
7387 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7388 thisjob->state = state;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007389#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007390 if (state == JOBSTOPPED) {
7391 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007392 }
Eric Andersenc470f442003-07-28 09:56:35 +00007393#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007394 }
7395 }
Eric Andersencb57d552001-06-28 07:25:16 +00007396
Eric Andersenc470f442003-07-28 09:56:35 +00007397out:
7398 INTON;
7399
7400 if (thisjob && thisjob == job) {
7401 char s[48 + 1];
7402 int len;
7403
7404 len = sprint_status(s, status, 1);
7405 if (len) {
7406 s[len] = '\n';
7407 s[len + 1] = 0;
7408 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007409 }
Eric Andersencb57d552001-06-28 07:25:16 +00007410 }
7411 return pid;
7412}
7413
7414
Eric Andersencb57d552001-06-28 07:25:16 +00007415/*
7416 * return 1 if there are stopped jobs, otherwise 0
7417 */
Eric Andersen90898442003-08-06 11:20:52 +00007418
Eric Andersenc470f442003-07-28 09:56:35 +00007419int
7420stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007421{
Eric Andersencb57d552001-06-28 07:25:16 +00007422 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007423 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007424
Eric Andersenc470f442003-07-28 09:56:35 +00007425 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007426 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007427 goto out;
7428 jp = curjob;
7429 if (jp && jp->state == JOBSTOPPED) {
7430 out2str("You have stopped jobs.\n");
7431 job_warning = 2;
7432 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007433 }
7434
Eric Andersenc470f442003-07-28 09:56:35 +00007435out:
7436 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007437}
7438
7439/*
7440 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007441 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007442 */
7443
Eric Andersenc470f442003-07-28 09:56:35 +00007444#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007445static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007446
Eric Andersenc470f442003-07-28 09:56:35 +00007447static char *
7448commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007449{
Eric Andersenc470f442003-07-28 09:56:35 +00007450 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007451
Eric Andersenc470f442003-07-28 09:56:35 +00007452 STARTSTACKSTR(cmdnextc);
7453 cmdtxt(n);
7454 name = stackblock();
7455 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7456 name, cmdnextc, cmdnextc));
7457 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007458}
7459
Eric Andersenc470f442003-07-28 09:56:35 +00007460static void
7461cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007462{
Eric Andersencb57d552001-06-28 07:25:16 +00007463 union node *np;
7464 struct nodelist *lp;
7465 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007466 char s[2];
7467
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007468 if (!n)
7469 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007470 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007471 default:
7472#if DEBUG
7473 abort();
7474#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007475 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007476 lp = n->npipe.cmdlist;
7477 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007478 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007479 lp = lp->next;
7480 if (!lp)
7481 break;
7482 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007483 }
7484 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007485 case NSEMI:
7486 p = "; ";
7487 goto binop;
7488 case NAND:
7489 p = " && ";
7490 goto binop;
7491 case NOR:
7492 p = " || ";
7493binop:
7494 cmdtxt(n->nbinary.ch1);
7495 cmdputs(p);
7496 n = n->nbinary.ch2;
7497 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007498 case NREDIR:
7499 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007500 n = n->nredir.n;
7501 goto donode;
7502 case NNOT:
7503 cmdputs("!");
7504 n = n->nnot.com;
7505donode:
7506 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007507 break;
7508 case NIF:
7509 cmdputs("if ");
7510 cmdtxt(n->nif.test);
7511 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007512 n = n->nif.ifpart;
7513 if (n->nif.elsepart) {
7514 cmdtxt(n);
7515 cmdputs("; else ");
7516 n = n->nif.elsepart;
7517 }
7518 p = "; fi";
7519 goto dotail;
7520 case NSUBSHELL:
7521 cmdputs("(");
7522 n = n->nredir.n;
7523 p = ")";
7524 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007525 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007526 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007527 goto until;
7528 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007529 p = "until ";
7530until:
7531 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007532 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007533 n = n->nbinary.ch2;
7534 p = "; done";
7535dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007536 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007537dotail:
7538 cmdtxt(n);
7539 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007540 case NFOR:
7541 cmdputs("for ");
7542 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007543 cmdputs(" in ");
7544 cmdlist(n->nfor.args, 1);
7545 n = n->nfor.body;
7546 p = "; done";
7547 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007548 case NDEFUN:
7549 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007550 p = "() { ... }";
7551 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007552 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007553 cmdlist(n->ncmd.args, 1);
7554 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007555 break;
7556 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007557 p = n->narg.text;
7558dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007559 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007560 break;
7561 case NHERE:
7562 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007563 p = "<<...";
7564 goto dotail2;
7565 case NCASE:
7566 cmdputs("case ");
7567 cmdputs(n->ncase.expr->narg.text);
7568 cmdputs(" in ");
7569 for (np = n->ncase.cases; np; np = np->nclist.next) {
7570 cmdtxt(np->nclist.pattern);
7571 cmdputs(") ");
7572 cmdtxt(np->nclist.body);
7573 cmdputs(";; ");
7574 }
7575 p = "esac";
7576 goto dotail2;
7577 case NTO:
7578 p = ">";
7579 goto redir;
7580 case NCLOBBER:
7581 p = ">|";
7582 goto redir;
7583 case NAPPEND:
7584 p = ">>";
7585 goto redir;
7586 case NTOFD:
7587 p = ">&";
7588 goto redir;
7589 case NFROM:
7590 p = "<";
7591 goto redir;
7592 case NFROMFD:
7593 p = "<&";
7594 goto redir;
7595 case NFROMTO:
7596 p = "<>";
7597redir:
7598 s[0] = n->nfile.fd + '0';
7599 s[1] = '\0';
7600 cmdputs(s);
7601 cmdputs(p);
7602 if (n->type == NTOFD || n->type == NFROMFD) {
7603 s[0] = n->ndup.dupfd + '0';
7604 p = s;
7605 goto dotail2;
7606 } else {
7607 n = n->nfile.fname;
7608 goto donode;
7609 }
Eric Andersencb57d552001-06-28 07:25:16 +00007610 }
7611}
Eric Andersencb57d552001-06-28 07:25:16 +00007612
Eric Andersenc470f442003-07-28 09:56:35 +00007613static void
7614cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007615{
Eric Andersenc470f442003-07-28 09:56:35 +00007616 for (; np; np = np->narg.next) {
7617 if (!sep)
7618 cmdputs(spcstr);
7619 cmdtxt(np);
7620 if (sep && np->narg.next)
7621 cmdputs(spcstr);
7622 }
Eric Andersencb57d552001-06-28 07:25:16 +00007623}
7624
Eric Andersenc470f442003-07-28 09:56:35 +00007625static void
7626cmdputs(const char *s)
7627{
7628 const char *p, *str;
7629 char c, cc[2] = " ";
7630 char *nextc;
7631 int subtype = 0;
7632 int quoted = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007633 static const char vstype[VSTYPE + 1][4] = {
7634 "", "}", "-", "+", "?", "=",
7635 "%", "%%", "#", "##"
Eric Andersenc470f442003-07-28 09:56:35 +00007636 };
Eric Andersenc470f442003-07-28 09:56:35 +00007637 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7638 p = s;
7639 while ((c = *p++) != 0) {
7640 str = 0;
7641 switch (c) {
7642 case CTLESC:
7643 c = *p++;
7644 break;
7645 case CTLVAR:
7646 subtype = *p++;
7647 if ((subtype & VSTYPE) == VSLENGTH)
7648 str = "${#";
7649 else
7650 str = "${";
7651 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7652 quoted ^= 1;
7653 c = '"';
7654 } else
7655 goto dostr;
7656 break;
7657 case CTLENDVAR:
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007658 str = "\"}" + !(quoted & 1);
Eric Andersenc470f442003-07-28 09:56:35 +00007659 quoted >>= 1;
7660 subtype = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007661 goto dostr;
Eric Andersenc470f442003-07-28 09:56:35 +00007662 case CTLBACKQ:
7663 str = "$(...)";
7664 goto dostr;
7665 case CTLBACKQ+CTLQUOTE:
7666 str = "\"$(...)\"";
7667 goto dostr;
7668#ifdef CONFIG_ASH_MATH_SUPPORT
7669 case CTLARI:
7670 str = "$((";
7671 goto dostr;
7672 case CTLENDARI:
7673 str = "))";
7674 goto dostr;
7675#endif
7676 case CTLQUOTEMARK:
7677 quoted ^= 1;
7678 c = '"';
7679 break;
7680 case '=':
7681 if (subtype == 0)
7682 break;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007683 if ((subtype & VSTYPE) != VSNORMAL)
7684 quoted <<= 1;
Eric Andersenc470f442003-07-28 09:56:35 +00007685 str = vstype[subtype & VSTYPE];
7686 if (subtype & VSNUL)
7687 c = ':';
7688 else
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007689 goto checkstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007690 break;
7691 case '\'':
7692 case '\\':
7693 case '"':
7694 case '$':
7695 /* These can only happen inside quotes */
7696 cc[0] = c;
7697 str = cc;
7698 c = '\\';
7699 break;
7700 default:
7701 break;
7702 }
7703 USTPUTC(c, nextc);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007704checkstr:
Eric Andersenc470f442003-07-28 09:56:35 +00007705 if (!str)
7706 continue;
7707dostr:
7708 while ((c = *str++)) {
7709 USTPUTC(c, nextc);
7710 }
7711 }
7712 if (quoted & 1) {
7713 USTPUTC('"', nextc);
7714 }
7715 *nextc = 0;
7716 cmdnextc = nextc;
7717}
7718
7719
7720static void
7721showpipe(struct job *jp, FILE *out)
7722{
7723 struct procstat *sp;
7724 struct procstat *spend;
7725
7726 spend = jp->ps + jp->nprocs;
7727 for (sp = jp->ps + 1; sp < spend; sp++)
7728 fprintf(out, " | %s", sp->cmd);
7729 outcslow('\n', out);
7730 flushall();
7731}
7732
7733static void
7734xtcsetpgrp(int fd, pid_t pgrp)
7735{
7736 if (tcsetpgrp(fd, pgrp))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007737 sh_error("Cannot set tty process group (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +00007738}
7739#endif /* JOBS */
7740
7741static int
7742getstatus(struct job *job) {
7743 int status;
7744 int retval;
7745
7746 status = job->ps[job->nprocs - 1].status;
7747 retval = WEXITSTATUS(status);
7748 if (!WIFEXITED(status)) {
7749#if JOBS
7750 retval = WSTOPSIG(status);
7751 if (!WIFSTOPPED(status))
7752#endif
7753 {
7754 /* XXX: limits number of signals */
7755 retval = WTERMSIG(status);
7756#if JOBS
7757 if (retval == SIGINT)
7758 job->sigint = 1;
7759#endif
7760 }
7761 retval += 128;
7762 }
7763 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7764 jobno(job), job->nprocs, status, retval));
7765 return retval;
7766}
7767
Eric Andersend35c5df2002-01-09 15:37:36 +00007768#ifdef CONFIG_ASH_MAIL
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007769/* mail.c */
Eric Andersenec074692001-10-31 11:05:49 +00007770
Eric Andersencb57d552001-06-28 07:25:16 +00007771/*
Eric Andersenc470f442003-07-28 09:56:35 +00007772 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007773 */
7774
Eric Andersencb57d552001-06-28 07:25:16 +00007775#define MAXMBOXES 10
7776
Eric Andersenc470f442003-07-28 09:56:35 +00007777/* times of mailboxes */
7778static time_t mailtime[MAXMBOXES];
7779/* Set if MAIL or MAILPATH is changed. */
7780static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007781
7782
7783
7784/*
Eric Andersenc470f442003-07-28 09:56:35 +00007785 * Print appropriate message(s) if mail has arrived.
7786 * If mail_var_path_changed is set,
7787 * then the value of MAIL has mail_var_path_changed,
7788 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007789 */
7790
Eric Andersenc470f442003-07-28 09:56:35 +00007791static void
7792chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007793{
Eric Andersencb57d552001-06-28 07:25:16 +00007794 const char *mpath;
7795 char *p;
7796 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007797 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007798 struct stackmark smark;
7799 struct stat statb;
7800
Eric Andersencb57d552001-06-28 07:25:16 +00007801 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007802 mpath = mpathset() ? mpathval() : mailval();
7803 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007804 p = padvance(&mpath, nullstr);
7805 if (p == NULL)
7806 break;
7807 if (*p == '\0')
7808 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007809 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007810#ifdef DEBUG
7811 if (q[-1] != '/')
7812 abort();
7813#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007814 q[-1] = '\0'; /* delete trailing '/' */
7815 if (stat(p, &statb) < 0) {
7816 *mtp = 0;
7817 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007818 }
Eric Andersenc470f442003-07-28 09:56:35 +00007819 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7820 fprintf(
7821 stderr, snlfmt,
7822 pathopt ? pathopt : "you have mail"
7823 );
7824 }
7825 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007826 }
Eric Andersenc470f442003-07-28 09:56:35 +00007827 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007828 popstackmark(&smark);
7829}
Eric Andersencb57d552001-06-28 07:25:16 +00007830
Eric Andersenec074692001-10-31 11:05:49 +00007831
Eric Andersenc470f442003-07-28 09:56:35 +00007832static void
7833changemail(const char *val)
7834{
7835 mail_var_path_changed++;
7836}
7837
7838#endif /* CONFIG_ASH_MAIL */
7839
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007840/* main.c */
Eric Andersenc470f442003-07-28 09:56:35 +00007841
Eric Andersencb57d552001-06-28 07:25:16 +00007842
Eric Andersencb57d552001-06-28 07:25:16 +00007843#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007844static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007845extern int etext();
7846#endif
7847
Eric Andersenc470f442003-07-28 09:56:35 +00007848static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007849
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007850static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007851
Eric Andersencb57d552001-06-28 07:25:16 +00007852/*
7853 * Main routine. We initialize things, parse the arguments, execute
7854 * profiles if we're a login shell, and then call cmdloop to execute
7855 * commands. The setjmp call sets up the location to jump to when an
7856 * exception occurs. When an exception occurs the variable "state"
7857 * is used to figure out how far we had gotten.
7858 */
7859
Eric Andersenc470f442003-07-28 09:56:35 +00007860int
7861ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007862{
Eric Andersenc470f442003-07-28 09:56:35 +00007863 char *shinit;
7864 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007865 struct jmploc jmploc;
7866 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007867
Eric Andersenc470f442003-07-28 09:56:35 +00007868#ifdef __GLIBC__
7869 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007870#endif
7871
Eric Andersencb57d552001-06-28 07:25:16 +00007872#if PROFILE
7873 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7874#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007875 state = 0;
7876 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007877 int e;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007878 int s;
Eric Andersenc470f442003-07-28 09:56:35 +00007879
Eric Andersencb57d552001-06-28 07:25:16 +00007880 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007881
7882 e = exception;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007883 if (e == EXERROR)
7884 exitstatus = 2;
7885 s = state;
7886 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00007887 exitshell();
7888
Eric Andersen90898442003-08-06 11:20:52 +00007889 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007890 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007891 }
7892 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007893 FORCEINTON; /* enable interrupts */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007894 if (s == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00007895 goto state1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007896 else if (s == 2)
Eric Andersencb57d552001-06-28 07:25:16 +00007897 goto state2;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007898 else if (s == 3)
Eric Andersencb57d552001-06-28 07:25:16 +00007899 goto state3;
7900 else
7901 goto state4;
7902 }
7903 handler = &jmploc;
7904#ifdef DEBUG
7905 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007906 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007907#endif
7908 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007909
7910#ifdef CONFIG_ASH_RANDOM_SUPPORT
7911 rseed = rootpid + ((time_t)time((time_t *)0));
7912#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007913 init();
7914 setstackmark(&smark);
7915 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007916#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7917 if ( iflag ) {
7918 const char *hp = lookupvar("HISTFILE");
7919
7920 if(hp == NULL ) {
7921 hp = lookupvar("HOME");
7922 if(hp != NULL) {
7923 char *defhp = concat_path_file(hp, ".ash_history");
7924 setvar("HISTFILE", defhp, 0);
7925 free(defhp);
7926 }
7927 }
7928 }
7929#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007930 if (argv[0] && argv[0][0] == '-')
7931 isloginsh = 1;
7932 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007933 state = 1;
7934 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007935state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007936 state = 2;
7937 read_profile(".profile");
7938 }
Eric Andersenc470f442003-07-28 09:56:35 +00007939state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007940 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007941 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007942#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007943 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007944#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007945 iflag
7946 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007947 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007948 read_profile(shinit);
7949 }
Eric Andersencb57d552001-06-28 07:25:16 +00007950 }
Eric Andersenc470f442003-07-28 09:56:35 +00007951state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007952 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007953 if (minusc)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007954 evalstring(minusc, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007955
7956 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007957#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007958 if ( iflag ) {
7959 const char *hp = lookupvar("HISTFILE");
7960
7961 if(hp != NULL )
7962 load_history ( hp );
7963 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007964#endif
Eric Andersen90898442003-08-06 11:20:52 +00007965state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007966 cmdloop(1);
7967 }
7968#if PROFILE
7969 monitor(0);
7970#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007971#if GPROF
7972 {
7973 extern void _mcleanup(void);
7974 _mcleanup();
7975 }
7976#endif
7977 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007978 /* NOTREACHED */
7979}
7980
7981
7982/*
7983 * Read and execute commands. "Top" is nonzero for the top level command
7984 * loop; it turns on prompting if the shell is interactive.
7985 */
7986
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007987static int
Eric Andersenc470f442003-07-28 09:56:35 +00007988cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007989{
7990 union node *n;
7991 struct stackmark smark;
7992 int inter;
7993 int numeof = 0;
7994
7995 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00007996 for (;;) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007997 int skip;
7998
Glenn L McGrath76620622004-01-13 10:19:37 +00007999 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00008000#if JOBS
8001 if (jobctl)
8002 showjobs(stderr, SHOW_CHANGED);
8003#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008004 inter = 0;
8005 if (iflag && top) {
8006 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008007#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008008 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008009#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008010 }
8011 n = parsecmd(inter);
8012 /* showtree(n); DEBUG */
8013 if (n == NEOF) {
8014 if (!top || numeof >= 50)
8015 break;
8016 if (!stoppedjobs()) {
8017 if (!Iflag)
8018 break;
8019 out2str("\nUse \"exit\" to leave shell.\n");
8020 }
8021 numeof++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008022 } else if (nflag == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008023 job_warning = (job_warning == 2) ? 1 : 0;
8024 numeof = 0;
8025 evaltree(n, 0);
8026 }
8027 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008028 skip = evalskip;
8029
8030 if (skip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008031 evalskip = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008032 return skip & SKIPEVAL;
Eric Andersencb57d552001-06-28 07:25:16 +00008033 }
8034 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008035
8036 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008037}
8038
8039
Eric Andersencb57d552001-06-28 07:25:16 +00008040/*
8041 * Read /etc/profile or .profile. Return on error.
8042 */
8043
Eric Andersenc470f442003-07-28 09:56:35 +00008044static void
8045read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008046{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008047 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008048
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008049 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008050 return;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008051
8052 skip = cmdloop(0);
Eric Andersencb57d552001-06-28 07:25:16 +00008053 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008054
8055 if (skip)
8056 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00008057}
8058
8059
Eric Andersencb57d552001-06-28 07:25:16 +00008060/*
8061 * Read a file containing shell functions.
8062 */
8063
Eric Andersenc470f442003-07-28 09:56:35 +00008064static void
8065readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008066{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008067 setinputfile(name, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008068 cmdloop(0);
8069 popfile();
8070}
8071
8072
Eric Andersencb57d552001-06-28 07:25:16 +00008073/*
Eric Andersenc470f442003-07-28 09:56:35 +00008074 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008075 * search for the file, which is necessary to find sub-commands.
8076 */
8077
Eric Andersenc470f442003-07-28 09:56:35 +00008078static inline char *
8079find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008080{
8081 char *fullname;
8082 const char *path = pathval();
8083 struct stat statb;
8084
8085 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008086 if (strchr(name, '/'))
8087 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008088
Eric Andersenc470f442003-07-28 09:56:35 +00008089 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008090 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8091 /*
8092 * Don't bother freeing here, since it will
8093 * be freed by the caller.
8094 */
8095 return fullname;
8096 }
8097 stunalloc(fullname);
8098 }
8099
8100 /* not found in the PATH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008101 sh_error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008102 /* NOTREACHED */
8103}
8104
Eric Andersen1e6aba92004-04-12 19:12:13 +00008105static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008106{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008107 struct strlist *sp;
8108 volatile struct shparam saveparam;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008109 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008110
Eric Andersen1e6aba92004-04-12 19:12:13 +00008111 for (sp = cmdenviron; sp; sp = sp->next)
8112 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8113
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00008114 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008115 char *fullname;
Eric Andersencb57d552001-06-28 07:25:16 +00008116
Eric Andersencb57d552001-06-28 07:25:16 +00008117 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008118
8119 if (argc > 2) {
8120 saveparam = shellparam;
8121 shellparam.malloc = 0;
8122 shellparam.nparam = argc - 2;
8123 shellparam.p = argv + 2;
8124 };
8125
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008126 setinputfile(fullname, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008127 commandname = fullname;
8128 cmdloop(0);
8129 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008130
8131 if (argc > 2) {
8132 freeparam(&shellparam);
8133 shellparam = saveparam;
8134 };
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008135 status = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00008136 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008137 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008138}
8139
8140
Eric Andersenc470f442003-07-28 09:56:35 +00008141static int
8142exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008143{
8144 if (stoppedjobs())
8145 return 0;
8146 if (argc > 1)
8147 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008148 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008149 /* NOTREACHED */
8150}
Eric Andersen62483552001-07-10 06:09:16 +00008151
Paul Fox0b621582005-08-09 19:38:05 +00008152#ifdef CONFIG_ASH_BUILTIN_ECHO
8153static int
8154echocmd(int argc, char **argv)
8155{
8156 return bb_echo(argc, argv);
8157}
8158#endif
Paul Fox6ab03782006-06-08 21:37:26 +00008159
8160#ifdef CONFIG_ASH_BUILTIN_TEST
8161static int
8162testcmd(int argc, char **argv)
8163{
8164 return bb_test(argc, argv);
8165}
8166#endif
8167
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008168/* memalloc.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008169
8170/*
Eric Andersen90898442003-08-06 11:20:52 +00008171 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008172 */
8173
8174static pointer
8175ckrealloc(pointer p, size_t nbytes)
8176{
8177 p = realloc(p, nbytes);
8178 if (p == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008179 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008180 return p;
8181}
8182
Eric Andersen90898442003-08-06 11:20:52 +00008183static pointer
8184ckmalloc(size_t nbytes)
8185{
8186 return ckrealloc(NULL, nbytes);
8187}
Eric Andersenc470f442003-07-28 09:56:35 +00008188
8189/*
8190 * Make a copy of a string in safe storage.
8191 */
8192
8193static char *
8194savestr(const char *s)
8195{
8196 char *p = strdup(s);
8197 if (!p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008198 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008199 return p;
8200}
8201
8202
8203/*
8204 * Parse trees for commands are allocated in lifo order, so we use a stack
8205 * to make this more efficient, and also to avoid all sorts of exception
8206 * handling code to handle interrupts in the middle of a parse.
8207 *
8208 * The size 504 was chosen because the Ultrix malloc handles that size
8209 * well.
8210 */
8211
8212
8213static pointer
8214stalloc(size_t nbytes)
8215{
8216 char *p;
8217 size_t aligned;
8218
8219 aligned = SHELL_ALIGN(nbytes);
8220 if (aligned > stacknleft) {
8221 size_t len;
8222 size_t blocksize;
8223 struct stack_block *sp;
8224
8225 blocksize = aligned;
8226 if (blocksize < MINSIZE)
8227 blocksize = MINSIZE;
8228 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8229 if (len < blocksize)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008230 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008231 INTOFF;
8232 sp = ckmalloc(len);
8233 sp->prev = stackp;
8234 stacknxt = sp->space;
8235 stacknleft = blocksize;
8236 sstrend = stacknxt + blocksize;
8237 stackp = sp;
8238 INTON;
8239 }
8240 p = stacknxt;
8241 stacknxt += aligned;
8242 stacknleft -= aligned;
8243 return p;
8244}
8245
8246
8247void
8248stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008249{
Eric Andersencb57d552001-06-28 07:25:16 +00008250#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008251 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008252 write(2, "stunalloc\n", 10);
8253 abort();
8254 }
8255#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008256 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008257 stacknxt = p;
8258}
8259
8260
Eric Andersenc470f442003-07-28 09:56:35 +00008261void
8262setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008263{
Eric Andersencb57d552001-06-28 07:25:16 +00008264 mark->stackp = stackp;
8265 mark->stacknxt = stacknxt;
8266 mark->stacknleft = stacknleft;
8267 mark->marknext = markp;
8268 markp = mark;
8269}
8270
8271
Eric Andersenc470f442003-07-28 09:56:35 +00008272void
8273popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008274{
Eric Andersencb57d552001-06-28 07:25:16 +00008275 struct stack_block *sp;
8276
8277 INTOFF;
8278 markp = mark->marknext;
8279 while (stackp != mark->stackp) {
8280 sp = stackp;
8281 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008282 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008283 }
8284 stacknxt = mark->stacknxt;
8285 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008286 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008287 INTON;
8288}
8289
8290
8291/*
8292 * When the parser reads in a string, it wants to stick the string on the
8293 * stack and only adjust the stack pointer when it knows how big the
8294 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8295 * of space on top of the stack and stackblocklen returns the length of
8296 * this block. Growstackblock will grow this space by at least one byte,
8297 * possibly moving it (like realloc). Grabstackblock actually allocates the
8298 * part of the block that has been used.
8299 */
8300
Eric Andersenc470f442003-07-28 09:56:35 +00008301void
8302growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008303{
Eric Andersenc470f442003-07-28 09:56:35 +00008304 size_t newlen;
8305
8306 newlen = stacknleft * 2;
8307 if (newlen < stacknleft)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008308 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008309 if (newlen < 128)
8310 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008311
8312 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008313 struct stack_block *oldstackp;
8314 struct stackmark *xmark;
8315 struct stack_block *sp;
8316 struct stack_block *prevstackp;
8317 size_t grosslen;
8318
Eric Andersencb57d552001-06-28 07:25:16 +00008319 INTOFF;
8320 oldstackp = stackp;
8321 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008322 prevstackp = sp->prev;
8323 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8324 sp = ckrealloc((pointer)sp, grosslen);
8325 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008326 stackp = sp;
8327 stacknxt = sp->space;
8328 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008329 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008330
Eric Andersenc470f442003-07-28 09:56:35 +00008331 /*
8332 * Stack marks pointing to the start of the old block
8333 * must be relocated to point to the new block
8334 */
8335 xmark = markp;
8336 while (xmark != NULL && xmark->stackp == oldstackp) {
8337 xmark->stackp = stackp;
8338 xmark->stacknxt = stacknxt;
8339 xmark->stacknleft = stacknleft;
8340 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008341 }
8342 INTON;
8343 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008344 char *oldspace = stacknxt;
8345 int oldlen = stacknleft;
8346 char *p = stalloc(newlen);
8347
8348 /* free the space we just allocated */
8349 stacknxt = memcpy(p, oldspace, oldlen);
8350 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008351 }
8352}
8353
Eric Andersenc470f442003-07-28 09:56:35 +00008354static inline void
8355grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008356{
Eric Andersenc470f442003-07-28 09:56:35 +00008357 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008358 stacknxt += len;
8359 stacknleft -= len;
8360}
8361
Eric Andersencb57d552001-06-28 07:25:16 +00008362/*
Eric Andersenc470f442003-07-28 09:56:35 +00008363 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008364 * The user declares a variable of type STACKSTR, which may be declared
8365 * to be a register. The macro STARTSTACKSTR initializes things. Then
8366 * the user uses the macro STPUTC to add characters to the string. In
8367 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8368 * grown as necessary. When the user is done, she can just leave the
8369 * string there and refer to it using stackblock(). Or she can allocate
8370 * the space for it using grabstackstr(). If it is necessary to allow
8371 * someone else to use the stack temporarily and then continue to grow
8372 * the string, the user should use grabstack to allocate the space, and
8373 * then call ungrabstr(p) to return to the previous mode of operation.
8374 *
8375 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8376 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8377 * is space for at least one character.
8378 */
8379
Eric Andersenc470f442003-07-28 09:56:35 +00008380void *
8381growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008382{
Eric Andersenc470f442003-07-28 09:56:35 +00008383 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008384 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008385 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008386 return stackblock();
8387 }
8388 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008389 return stackblock() + len;
8390}
8391
Eric Andersencb57d552001-06-28 07:25:16 +00008392/*
8393 * Called from CHECKSTRSPACE.
8394 */
8395
Eric Andersenc470f442003-07-28 09:56:35 +00008396char *
8397makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008398{
Eric Andersenc470f442003-07-28 09:56:35 +00008399 size_t len = p - stacknxt;
8400 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008401
Eric Andersenc470f442003-07-28 09:56:35 +00008402 for (;;) {
8403 size_t nleft;
8404
8405 size = stackblocksize();
8406 nleft = size - len;
8407 if (nleft >= newlen)
8408 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008409 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008410 }
Eric Andersencb57d552001-06-28 07:25:16 +00008411 return stackblock() + len;
8412}
8413
Eric Andersenc470f442003-07-28 09:56:35 +00008414char *
8415stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008416{
Eric Andersenc470f442003-07-28 09:56:35 +00008417 p = makestrspace(n, p);
8418 p = mempcpy(p, s, n);
8419 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008420}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008421
Eric Andersenc470f442003-07-28 09:56:35 +00008422char *
8423stputs(const char *s, char *p)
8424{
8425 return stnputs(s, strlen(s), p);
8426}
8427
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008428/* mystring.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008429
Eric Andersencb57d552001-06-28 07:25:16 +00008430/*
Eric Andersenc470f442003-07-28 09:56:35 +00008431 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008432 *
Eric Andersenc470f442003-07-28 09:56:35 +00008433 * number(s) Convert a string of digits to an integer.
8434 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008435 */
8436
Eric Andersencb57d552001-06-28 07:25:16 +00008437/*
8438 * prefix -- see if pfx is a prefix of string.
8439 */
8440
Eric Andersenc470f442003-07-28 09:56:35 +00008441char *
8442prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008443{
Eric Andersencb57d552001-06-28 07:25:16 +00008444 while (*pfx) {
8445 if (*pfx++ != *string++)
8446 return 0;
8447 }
Eric Andersenc470f442003-07-28 09:56:35 +00008448 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008449}
8450
8451
8452/*
8453 * Convert a string of digits to an integer, printing an error message on
8454 * failure.
8455 */
8456
Eric Andersenc470f442003-07-28 09:56:35 +00008457int
8458number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008459{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008460
Eric Andersenc470f442003-07-28 09:56:35 +00008461 if (! is_number(s))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008462 sh_error(illnum, s);
Eric Andersenc470f442003-07-28 09:56:35 +00008463 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008464}
8465
Eric Andersenc470f442003-07-28 09:56:35 +00008466
Eric Andersenc470f442003-07-28 09:56:35 +00008467/*
8468 * Check for a valid number. This should be elsewhere.
8469 */
8470
8471int
8472is_number(const char *p)
8473{
8474 do {
8475 if (! is_digit(*p))
8476 return 0;
8477 } while (*++p != '\0');
8478 return 1;
8479}
8480
8481
Eric Andersencb57d552001-06-28 07:25:16 +00008482/*
8483 * Produce a possibly single quoted string suitable as input to the shell.
8484 * The return string is allocated on the stack.
8485 */
8486
Eric Andersenc470f442003-07-28 09:56:35 +00008487char *
8488single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008489 char *p;
8490
8491 STARTSTACKSTR(p);
8492
8493 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008494 char *q;
8495 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008496
Eric Andersenc470f442003-07-28 09:56:35 +00008497 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008498
Eric Andersenc470f442003-07-28 09:56:35 +00008499 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008500
Eric Andersenc470f442003-07-28 09:56:35 +00008501 *q++ = '\'';
8502 q = mempcpy(q, s, len);
8503 *q++ = '\'';
8504 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008505
Eric Andersenc470f442003-07-28 09:56:35 +00008506 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008507
Eric Andersenc470f442003-07-28 09:56:35 +00008508 len = strspn(s, "'");
8509 if (!len)
8510 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008511
Eric Andersenc470f442003-07-28 09:56:35 +00008512 q = p = makestrspace(len + 3, p);
8513
8514 *q++ = '"';
8515 q = mempcpy(q, s, len);
8516 *q++ = '"';
8517 s += len;
8518
8519 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008520 } while (*s);
8521
8522 USTPUTC(0, p);
8523
Eric Andersenc470f442003-07-28 09:56:35 +00008524 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008525}
8526
8527/*
Eric Andersenc470f442003-07-28 09:56:35 +00008528 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008529 */
8530
Eric Andersenc470f442003-07-28 09:56:35 +00008531char *
8532sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008533{
Eric Andersenc470f442003-07-28 09:56:35 +00008534 size_t len = strlen(p) + 1;
8535 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008536}
Eric Andersenc470f442003-07-28 09:56:35 +00008537
8538
8539static void
8540calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008541{
Eric Andersenc470f442003-07-28 09:56:35 +00008542 if (n == NULL)
8543 return;
8544 funcblocksize += nodesize[n->type];
8545 switch (n->type) {
8546 case NCMD:
8547 calcsize(n->ncmd.redirect);
8548 calcsize(n->ncmd.args);
8549 calcsize(n->ncmd.assign);
8550 break;
8551 case NPIPE:
8552 sizenodelist(n->npipe.cmdlist);
8553 break;
8554 case NREDIR:
8555 case NBACKGND:
8556 case NSUBSHELL:
8557 calcsize(n->nredir.redirect);
8558 calcsize(n->nredir.n);
8559 break;
8560 case NAND:
8561 case NOR:
8562 case NSEMI:
8563 case NWHILE:
8564 case NUNTIL:
8565 calcsize(n->nbinary.ch2);
8566 calcsize(n->nbinary.ch1);
8567 break;
8568 case NIF:
8569 calcsize(n->nif.elsepart);
8570 calcsize(n->nif.ifpart);
8571 calcsize(n->nif.test);
8572 break;
8573 case NFOR:
8574 funcstringsize += strlen(n->nfor.var) + 1;
8575 calcsize(n->nfor.body);
8576 calcsize(n->nfor.args);
8577 break;
8578 case NCASE:
8579 calcsize(n->ncase.cases);
8580 calcsize(n->ncase.expr);
8581 break;
8582 case NCLIST:
8583 calcsize(n->nclist.body);
8584 calcsize(n->nclist.pattern);
8585 calcsize(n->nclist.next);
8586 break;
8587 case NDEFUN:
8588 case NARG:
8589 sizenodelist(n->narg.backquote);
8590 funcstringsize += strlen(n->narg.text) + 1;
8591 calcsize(n->narg.next);
8592 break;
8593 case NTO:
8594 case NCLOBBER:
8595 case NFROM:
8596 case NFROMTO:
8597 case NAPPEND:
8598 calcsize(n->nfile.fname);
8599 calcsize(n->nfile.next);
8600 break;
8601 case NTOFD:
8602 case NFROMFD:
8603 calcsize(n->ndup.vname);
8604 calcsize(n->ndup.next);
8605 break;
8606 case NHERE:
8607 case NXHERE:
8608 calcsize(n->nhere.doc);
8609 calcsize(n->nhere.next);
8610 break;
8611 case NNOT:
8612 calcsize(n->nnot.com);
8613 break;
8614 };
Eric Andersencb57d552001-06-28 07:25:16 +00008615}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008616
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008617
Eric Andersenc470f442003-07-28 09:56:35 +00008618static void
8619sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008620{
8621 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008622 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008623 calcsize(lp->n);
8624 lp = lp->next;
8625 }
8626}
Eric Andersencb57d552001-06-28 07:25:16 +00008627
8628
Eric Andersenc470f442003-07-28 09:56:35 +00008629static union node *
8630copynode(union node *n)
8631{
8632 union node *new;
8633
8634 if (n == NULL)
8635 return NULL;
8636 new = funcblock;
8637 funcblock = (char *) funcblock + nodesize[n->type];
8638 switch (n->type) {
8639 case NCMD:
8640 new->ncmd.redirect = copynode(n->ncmd.redirect);
8641 new->ncmd.args = copynode(n->ncmd.args);
8642 new->ncmd.assign = copynode(n->ncmd.assign);
8643 break;
8644 case NPIPE:
8645 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8646 new->npipe.backgnd = n->npipe.backgnd;
8647 break;
8648 case NREDIR:
8649 case NBACKGND:
8650 case NSUBSHELL:
8651 new->nredir.redirect = copynode(n->nredir.redirect);
8652 new->nredir.n = copynode(n->nredir.n);
8653 break;
8654 case NAND:
8655 case NOR:
8656 case NSEMI:
8657 case NWHILE:
8658 case NUNTIL:
8659 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8660 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8661 break;
8662 case NIF:
8663 new->nif.elsepart = copynode(n->nif.elsepart);
8664 new->nif.ifpart = copynode(n->nif.ifpart);
8665 new->nif.test = copynode(n->nif.test);
8666 break;
8667 case NFOR:
8668 new->nfor.var = nodesavestr(n->nfor.var);
8669 new->nfor.body = copynode(n->nfor.body);
8670 new->nfor.args = copynode(n->nfor.args);
8671 break;
8672 case NCASE:
8673 new->ncase.cases = copynode(n->ncase.cases);
8674 new->ncase.expr = copynode(n->ncase.expr);
8675 break;
8676 case NCLIST:
8677 new->nclist.body = copynode(n->nclist.body);
8678 new->nclist.pattern = copynode(n->nclist.pattern);
8679 new->nclist.next = copynode(n->nclist.next);
8680 break;
8681 case NDEFUN:
8682 case NARG:
8683 new->narg.backquote = copynodelist(n->narg.backquote);
8684 new->narg.text = nodesavestr(n->narg.text);
8685 new->narg.next = copynode(n->narg.next);
8686 break;
8687 case NTO:
8688 case NCLOBBER:
8689 case NFROM:
8690 case NFROMTO:
8691 case NAPPEND:
8692 new->nfile.fname = copynode(n->nfile.fname);
8693 new->nfile.fd = n->nfile.fd;
8694 new->nfile.next = copynode(n->nfile.next);
8695 break;
8696 case NTOFD:
8697 case NFROMFD:
8698 new->ndup.vname = copynode(n->ndup.vname);
8699 new->ndup.dupfd = n->ndup.dupfd;
8700 new->ndup.fd = n->ndup.fd;
8701 new->ndup.next = copynode(n->ndup.next);
8702 break;
8703 case NHERE:
8704 case NXHERE:
8705 new->nhere.doc = copynode(n->nhere.doc);
8706 new->nhere.fd = n->nhere.fd;
8707 new->nhere.next = copynode(n->nhere.next);
8708 break;
8709 case NNOT:
8710 new->nnot.com = copynode(n->nnot.com);
8711 break;
8712 };
8713 new->type = n->type;
8714 return new;
8715}
8716
8717
8718static struct nodelist *
8719copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008720{
8721 struct nodelist *start;
8722 struct nodelist **lpp;
8723
8724 lpp = &start;
8725 while (lp) {
8726 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008727 funcblock = (char *) funcblock +
8728 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008729 (*lpp)->n = copynode(lp->n);
8730 lp = lp->next;
8731 lpp = &(*lpp)->next;
8732 }
8733 *lpp = NULL;
8734 return start;
8735}
8736
8737
Eric Andersenc470f442003-07-28 09:56:35 +00008738static char *
8739nodesavestr(char *s)
8740{
8741 char *rtn = funcstring;
8742
8743 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008744 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008745}
8746
Eric Andersenc470f442003-07-28 09:56:35 +00008747
Eric Andersenc470f442003-07-28 09:56:35 +00008748/*
8749 * Free a parse tree.
8750 */
8751
8752static void
8753freefunc(struct funcnode *f)
8754{
8755 if (f && --f->count < 0)
8756 ckfree(f);
8757}
8758
8759
8760static void options(int);
8761static void setoption(int, int);
8762
Eric Andersencb57d552001-06-28 07:25:16 +00008763
Eric Andersencb57d552001-06-28 07:25:16 +00008764/*
8765 * Process the shell command line arguments.
8766 */
8767
Eric Andersenc470f442003-07-28 09:56:35 +00008768void
8769procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008770{
8771 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008772 const char *xminusc;
8773 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008774
Eric Andersenc470f442003-07-28 09:56:35 +00008775 xargv = argv;
8776 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008777 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008778 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008779 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008780 optlist[i] = 2;
8781 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008782 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008783 xargv = argptr;
8784 xminusc = minusc;
8785 if (*xargv == NULL) {
8786 if (xminusc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +00008787 sh_error(bb_msg_requires_arg, "-c");
Eric Andersencb57d552001-06-28 07:25:16 +00008788 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008789 }
Eric Andersencb57d552001-06-28 07:25:16 +00008790 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8791 iflag = 1;
8792 if (mflag == 2)
8793 mflag = iflag;
8794 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008795 if (optlist[i] == 2)
8796 optlist[i] = 0;
8797#if DEBUG == 2
8798 debug = 1;
8799#endif
8800 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8801 if (xminusc) {
8802 minusc = *xargv++;
8803 if (*xargv)
8804 goto setarg0;
8805 } else if (!sflag) {
8806 setinputfile(*xargv, 0);
8807setarg0:
8808 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008809 commandname = arg0;
8810 }
Eric Andersencb57d552001-06-28 07:25:16 +00008811
Eric Andersenc470f442003-07-28 09:56:35 +00008812 shellparam.p = xargv;
8813#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008814 shellparam.optind = 1;
8815 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008816#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008817 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008818 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008819 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008820 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008821 }
8822 optschanged();
8823}
8824
8825
Eric Andersenc470f442003-07-28 09:56:35 +00008826void
8827optschanged(void)
8828{
8829#ifdef DEBUG
8830 opentrace();
8831#endif
8832 setinteractive(iflag);
8833 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008834 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008835}
Eric Andersencb57d552001-06-28 07:25:16 +00008836
Eric Andersenc470f442003-07-28 09:56:35 +00008837static inline void
8838minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008839{
8840 int i;
8841
8842 if (name == NULL) {
8843 out1str("Current option settings\n");
8844 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008845 out1fmt("%-16s%s\n", optnames(i),
8846 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008847 } else {
8848 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008849 if (equal(name, optnames(i))) {
8850 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008851 return;
8852 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008853 sh_error("Illegal option -o %s", name);
Eric Andersen62483552001-07-10 06:09:16 +00008854 }
8855}
8856
Eric Andersenc470f442003-07-28 09:56:35 +00008857/*
8858 * Process shell options. The global variable argptr contains a pointer
8859 * to the argument list; we advance it past the options.
8860 */
Eric Andersen62483552001-07-10 06:09:16 +00008861
Eric Andersenc470f442003-07-28 09:56:35 +00008862static void
8863options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008864{
8865 char *p;
8866 int val;
8867 int c;
8868
8869 if (cmdline)
8870 minusc = NULL;
8871 while ((p = *argptr) != NULL) {
8872 argptr++;
8873 if ((c = *p++) == '-') {
8874 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008875 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8876 if (!cmdline) {
8877 /* "-" means turn off -x and -v */
8878 if (p[0] == '\0')
8879 xflag = vflag = 0;
8880 /* "--" means reset params */
8881 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008882 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008883 }
Eric Andersenc470f442003-07-28 09:56:35 +00008884 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008885 }
8886 } else if (c == '+') {
8887 val = 0;
8888 } else {
8889 argptr--;
8890 break;
8891 }
8892 while ((c = *p++) != '\0') {
8893 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008894 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008895 } else if (c == 'o') {
8896 minus_o(*argptr, val);
8897 if (*argptr)
8898 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008899 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008900 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008901 isloginsh = 1;
8902 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008903 } else {
8904 setoption(c, val);
8905 }
8906 }
8907 }
8908}
8909
Eric Andersencb57d552001-06-28 07:25:16 +00008910
Eric Andersenc470f442003-07-28 09:56:35 +00008911static void
8912setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008913{
Eric Andersencb57d552001-06-28 07:25:16 +00008914 int i;
8915
8916 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008917 if (optletters(i) == flag) {
8918 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008919 return;
8920 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008921 sh_error("Illegal option -%c", flag);
Eric Andersencb57d552001-06-28 07:25:16 +00008922 /* NOTREACHED */
8923}
8924
8925
8926
Eric Andersencb57d552001-06-28 07:25:16 +00008927/*
8928 * Set the shell parameters.
8929 */
8930
Eric Andersenc470f442003-07-28 09:56:35 +00008931void
8932setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008933{
Eric Andersencb57d552001-06-28 07:25:16 +00008934 char **newparam;
8935 char **ap;
8936 int nparam;
8937
Eric Andersenc470f442003-07-28 09:56:35 +00008938 for (nparam = 0 ; argv[nparam] ; nparam++);
8939 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008940 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008941 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008942 }
8943 *ap = NULL;
8944 freeparam(&shellparam);
8945 shellparam.malloc = 1;
8946 shellparam.nparam = nparam;
8947 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008948#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008949 shellparam.optind = 1;
8950 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008951#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008952}
8953
8954
8955/*
8956 * Free the list of positional parameters.
8957 */
8958
Eric Andersenc470f442003-07-28 09:56:35 +00008959void
8960freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008961{
Eric Andersencb57d552001-06-28 07:25:16 +00008962 char **ap;
8963
8964 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008965 for (ap = param->p ; *ap ; ap++)
8966 ckfree(*ap);
8967 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008968 }
8969}
8970
8971
8972
8973/*
8974 * The shift builtin command.
8975 */
8976
Eric Andersenc470f442003-07-28 09:56:35 +00008977int
8978shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008979{
8980 int n;
8981 char **ap1, **ap2;
8982
8983 n = 1;
8984 if (argc > 1)
8985 n = number(argv[1]);
8986 if (n > shellparam.nparam)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008987 sh_error("can't shift that many");
Eric Andersencb57d552001-06-28 07:25:16 +00008988 INTOFF;
8989 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008990 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008991 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008992 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008993 }
8994 ap2 = shellparam.p;
8995 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008996#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008997 shellparam.optind = 1;
8998 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008999#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009000 INTON;
9001 return 0;
9002}
9003
9004
9005
9006/*
9007 * The set command builtin.
9008 */
9009
Eric Andersenc470f442003-07-28 09:56:35 +00009010int
9011setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009012{
9013 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009014 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009015 INTOFF;
9016 options(0);
9017 optschanged();
9018 if (*argptr != NULL) {
9019 setparam(argptr);
9020 }
9021 INTON;
9022 return 0;
9023}
9024
9025
Eric Andersenc470f442003-07-28 09:56:35 +00009026#ifdef CONFIG_ASH_GETOPTS
9027static void
9028getoptsreset(value)
9029 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009030{
9031 shellparam.optind = number(value);
9032 shellparam.optoff = -1;
9033}
Eric Andersenc470f442003-07-28 09:56:35 +00009034#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009035
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009036#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009037static void change_lc_all(const char *value)
9038{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009039 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009040 setlocale(LC_ALL, value);
9041}
9042
9043static void change_lc_ctype(const char *value)
9044{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009045 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009046 setlocale(LC_CTYPE, value);
9047}
9048
9049#endif
9050
Eric Andersen16767e22004-03-16 05:14:10 +00009051#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009052/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009053static void change_random(const char *value)
9054{
Eric Andersen16767e22004-03-16 05:14:10 +00009055 if(value == NULL) {
9056 /* "get", generate */
9057 char buf[16];
9058
9059 rseed = rseed * 1103515245 + 12345;
9060 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9061 /* set without recursion */
9062 setvar(vrandom.text, buf, VNOFUNC);
9063 vrandom.flags &= ~VNOFUNC;
9064 } else {
9065 /* set/reset */
9066 rseed = strtoul(value, (char **)NULL, 10);
9067 }
Eric Andersenef02f822004-03-11 13:34:24 +00009068}
Eric Andersen16767e22004-03-16 05:14:10 +00009069#endif
9070
Eric Andersenef02f822004-03-11 13:34:24 +00009071
Eric Andersend35c5df2002-01-09 15:37:36 +00009072#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009073static int
Eric Andersenc470f442003-07-28 09:56:35 +00009074getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009075{
9076 char *p, *q;
9077 char c = '?';
9078 int done = 0;
9079 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009080 char s[12];
9081 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009082
Eric Andersena48b0a32003-10-22 10:56:47 +00009083 if(*param_optind < 1)
9084 return 1;
9085 optnext = optfirst + *param_optind - 1;
9086
9087 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009088 p = NULL;
9089 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009090 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009091 if (p == NULL || *p == '\0') {
9092 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009093 p = *optnext;
9094 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009095atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009096 p = NULL;
9097 done = 1;
9098 goto out;
9099 }
9100 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009101 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009102 goto atend;
9103 }
9104
9105 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009106 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009107 if (*q == '\0') {
9108 if (optstr[0] == ':') {
9109 s[0] = c;
9110 s[1] = '\0';
9111 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009112 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009113 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009114 (void) unsetvar("OPTARG");
9115 }
9116 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009117 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009118 }
9119 if (*++q == ':')
9120 q++;
9121 }
9122
9123 if (*++q == ':') {
9124 if (*p == '\0' && (p = *optnext) == NULL) {
9125 if (optstr[0] == ':') {
9126 s[0] = c;
9127 s[1] = '\0';
9128 err |= setvarsafe("OPTARG", s, 0);
9129 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009130 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009131 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009132 (void) unsetvar("OPTARG");
9133 c = '?';
9134 }
Eric Andersenc470f442003-07-28 09:56:35 +00009135 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009136 }
9137
9138 if (p == *optnext)
9139 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009140 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009141 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009142 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009143 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009144
Eric Andersenc470f442003-07-28 09:56:35 +00009145out:
Eric Andersencb57d552001-06-28 07:25:16 +00009146 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009147 *param_optind = optnext - optfirst + 1;
9148 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009149 err |= setvarsafe("OPTIND", s, VNOFUNC);
9150 s[0] = c;
9151 s[1] = '\0';
9152 err |= setvarsafe(optvar, s, 0);
9153 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009154 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009155 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009156 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009157 exraise(EXERROR);
9158 }
9159 return done;
9160}
Eric Andersenc470f442003-07-28 09:56:35 +00009161
9162/*
9163 * The getopts builtin. Shellparam.optnext points to the next argument
9164 * to be processed. Shellparam.optptr points to the next character to
9165 * be processed in the current argument. If shellparam.optnext is NULL,
9166 * then it's the first time getopts has been called.
9167 */
9168
9169int
9170getoptscmd(int argc, char **argv)
9171{
9172 char **optbase;
9173
9174 if (argc < 3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009175 sh_error("Usage: getopts optstring var [arg]");
Eric Andersenc470f442003-07-28 09:56:35 +00009176 else if (argc == 3) {
9177 optbase = shellparam.p;
9178 if (shellparam.optind > shellparam.nparam + 1) {
9179 shellparam.optind = 1;
9180 shellparam.optoff = -1;
9181 }
9182 }
9183 else {
9184 optbase = &argv[3];
9185 if (shellparam.optind > argc - 2) {
9186 shellparam.optind = 1;
9187 shellparam.optoff = -1;
9188 }
9189 }
9190
9191 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9192 &shellparam.optoff);
9193}
9194#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009195
9196/*
9197 * XXX - should get rid of. have all builtins use getopt(3). the
9198 * library getopt must have the BSD extension static variable "optreset"
9199 * otherwise it can't be used within the shell safely.
9200 *
9201 * Standard option processing (a la getopt) for builtin routines. The
9202 * only argument that is passed to nextopt is the option string; the
9203 * other arguments are unnecessary. It return the character, or '\0' on
9204 * end of input.
9205 */
9206
Eric Andersenc470f442003-07-28 09:56:35 +00009207static int
9208nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009209{
Eric Andersencb57d552001-06-28 07:25:16 +00009210 char *p;
9211 const char *q;
9212 char c;
9213
9214 if ((p = optptr) == NULL || *p == '\0') {
9215 p = *argptr;
9216 if (p == NULL || *p != '-' || *++p == '\0')
9217 return '\0';
9218 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009219 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009220 return '\0';
9221 }
9222 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009223 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009224 if (*q == '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009225 sh_error("Illegal option -%c", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009226 if (*++q == ':')
9227 q++;
9228 }
9229 if (*++q == ':') {
9230 if (*p == '\0' && (p = *argptr++) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009231 sh_error("No arg for -%c option", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009232 optionarg = p;
9233 p = NULL;
9234 }
9235 optptr = p;
9236 return c;
9237}
9238
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009239
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009240/* output.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009241
Eric Andersenc470f442003-07-28 09:56:35 +00009242void
9243outstr(const char *p, FILE *file)
9244{
9245 INTOFF;
9246 fputs(p, file);
9247 INTON;
9248}
9249
9250void
9251flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009252{
Eric Andersencb57d552001-06-28 07:25:16 +00009253 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009254 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009255 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009256 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009257}
9258
Eric Andersenc470f442003-07-28 09:56:35 +00009259void
Eric Andersen16767e22004-03-16 05:14:10 +00009260flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009261{
9262 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009263 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009264 INTON;
9265}
9266
9267static void
9268outcslow(int c, FILE *dest)
9269{
9270 INTOFF;
9271 putc(c, dest);
9272 fflush(dest);
9273 INTON;
9274}
9275
9276
9277static int
9278out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009279{
9280 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009281 int r;
9282
9283 INTOFF;
9284 va_start(ap, fmt);
9285 r = vprintf(fmt, ap);
9286 va_end(ap);
9287 INTON;
9288 return r;
9289}
9290
9291
9292int
9293fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9294{
9295 va_list ap;
9296 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009297
Eric Andersencb57d552001-06-28 07:25:16 +00009298 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009299 INTOFF;
9300 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009301 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009302 INTON;
9303 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009304}
9305
Eric Andersenc470f442003-07-28 09:56:35 +00009306
Eric Andersencb57d552001-06-28 07:25:16 +00009307
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009308/* parser.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009309
9310
Eric Andersencb57d552001-06-28 07:25:16 +00009311/*
9312 * Shell command parser.
9313 */
9314
9315#define EOFMARKLEN 79
9316
9317
Eric Andersencb57d552001-06-28 07:25:16 +00009318struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009319 struct heredoc *next; /* next here document in list */
9320 union node *here; /* redirection node */
9321 char *eofmark; /* string indicating end of input */
9322 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009323};
9324
9325
9326
Eric Andersenc470f442003-07-28 09:56:35 +00009327static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009328
9329
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009330static union node *list(int);
9331static union node *andor(void);
9332static union node *pipeline(void);
9333static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009334static union node *simplecmd(void);
9335static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009336static void parsefname(void);
9337static void parseheredoc(void);
9338static char peektoken(void);
9339static int readtoken(void);
9340static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009341static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009342static int noexpand(char *);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00009343static void synexpect(int) ATTRIBUTE_NORETURN;
9344static void synerror(const char *) ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009345static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009346
9347
Eric Andersenc470f442003-07-28 09:56:35 +00009348
Eric Andersenc470f442003-07-28 09:56:35 +00009349
Eric Andersencb57d552001-06-28 07:25:16 +00009350/*
9351 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9352 * valid parse tree indicating a blank line.)
9353 */
9354
Eric Andersenc470f442003-07-28 09:56:35 +00009355union node *
9356parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009357{
9358 int t;
9359
9360 tokpushback = 0;
9361 doprompt = interact;
9362 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009363 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009364 needprompt = 0;
9365 t = readtoken();
9366 if (t == TEOF)
9367 return NEOF;
9368 if (t == TNL)
9369 return NULL;
9370 tokpushback++;
9371 return list(1);
9372}
9373
9374
Eric Andersenc470f442003-07-28 09:56:35 +00009375static union node *
9376list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009377{
9378 union node *n1, *n2, *n3;
9379 int tok;
9380
Eric Andersenc470f442003-07-28 09:56:35 +00009381 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9382 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009383 return NULL;
9384 n1 = NULL;
9385 for (;;) {
9386 n2 = andor();
9387 tok = readtoken();
9388 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009389 if (n2->type == NPIPE) {
9390 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009391 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009392 if (n2->type != NREDIR) {
9393 n3 = stalloc(sizeof(struct nredir));
9394 n3->nredir.n = n2;
9395 n3->nredir.redirect = NULL;
9396 n2 = n3;
9397 }
9398 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009399 }
9400 }
9401 if (n1 == NULL) {
9402 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009403 }
9404 else {
9405 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009406 n3->type = NSEMI;
9407 n3->nbinary.ch1 = n1;
9408 n3->nbinary.ch2 = n2;
9409 n1 = n3;
9410 }
9411 switch (tok) {
9412 case TBACKGND:
9413 case TSEMI:
9414 tok = readtoken();
9415 /* fall through */
9416 case TNL:
9417 if (tok == TNL) {
9418 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009419 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009420 return n1;
9421 } else {
9422 tokpushback++;
9423 }
Eric Andersenc470f442003-07-28 09:56:35 +00009424 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009425 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009426 return n1;
9427 break;
9428 case TEOF:
9429 if (heredoclist)
9430 parseheredoc();
9431 else
Eric Andersenc470f442003-07-28 09:56:35 +00009432 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009433 return n1;
9434 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009435 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009436 synexpect(-1);
9437 tokpushback++;
9438 return n1;
9439 }
9440 }
9441}
9442
9443
9444
Eric Andersenc470f442003-07-28 09:56:35 +00009445static union node *
9446andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009447{
Eric Andersencb57d552001-06-28 07:25:16 +00009448 union node *n1, *n2, *n3;
9449 int t;
9450
Eric Andersencb57d552001-06-28 07:25:16 +00009451 n1 = pipeline();
9452 for (;;) {
9453 if ((t = readtoken()) == TAND) {
9454 t = NAND;
9455 } else if (t == TOR) {
9456 t = NOR;
9457 } else {
9458 tokpushback++;
9459 return n1;
9460 }
Eric Andersenc470f442003-07-28 09:56:35 +00009461 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009462 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009463 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009464 n3->type = t;
9465 n3->nbinary.ch1 = n1;
9466 n3->nbinary.ch2 = n2;
9467 n1 = n3;
9468 }
9469}
9470
9471
9472
Eric Andersenc470f442003-07-28 09:56:35 +00009473static union node *
9474pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009475{
Eric Andersencb57d552001-06-28 07:25:16 +00009476 union node *n1, *n2, *pipenode;
9477 struct nodelist *lp, *prev;
9478 int negate;
9479
9480 negate = 0;
9481 TRACE(("pipeline: entered\n"));
9482 if (readtoken() == TNOT) {
9483 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009484 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009485 } else
9486 tokpushback++;
9487 n1 = command();
9488 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009489 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009490 pipenode->type = NPIPE;
9491 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009492 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009493 pipenode->npipe.cmdlist = lp;
9494 lp->n = n1;
9495 do {
9496 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009497 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9498 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009499 lp->n = command();
9500 prev->next = lp;
9501 } while (readtoken() == TPIPE);
9502 lp->next = NULL;
9503 n1 = pipenode;
9504 }
9505 tokpushback++;
9506 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009507 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009508 n2->type = NNOT;
9509 n2->nnot.com = n1;
9510 return n2;
9511 } else
9512 return n1;
9513}
9514
9515
9516
Eric Andersenc470f442003-07-28 09:56:35 +00009517static union node *
9518command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009519{
Eric Andersencb57d552001-06-28 07:25:16 +00009520 union node *n1, *n2;
9521 union node *ap, **app;
9522 union node *cp, **cpp;
9523 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009524 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009525 int t;
9526
9527 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009528 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009529
Eric Andersencb57d552001-06-28 07:25:16 +00009530 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009531 default:
9532 synexpect(-1);
9533 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009534 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009535 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009536 n1->type = NIF;
9537 n1->nif.test = list(0);
9538 if (readtoken() != TTHEN)
9539 synexpect(TTHEN);
9540 n1->nif.ifpart = list(0);
9541 n2 = n1;
9542 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009543 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009544 n2 = n2->nif.elsepart;
9545 n2->type = NIF;
9546 n2->nif.test = list(0);
9547 if (readtoken() != TTHEN)
9548 synexpect(TTHEN);
9549 n2->nif.ifpart = list(0);
9550 }
9551 if (lasttoken == TELSE)
9552 n2->nif.elsepart = list(0);
9553 else {
9554 n2->nif.elsepart = NULL;
9555 tokpushback++;
9556 }
Eric Andersenc470f442003-07-28 09:56:35 +00009557 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009558 break;
9559 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009560 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009561 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009562 n1 = (union node *)stalloc(sizeof (struct nbinary));
9563 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009564 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009565 if ((got=readtoken()) != TDO) {
9566TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009567 synexpect(TDO);
9568 }
9569 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009570 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009571 break;
9572 }
9573 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009574 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009575 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009576 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009577 n1->type = NFOR;
9578 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009579 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009580 if (readtoken() == TIN) {
9581 app = &ap;
9582 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009583 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009584 n2->type = NARG;
9585 n2->narg.text = wordtext;
9586 n2->narg.backquote = backquotelist;
9587 *app = n2;
9588 app = &n2->narg.next;
9589 }
9590 *app = NULL;
9591 n1->nfor.args = ap;
9592 if (lasttoken != TNL && lasttoken != TSEMI)
9593 synexpect(-1);
9594 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009595 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009596 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009597 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009598 n2->narg.backquote = NULL;
9599 n2->narg.next = NULL;
9600 n1->nfor.args = n2;
9601 /*
9602 * Newline or semicolon here is optional (but note
9603 * that the original Bourne shell only allowed NL).
9604 */
9605 if (lasttoken != TNL && lasttoken != TSEMI)
9606 tokpushback++;
9607 }
Eric Andersenc470f442003-07-28 09:56:35 +00009608 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009609 if (readtoken() != TDO)
9610 synexpect(TDO);
9611 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009612 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009613 break;
9614 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009615 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009616 n1->type = NCASE;
9617 if (readtoken() != TWORD)
9618 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009619 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009620 n2->type = NARG;
9621 n2->narg.text = wordtext;
9622 n2->narg.backquote = backquotelist;
9623 n2->narg.next = NULL;
9624 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009625 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009626 } while (readtoken() == TNL);
9627 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009628 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009629 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009630next_case:
9631 checkkwd = CHKNL | CHKKWD;
9632 t = readtoken();
9633 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009634 if (lasttoken == TLP)
9635 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009636 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009637 cp->type = NCLIST;
9638 app = &cp->nclist.pattern;
9639 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009640 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009641 ap->type = NARG;
9642 ap->narg.text = wordtext;
9643 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009644 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009645 break;
9646 app = &ap->narg.next;
9647 readtoken();
9648 }
9649 ap->narg.next = NULL;
9650 if (lasttoken != TRP)
9651 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009652 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009653
Eric Andersenc470f442003-07-28 09:56:35 +00009654 cpp = &cp->nclist.next;
9655
9656 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009657 if ((t = readtoken()) != TESAC) {
9658 if (t != TENDCASE)
9659 synexpect(TENDCASE);
9660 else
Eric Andersenc470f442003-07-28 09:56:35 +00009661 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009662 }
Eric Andersenc470f442003-07-28 09:56:35 +00009663 }
Eric Andersencb57d552001-06-28 07:25:16 +00009664 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009665 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009666 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009667 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009668 n1->type = NSUBSHELL;
9669 n1->nredir.n = list(0);
9670 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009671 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009672 break;
9673 case TBEGIN:
9674 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009675 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009676 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009677 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009678 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009679 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009680 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009681 }
9682
Eric Andersenc470f442003-07-28 09:56:35 +00009683 if (readtoken() != t)
9684 synexpect(t);
9685
9686redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009687 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009688 checkkwd = CHKKWD | CHKALIAS;
9689 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009690 while (readtoken() == TREDIR) {
9691 *rpp = n2 = redirnode;
9692 rpp = &n2->nfile.next;
9693 parsefname();
9694 }
9695 tokpushback++;
9696 *rpp = NULL;
9697 if (redir) {
9698 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009699 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009700 n2->type = NREDIR;
9701 n2->nredir.n = n1;
9702 n1 = n2;
9703 }
9704 n1->nredir.redirect = redir;
9705 }
9706
9707 return n1;
9708}
9709
9710
Eric Andersenc470f442003-07-28 09:56:35 +00009711static union node *
9712simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009713 union node *args, **app;
9714 union node *n = NULL;
9715 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009716 union node **rpp, *redir;
9717 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009718
9719 args = NULL;
9720 app = &args;
9721 vars = NULL;
9722 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009723 redir = NULL;
9724 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009725
Eric Andersenc470f442003-07-28 09:56:35 +00009726 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009727 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009728 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009729 switch (readtoken()) {
9730 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009731 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009732 n->type = NARG;
9733 n->narg.text = wordtext;
9734 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009735 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009736 *vpp = n;
9737 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009738 } else {
9739 *app = n;
9740 app = &n->narg.next;
9741 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009742 }
9743 break;
9744 case TREDIR:
9745 *rpp = n = redirnode;
9746 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009747 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009748 break;
9749 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009750 if (
9751 args && app == &args->narg.next &&
9752 !vars && !redir
9753 ) {
9754 struct builtincmd *bcmd;
9755 const char *name;
9756
Eric Andersencb57d552001-06-28 07:25:16 +00009757 /* We have a function */
9758 if (readtoken() != TRP)
9759 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009760 name = n->narg.text;
9761 if (
9762 !goodname(name) || (
9763 (bcmd = find_builtin(name)) &&
9764 IS_BUILTIN_SPECIAL(bcmd)
9765 )
9766 )
9767 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009768 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009769 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009770 n->narg.next = command();
9771 return n;
9772 }
9773 /* fall through */
9774 default:
9775 tokpushback++;
9776 goto out;
9777 }
9778 }
Eric Andersenc470f442003-07-28 09:56:35 +00009779out:
Eric Andersencb57d552001-06-28 07:25:16 +00009780 *app = NULL;
9781 *vpp = NULL;
9782 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009783 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009784 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009785 n->ncmd.args = args;
9786 n->ncmd.assign = vars;
9787 n->ncmd.redirect = redir;
9788 return n;
9789}
9790
Eric Andersenc470f442003-07-28 09:56:35 +00009791static union node *
9792makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009793{
Eric Andersencb57d552001-06-28 07:25:16 +00009794 union node *n;
9795
Eric Andersenc470f442003-07-28 09:56:35 +00009796 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009797 n->type = NARG;
9798 n->narg.next = NULL;
9799 n->narg.text = wordtext;
9800 n->narg.backquote = backquotelist;
9801 return n;
9802}
9803
Eric Andersenc470f442003-07-28 09:56:35 +00009804void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009805{
Eric Andersencb57d552001-06-28 07:25:16 +00009806 TRACE(("Fix redir %s %d\n", text, err));
9807 if (!err)
9808 n->ndup.vname = NULL;
9809
9810 if (is_digit(text[0]) && text[1] == '\0')
9811 n->ndup.dupfd = digit_val(text[0]);
9812 else if (text[0] == '-' && text[1] == '\0')
9813 n->ndup.dupfd = -1;
9814 else {
9815
9816 if (err)
9817 synerror("Bad fd number");
9818 else
9819 n->ndup.vname = makename();
9820 }
9821}
9822
9823
Eric Andersenc470f442003-07-28 09:56:35 +00009824static void
9825parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009826{
Eric Andersencb57d552001-06-28 07:25:16 +00009827 union node *n = redirnode;
9828
9829 if (readtoken() != TWORD)
9830 synexpect(-1);
9831 if (n->type == NHERE) {
9832 struct heredoc *here = heredoc;
9833 struct heredoc *p;
9834 int i;
9835
9836 if (quoteflag == 0)
9837 n->type = NXHERE;
9838 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009839 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009840 synerror("Illegal eof marker for << redirection");
9841 rmescapes(wordtext);
9842 here->eofmark = wordtext;
9843 here->next = NULL;
9844 if (heredoclist == NULL)
9845 heredoclist = here;
9846 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009847 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009848 p->next = here;
9849 }
9850 } else if (n->type == NTOFD || n->type == NFROMFD) {
9851 fixredir(n, wordtext, 0);
9852 } else {
9853 n->nfile.fname = makename();
9854 }
9855}
9856
9857
9858/*
9859 * Input any here documents.
9860 */
9861
Eric Andersenc470f442003-07-28 09:56:35 +00009862static void
9863parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009864{
Eric Andersencb57d552001-06-28 07:25:16 +00009865 struct heredoc *here;
9866 union node *n;
9867
Eric Andersenc470f442003-07-28 09:56:35 +00009868 here = heredoclist;
9869 heredoclist = 0;
9870
9871 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009872 if (needprompt) {
9873 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009874 }
Eric Andersenc470f442003-07-28 09:56:35 +00009875 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9876 here->eofmark, here->striptabs);
9877 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009878 n->narg.type = NARG;
9879 n->narg.next = NULL;
9880 n->narg.text = wordtext;
9881 n->narg.backquote = backquotelist;
9882 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009883 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009884 }
9885}
9886
Eric Andersenc470f442003-07-28 09:56:35 +00009887static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009888{
Eric Andersencb57d552001-06-28 07:25:16 +00009889 int t;
9890
9891 t = readtoken();
9892 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009893 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009894}
9895
Eric Andersenc470f442003-07-28 09:56:35 +00009896static int
9897readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009898{
Eric Andersencb57d552001-06-28 07:25:16 +00009899 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009900#ifdef DEBUG
9901 int alreadyseen = tokpushback;
9902#endif
9903
Eric Andersend35c5df2002-01-09 15:37:36 +00009904#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009905top:
Eric Andersen2870d962001-07-02 17:27:21 +00009906#endif
9907
Eric Andersencb57d552001-06-28 07:25:16 +00009908 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009909
Eric Andersenc470f442003-07-28 09:56:35 +00009910 /*
9911 * eat newlines
9912 */
9913 if (checkkwd & CHKNL) {
9914 while (t == TNL) {
9915 parseheredoc();
9916 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009917 }
9918 }
9919
Eric Andersenc470f442003-07-28 09:56:35 +00009920 if (t != TWORD || quoteflag) {
9921 goto out;
9922 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009923
Eric Andersenc470f442003-07-28 09:56:35 +00009924 /*
9925 * check for keywords
9926 */
9927 if (checkkwd & CHKKWD) {
9928 const char *const *pp;
9929
9930 if ((pp = findkwd(wordtext))) {
9931 lasttoken = t = pp - tokname_array;
9932 TRACE(("keyword %s recognized\n", tokname(t)));
9933 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009934 }
Eric Andersenc470f442003-07-28 09:56:35 +00009935 }
9936
9937 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009938#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009939 struct alias *ap;
9940 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009941 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009942 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009943 }
Eric Andersencb57d552001-06-28 07:25:16 +00009944 goto top;
9945 }
Eric Andersen2870d962001-07-02 17:27:21 +00009946#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009947 }
Eric Andersenc470f442003-07-28 09:56:35 +00009948out:
9949 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009950#ifdef DEBUG
9951 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009952 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009953 else
Eric Andersenc470f442003-07-28 09:56:35 +00009954 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009955#endif
9956 return (t);
9957}
9958
9959
9960/*
9961 * Read the next input token.
9962 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009963 * backquotes. We set quoteflag to true if any part of the word was
9964 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009965 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009966 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009967 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009968 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009969 *
9970 * [Change comment: here documents and internal procedures]
9971 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9972 * word parsing code into a separate routine. In this case, readtoken
9973 * doesn't need to have any internal procedures, but parseword does.
9974 * We could also make parseoperator in essence the main routine, and
9975 * have parseword (readtoken1?) handle both words and redirection.]
9976 */
9977
Eric Andersen81fe1232003-07-29 06:38:40 +00009978#define NEW_xxreadtoken
9979#ifdef NEW_xxreadtoken
9980
9981/* singles must be first! */
9982static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9983
9984static const char xxreadtoken_tokens[] = {
9985 TNL, TLP, TRP, /* only single occurrence allowed */
9986 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9987 TEOF, /* corresponds to trailing nul */
9988 TAND, TOR, TENDCASE, /* if double occurrence */
9989};
9990
9991#define xxreadtoken_doubles \
9992 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9993#define xxreadtoken_singles \
9994 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9995
9996static int xxreadtoken()
9997{
9998 int c;
9999
10000 if (tokpushback) {
10001 tokpushback = 0;
10002 return lasttoken;
10003 }
10004 if (needprompt) {
10005 setprompt(2);
Eric Andersen81fe1232003-07-29 06:38:40 +000010006 }
10007 startlinno = plinno;
10008 for (;;) { /* until token or start of word found */
10009 c = pgetc_macro();
10010
10011 if ((c != ' ') && (c != '\t')
10012#ifdef CONFIG_ASH_ALIAS
10013 && (c != PEOA)
10014#endif
10015 ) {
10016 if (c == '#') {
10017 while ((c = pgetc()) != '\n' && c != PEOF);
10018 pungetc();
10019 } else if (c == '\\') {
10020 if (pgetc() != '\n') {
10021 pungetc();
10022 goto READTOKEN1;
10023 }
10024 startlinno = ++plinno;
10025 if (doprompt)
10026 setprompt(2);
10027 } else {
10028 const char *p
10029 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10030
10031 if (c != PEOF) {
10032 if (c == '\n') {
10033 plinno++;
10034 needprompt = doprompt;
10035 }
10036
10037 p = strchr(xxreadtoken_chars, c);
10038 if (p == NULL) {
10039 READTOKEN1:
10040 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10041 }
10042
10043 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10044 if (pgetc() == *p) { /* double occurrence? */
10045 p += xxreadtoken_doubles + 1;
10046 } else {
10047 pungetc();
10048 }
10049 }
10050 }
10051
10052 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10053 }
10054 }
10055 }
10056}
10057
10058
10059#else
Eric Andersen2870d962001-07-02 17:27:21 +000010060#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010061
Eric Andersenc470f442003-07-28 09:56:35 +000010062static int
10063xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010064{
Eric Andersencb57d552001-06-28 07:25:16 +000010065 int c;
10066
10067 if (tokpushback) {
10068 tokpushback = 0;
10069 return lasttoken;
10070 }
10071 if (needprompt) {
10072 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010073 }
10074 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010075 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010076 c = pgetc_macro();
10077 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010078 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010079#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010080 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010081#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010082 continue;
10083 case '#':
10084 while ((c = pgetc()) != '\n' && c != PEOF);
10085 pungetc();
10086 continue;
10087 case '\\':
10088 if (pgetc() == '\n') {
10089 startlinno = ++plinno;
10090 if (doprompt)
10091 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010092 continue;
10093 }
10094 pungetc();
10095 goto breakloop;
10096 case '\n':
10097 plinno++;
10098 needprompt = doprompt;
10099 RETURN(TNL);
10100 case PEOF:
10101 RETURN(TEOF);
10102 case '&':
10103 if (pgetc() == '&')
10104 RETURN(TAND);
10105 pungetc();
10106 RETURN(TBACKGND);
10107 case '|':
10108 if (pgetc() == '|')
10109 RETURN(TOR);
10110 pungetc();
10111 RETURN(TPIPE);
10112 case ';':
10113 if (pgetc() == ';')
10114 RETURN(TENDCASE);
10115 pungetc();
10116 RETURN(TSEMI);
10117 case '(':
10118 RETURN(TLP);
10119 case ')':
10120 RETURN(TRP);
10121 default:
10122 goto breakloop;
10123 }
10124 }
Eric Andersenc470f442003-07-28 09:56:35 +000010125breakloop:
10126 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010127#undef RETURN
10128}
Eric Andersen81fe1232003-07-29 06:38:40 +000010129#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010130
Eric Andersencb57d552001-06-28 07:25:16 +000010131
Eric Andersencb57d552001-06-28 07:25:16 +000010132/*
10133 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10134 * is not NULL, read a here document. In the latter case, eofmark is the
10135 * word which marks the end of the document and striptabs is true if
10136 * leading tabs should be stripped from the document. The argument firstc
10137 * is the first character of the input token or document.
10138 *
10139 * Because C does not have internal subroutines, I have simulated them
10140 * using goto's to implement the subroutine linkage. The following macros
10141 * will run code that appears at the end of readtoken1.
10142 */
10143
Eric Andersen2870d962001-07-02 17:27:21 +000010144#define CHECKEND() {goto checkend; checkend_return:;}
10145#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10146#define PARSESUB() {goto parsesub; parsesub_return:;}
10147#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10148#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10149#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010150
10151static int
Eric Andersenc470f442003-07-28 09:56:35 +000010152readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010153{
Eric Andersencb57d552001-06-28 07:25:16 +000010154 int c = firstc;
10155 char *out;
10156 int len;
10157 char line[EOFMARKLEN + 1];
Eric Andersena68ea1c2006-01-30 22:48:39 +000010158 struct nodelist *bqlist = 0;
10159 int quotef = 0;
10160 int dblquote = 0;
10161 int varnest = 0; /* levels of variables expansion */
10162 int arinest = 0; /* levels of arithmetic expansion */
10163 int parenlevel = 0; /* levels of parens in arithmetic */
10164 int dqvarnest = 0; /* levels of variables expansion within double quotes */
10165 int oldstyle = 0;
10166 int prevsyntax = 0; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010167#if __GNUC__
10168 /* Avoid longjmp clobbering */
10169 (void) &out;
10170 (void) &quotef;
10171 (void) &dblquote;
10172 (void) &varnest;
10173 (void) &arinest;
10174 (void) &parenlevel;
10175 (void) &dqvarnest;
10176 (void) &oldstyle;
10177 (void) &prevsyntax;
10178 (void) &syntax;
10179#endif
10180
10181 startlinno = plinno;
10182 dblquote = 0;
10183 if (syntax == DQSYNTAX)
10184 dblquote = 1;
10185 quotef = 0;
10186 bqlist = NULL;
10187 varnest = 0;
10188 arinest = 0;
10189 parenlevel = 0;
10190 dqvarnest = 0;
10191
10192 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010193 loop: { /* for each line, until end of word */
10194 CHECKEND(); /* set c to PEOF if at end of here document */
10195 for (;;) { /* until end of line or end of word */
10196 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10197 switch(SIT(c, syntax)) {
10198 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010199 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010200 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010201 USTPUTC(c, out);
10202 plinno++;
10203 if (doprompt)
10204 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010205 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010206 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010207 case CWORD:
10208 USTPUTC(c, out);
10209 break;
10210 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010211 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010212 USTPUTC(CTLESC, out);
10213 USTPUTC(c, out);
10214 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010215 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010216 c = pgetc2();
10217 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010218 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010219 USTPUTC('\\', out);
10220 pungetc();
10221 } else if (c == '\n') {
10222 if (doprompt)
10223 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010224 } else {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010225 if (dblquote &&
Eric Andersenc470f442003-07-28 09:56:35 +000010226 c != '\\' && c != '`' &&
10227 c != '$' && (
10228 c != '"' ||
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010229 eofmark != NULL)
Eric Andersenc470f442003-07-28 09:56:35 +000010230 ) {
10231 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010232 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010233 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010234 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010235 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010236 USTPUTC(c, out);
10237 quotef++;
10238 }
10239 break;
10240 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010241 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010242quotemark:
10243 if (eofmark == NULL) {
10244 USTPUTC(CTLQUOTEMARK, out);
10245 }
Eric Andersencb57d552001-06-28 07:25:16 +000010246 break;
10247 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010248 syntax = DQSYNTAX;
10249 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010250 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010251 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010252 if (eofmark != NULL && arinest == 0 &&
10253 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010254 USTPUTC(c, out);
10255 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010256 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010257 syntax = BASESYNTAX;
10258 dblquote = 0;
10259 }
10260 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010261 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010262 }
10263 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010264 case CVAR: /* '$' */
10265 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010266 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010267 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010268 if (varnest > 0) {
10269 varnest--;
10270 if (dqvarnest > 0) {
10271 dqvarnest--;
10272 }
10273 USTPUTC(CTLENDVAR, out);
10274 } else {
10275 USTPUTC(c, out);
10276 }
10277 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010278#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010279 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010280 parenlevel++;
10281 USTPUTC(c, out);
10282 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010283 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010284 if (parenlevel > 0) {
10285 USTPUTC(c, out);
10286 --parenlevel;
10287 } else {
10288 if (pgetc() == ')') {
10289 if (--arinest == 0) {
10290 USTPUTC(CTLENDARI, out);
10291 syntax = prevsyntax;
10292 if (syntax == DQSYNTAX)
10293 dblquote = 1;
10294 else
10295 dblquote = 0;
10296 } else
10297 USTPUTC(')', out);
10298 } else {
10299 /*
10300 * unbalanced parens
10301 * (don't 2nd guess - no error)
10302 */
10303 pungetc();
10304 USTPUTC(')', out);
10305 }
10306 }
10307 break;
10308#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010309 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010310 PARSEBACKQOLD();
10311 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010312 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010313 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010314 case CIGN:
10315 break;
10316 default:
10317 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010318 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010319#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010320 if (c != PEOA)
10321#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010322 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010323
Eric Andersencb57d552001-06-28 07:25:16 +000010324 }
10325 c = pgetc_macro();
10326 }
10327 }
Eric Andersenc470f442003-07-28 09:56:35 +000010328endword:
10329#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010330 if (syntax == ARISYNTAX)
10331 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010332#endif
10333 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010334 synerror("Unterminated quoted string");
10335 if (varnest != 0) {
10336 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010337 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010338 synerror("Missing '}'");
10339 }
10340 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010341 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010342 out = stackblock();
10343 if (eofmark == NULL) {
10344 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010345 && quotef == 0
10346 && len <= 2
10347 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010348 PARSEREDIR();
10349 return lasttoken = TREDIR;
10350 } else {
10351 pungetc();
10352 }
10353 }
10354 quoteflag = quotef;
10355 backquotelist = bqlist;
10356 grabstackblock(len);
10357 wordtext = out;
10358 return lasttoken = TWORD;
10359/* end of readtoken routine */
10360
10361
10362
10363/*
10364 * Check to see whether we are at the end of the here document. When this
10365 * is called, c is set to the first character of the next input line. If
10366 * we are at the end of the here document, this routine sets the c to PEOF.
10367 */
10368
Eric Andersenc470f442003-07-28 09:56:35 +000010369checkend: {
10370 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010371#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010372 if (c == PEOA) {
10373 c = pgetc2();
10374 }
10375#endif
10376 if (striptabs) {
10377 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010378 c = pgetc2();
10379 }
Eric Andersenc470f442003-07-28 09:56:35 +000010380 }
10381 if (c == *eofmark) {
10382 if (pfgets(line, sizeof line) != NULL) {
10383 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010384
Eric Andersenc470f442003-07-28 09:56:35 +000010385 p = line;
10386 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10387 if (*p == '\n' && *q == '\0') {
10388 c = PEOF;
10389 plinno++;
10390 needprompt = doprompt;
10391 } else {
10392 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010393 }
10394 }
10395 }
10396 }
Eric Andersenc470f442003-07-28 09:56:35 +000010397 goto checkend_return;
10398}
Eric Andersencb57d552001-06-28 07:25:16 +000010399
10400
10401/*
10402 * Parse a redirection operator. The variable "out" points to a string
10403 * specifying the fd to be redirected. The variable "c" contains the
10404 * first character of the redirection operator.
10405 */
10406
Eric Andersenc470f442003-07-28 09:56:35 +000010407parseredir: {
10408 char fd = *out;
10409 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010410
Eric Andersenc470f442003-07-28 09:56:35 +000010411 np = (union node *)stalloc(sizeof (struct nfile));
10412 if (c == '>') {
10413 np->nfile.fd = 1;
10414 c = pgetc();
10415 if (c == '>')
10416 np->type = NAPPEND;
10417 else if (c == '|')
10418 np->type = NCLOBBER;
10419 else if (c == '&')
10420 np->type = NTOFD;
10421 else {
10422 np->type = NTO;
10423 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010424 }
Eric Andersenc470f442003-07-28 09:56:35 +000010425 } else { /* c == '<' */
10426 np->nfile.fd = 0;
10427 switch (c = pgetc()) {
10428 case '<':
10429 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10430 np = (union node *)stalloc(sizeof (struct nhere));
10431 np->nfile.fd = 0;
10432 }
10433 np->type = NHERE;
10434 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10435 heredoc->here = np;
10436 if ((c = pgetc()) == '-') {
10437 heredoc->striptabs = 1;
10438 } else {
10439 heredoc->striptabs = 0;
10440 pungetc();
10441 }
10442 break;
10443
10444 case '&':
10445 np->type = NFROMFD;
10446 break;
10447
10448 case '>':
10449 np->type = NFROMTO;
10450 break;
10451
10452 default:
10453 np->type = NFROM;
10454 pungetc();
10455 break;
10456 }
Eric Andersencb57d552001-06-28 07:25:16 +000010457 }
Eric Andersenc470f442003-07-28 09:56:35 +000010458 if (fd != '\0')
10459 np->nfile.fd = digit_val(fd);
10460 redirnode = np;
10461 goto parseredir_return;
10462}
Eric Andersencb57d552001-06-28 07:25:16 +000010463
10464
10465/*
10466 * Parse a substitution. At this point, we have read the dollar sign
10467 * and nothing else.
10468 */
10469
Eric Andersenc470f442003-07-28 09:56:35 +000010470parsesub: {
10471 int subtype;
10472 int typeloc;
10473 int flags;
10474 char *p;
10475 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010476
Eric Andersenc470f442003-07-28 09:56:35 +000010477 c = pgetc();
10478 if (
10479 c <= PEOA_OR_PEOF ||
10480 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10481 ) {
10482 USTPUTC('$', out);
10483 pungetc();
10484 } else if (c == '(') { /* $(command) or $((arith)) */
10485 if (pgetc() == '(') {
10486#ifdef CONFIG_ASH_MATH_SUPPORT
10487 PARSEARITH();
10488#else
10489 synerror("We unsupport $((arith))");
10490#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010491 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010492 pungetc();
10493 PARSEBACKQNEW();
10494 }
10495 } else {
10496 USTPUTC(CTLVAR, out);
10497 typeloc = out - (char *)stackblock();
10498 USTPUTC(VSNORMAL, out);
10499 subtype = VSNORMAL;
10500 if (c == '{') {
10501 c = pgetc();
10502 if (c == '#') {
10503 if ((c = pgetc()) == '}')
10504 c = '#';
10505 else
10506 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010507 }
Eric Andersenc470f442003-07-28 09:56:35 +000010508 else
10509 subtype = 0;
10510 }
10511 if (c > PEOA_OR_PEOF && is_name(c)) {
10512 do {
10513 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010514 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010515 } while (c > PEOA_OR_PEOF && is_in_name(c));
10516 } else if (is_digit(c)) {
10517 do {
10518 STPUTC(c, out);
10519 c = pgetc();
10520 } while (is_digit(c));
10521 }
10522 else if (is_special(c)) {
10523 USTPUTC(c, out);
10524 c = pgetc();
10525 }
10526 else
10527badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010528
Eric Andersenc470f442003-07-28 09:56:35 +000010529 STPUTC('=', out);
10530 flags = 0;
10531 if (subtype == 0) {
10532 switch (c) {
10533 case ':':
10534 flags = VSNUL;
10535 c = pgetc();
10536 /*FALLTHROUGH*/
10537 default:
10538 p = strchr(types, c);
10539 if (p == NULL)
10540 goto badsub;
10541 subtype = p - types + VSNORMAL;
10542 break;
10543 case '%':
10544 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010545 {
10546 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010547 subtype = c == '#' ? VSTRIMLEFT :
10548 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010549 c = pgetc();
10550 if (c == cc)
10551 subtype++;
10552 else
10553 pungetc();
10554 break;
10555 }
10556 }
Eric Andersenc470f442003-07-28 09:56:35 +000010557 } else {
10558 pungetc();
10559 }
10560 if (dblquote || arinest)
10561 flags |= VSQUOTE;
10562 *((char *)stackblock() + typeloc) = subtype | flags;
10563 if (subtype != VSNORMAL) {
10564 varnest++;
10565 if (dblquote || arinest) {
10566 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010567 }
10568 }
10569 }
Eric Andersenc470f442003-07-28 09:56:35 +000010570 goto parsesub_return;
10571}
Eric Andersencb57d552001-06-28 07:25:16 +000010572
10573
10574/*
10575 * Called to parse command substitutions. Newstyle is set if the command
10576 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10577 * list of commands (passed by reference), and savelen is the number of
10578 * characters on the top of the stack which must be preserved.
10579 */
10580
Eric Andersenc470f442003-07-28 09:56:35 +000010581parsebackq: {
10582 struct nodelist **nlpp;
10583 int savepbq;
10584 union node *n;
10585 char *volatile str;
10586 struct jmploc jmploc;
10587 struct jmploc *volatile savehandler;
10588 size_t savelen;
Eric Andersena68ea1c2006-01-30 22:48:39 +000010589 int saveprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010590#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010591 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010592#endif
10593
Eric Andersenc470f442003-07-28 09:56:35 +000010594 savepbq = parsebackquote;
10595 if (setjmp(jmploc.loc)) {
10596 if (str)
10597 ckfree(str);
10598 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010599 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010600 longjmp(handler->loc, 1);
10601 }
10602 INTOFF;
10603 str = NULL;
10604 savelen = out - (char *)stackblock();
10605 if (savelen > 0) {
10606 str = ckmalloc(savelen);
10607 memcpy(str, stackblock(), savelen);
10608 }
10609 savehandler = handler;
10610 handler = &jmploc;
10611 INTON;
10612 if (oldstyle) {
10613 /* We must read until the closing backquote, giving special
10614 treatment to some slashes, and then push the string and
10615 reread it as input, interpreting it normally. */
10616 char *pout;
10617 int pc;
10618 size_t psavelen;
10619 char *pstr;
10620
10621
10622 STARTSTACKSTR(pout);
10623 for (;;) {
10624 if (needprompt) {
10625 setprompt(2);
Eric Andersenc470f442003-07-28 09:56:35 +000010626 }
10627 switch (pc = pgetc()) {
10628 case '`':
10629 goto done;
10630
10631 case '\\':
10632 if ((pc = pgetc()) == '\n') {
10633 plinno++;
10634 if (doprompt)
10635 setprompt(2);
10636 /*
10637 * If eating a newline, avoid putting
10638 * the newline into the new character
10639 * stream (via the STPUTC after the
10640 * switch).
10641 */
10642 continue;
10643 }
10644 if (pc != '\\' && pc != '`' && pc != '$'
10645 && (!dblquote || pc != '"'))
10646 STPUTC('\\', pout);
10647 if (pc > PEOA_OR_PEOF) {
10648 break;
10649 }
10650 /* fall through */
10651
10652 case PEOF:
10653#ifdef CONFIG_ASH_ALIAS
10654 case PEOA:
10655#endif
10656 startlinno = plinno;
10657 synerror("EOF in backquote substitution");
10658
10659 case '\n':
10660 plinno++;
10661 needprompt = doprompt;
10662 break;
10663
10664 default:
10665 break;
10666 }
10667 STPUTC(pc, pout);
10668 }
10669done:
10670 STPUTC('\0', pout);
10671 psavelen = pout - (char *)stackblock();
10672 if (psavelen > 0) {
10673 pstr = grabstackstr(pout);
10674 setinputstring(pstr);
10675 }
10676 }
10677 nlpp = &bqlist;
10678 while (*nlpp)
10679 nlpp = &(*nlpp)->next;
10680 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10681 (*nlpp)->next = NULL;
10682 parsebackquote = oldstyle;
10683
10684 if (oldstyle) {
10685 saveprompt = doprompt;
10686 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010687 }
10688
Eric Andersenc470f442003-07-28 09:56:35 +000010689 n = list(2);
10690
10691 if (oldstyle)
10692 doprompt = saveprompt;
10693 else {
10694 if (readtoken() != TRP)
10695 synexpect(TRP);
10696 }
10697
10698 (*nlpp)->n = n;
10699 if (oldstyle) {
10700 /*
10701 * Start reading from old file again, ignoring any pushed back
10702 * tokens left from the backquote parsing
10703 */
10704 popfile();
10705 tokpushback = 0;
10706 }
10707 while (stackblocksize() <= savelen)
10708 growstackblock();
10709 STARTSTACKSTR(out);
10710 if (str) {
10711 memcpy(out, str, savelen);
10712 STADJUST(savelen, out);
10713 INTOFF;
10714 ckfree(str);
10715 str = NULL;
10716 INTON;
10717 }
10718 parsebackquote = savepbq;
10719 handler = savehandler;
10720 if (arinest || dblquote)
10721 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10722 else
10723 USTPUTC(CTLBACKQ, out);
10724 if (oldstyle)
10725 goto parsebackq_oldreturn;
10726 else
10727 goto parsebackq_newreturn;
10728}
10729
10730#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010731/*
10732 * Parse an arithmetic expansion (indicate start of one and set state)
10733 */
Eric Andersenc470f442003-07-28 09:56:35 +000010734parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010735
Eric Andersenc470f442003-07-28 09:56:35 +000010736 if (++arinest == 1) {
10737 prevsyntax = syntax;
10738 syntax = ARISYNTAX;
10739 USTPUTC(CTLARI, out);
10740 if (dblquote)
10741 USTPUTC('"',out);
10742 else
10743 USTPUTC(' ',out);
10744 } else {
10745 /*
10746 * we collapse embedded arithmetic expansion to
10747 * parenthesis, which should be equivalent
10748 */
10749 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010750 }
Eric Andersenc470f442003-07-28 09:56:35 +000010751 goto parsearith_return;
10752}
10753#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010754
Eric Andersenc470f442003-07-28 09:56:35 +000010755} /* end of readtoken */
10756
Eric Andersencb57d552001-06-28 07:25:16 +000010757
10758
Eric Andersencb57d552001-06-28 07:25:16 +000010759/*
10760 * Returns true if the text contains nothing to expand (no dollar signs
10761 * or backquotes).
10762 */
10763
Eric Andersenc470f442003-07-28 09:56:35 +000010764static int
10765noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010766{
Eric Andersencb57d552001-06-28 07:25:16 +000010767 char *p;
10768 char c;
10769
10770 p = text;
10771 while ((c = *p++) != '\0') {
10772 if (c == CTLQUOTEMARK)
10773 continue;
10774 if (c == CTLESC)
10775 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010776 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010777 return 0;
10778 }
10779 return 1;
10780}
10781
10782
10783/*
Eric Andersenc470f442003-07-28 09:56:35 +000010784 * Return of a legal variable name (a letter or underscore followed by zero or
10785 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010786 */
10787
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010788static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010789endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010790{
Eric Andersenc470f442003-07-28 09:56:35 +000010791 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010792
Eric Andersenc470f442003-07-28 09:56:35 +000010793 p = (char *) name;
10794 if (! is_name(*p))
10795 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010796 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010797 if (! is_in_name(*p))
10798 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010799 }
Eric Andersenc470f442003-07-28 09:56:35 +000010800 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010801}
10802
10803
10804/*
10805 * Called when an unexpected token is read during the parse. The argument
10806 * is the token that is expected, or -1 if more than one type of token can
10807 * occur at this point.
10808 */
10809
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010810static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010811{
10812 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010813 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010814
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010815 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10816 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010817 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010818 synerror(msg);
10819 /* NOTREACHED */
10820}
10821
Eric Andersenc470f442003-07-28 09:56:35 +000010822static void
10823synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010824{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010825 sh_error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010826 /* NOTREACHED */
10827}
10828
Eric Andersencb57d552001-06-28 07:25:16 +000010829
10830/*
10831 * called by editline -- any expansions to the prompt
10832 * should be added here.
10833 */
Eric Andersenc470f442003-07-28 09:56:35 +000010834
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010835#ifdef CONFIG_ASH_EXPAND_PRMT
10836static const char *
10837expandstr(const char *ps)
10838{
10839 union node n;
10840
10841 /* XXX Fix (char *) cast. */
10842 setinputstring((char *)ps);
10843 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10844 popfile();
10845
10846 n.narg.type = NARG;
10847 n.narg.next = NULL;
10848 n.narg.text = wordtext;
10849 n.narg.backquote = backquotelist;
10850
10851 expandarg(&n, NULL, 0);
10852 return stackblock();
10853}
10854#endif
10855
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010856static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010857{
Eric Andersenc470f442003-07-28 09:56:35 +000010858 const char *prompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010859#ifdef CONFIG_ASH_EXPAND_PRMT
10860 struct stackmark smark;
10861#endif
10862
10863 needprompt = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010864
10865 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010866 case 1:
10867 prompt = ps1val();
10868 break;
10869 case 2:
10870 prompt = ps2val();
10871 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010872 default: /* 0 */
10873 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010874 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010875#ifdef CONFIG_ASH_EXPAND_PRMT
10876 setstackmark(&smark);
10877 stalloc(stackblocksize());
10878#endif
10879 putprompt(expandstr(prompt));
10880#ifdef CONFIG_ASH_EXPAND_PRMT
10881 popstackmark(&smark);
10882#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010883}
10884
Eric Andersencb57d552001-06-28 07:25:16 +000010885
Eric Andersenc470f442003-07-28 09:56:35 +000010886static const char *const *findkwd(const char *s)
10887{
10888 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010889 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010890 sizeof(const char *), pstrcmp);
10891}
10892
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010893/* redir.c */
Eric Andersenc470f442003-07-28 09:56:35 +000010894
Eric Andersencb57d552001-06-28 07:25:16 +000010895/*
10896 * Code for dealing with input/output redirection.
10897 */
10898
Eric Andersenc470f442003-07-28 09:56:35 +000010899#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010900#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010901# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010902#else
10903# define PIPESIZE PIPE_BUF
10904#endif
10905
Eric Andersen62483552001-07-10 06:09:16 +000010906/*
10907 * Open a file in noclobber mode.
10908 * The code was copied from bash.
10909 */
Eric Andersenc470f442003-07-28 09:56:35 +000010910static inline int
10911noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010912{
10913 int r, fd;
10914 struct stat finfo, finfo2;
10915
10916 /*
10917 * If the file exists and is a regular file, return an error
10918 * immediately.
10919 */
10920 r = stat(fname, &finfo);
10921 if (r == 0 && S_ISREG(finfo.st_mode)) {
10922 errno = EEXIST;
10923 return -1;
10924 }
10925
10926 /*
10927 * If the file was not present (r != 0), make sure we open it
10928 * exclusively so that if it is created before we open it, our open
10929 * will fail. Make sure that we do not truncate an existing file.
10930 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10931 * file was not a regular file, we leave O_EXCL off.
10932 */
10933 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010934 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10935 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010936
10937 /* If the open failed, return the file descriptor right away. */
10938 if (fd < 0)
10939 return fd;
10940
10941 /*
10942 * OK, the open succeeded, but the file may have been changed from a
10943 * non-regular file to a regular file between the stat and the open.
10944 * We are assuming that the O_EXCL open handles the case where FILENAME
10945 * did not exist and is symlinked to an existing file between the stat
10946 * and open.
10947 */
10948
10949 /*
10950 * If we can open it and fstat the file descriptor, and neither check
10951 * revealed that it was a regular file, and the file has not been
10952 * replaced, return the file descriptor.
10953 */
Eric Andersenc470f442003-07-28 09:56:35 +000010954 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10955 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010956 return fd;
10957
10958 /* The file has been replaced. badness. */
10959 close(fd);
10960 errno = EEXIST;
10961 return -1;
10962}
Eric Andersencb57d552001-06-28 07:25:16 +000010963
10964/*
Eric Andersen62483552001-07-10 06:09:16 +000010965 * Handle here documents. Normally we fork off a process to write the
10966 * data to a pipe. If the document is short, we can stuff the data in
10967 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010968 */
10969
Eric Andersenc470f442003-07-28 09:56:35 +000010970static inline int
10971openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010972{
10973 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010974 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010975
Eric Andersen62483552001-07-10 06:09:16 +000010976 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010977 sh_error("Pipe call failed");
Eric Andersen62483552001-07-10 06:09:16 +000010978 if (redir->type == NHERE) {
10979 len = strlen(redir->nhere.doc->narg.text);
10980 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010981 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010982 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010983 }
Eric Andersencb57d552001-06-28 07:25:16 +000010984 }
Eric Andersenc470f442003-07-28 09:56:35 +000010985 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010986 close(pip[0]);
10987 signal(SIGINT, SIG_IGN);
10988 signal(SIGQUIT, SIG_IGN);
10989 signal(SIGHUP, SIG_IGN);
10990#ifdef SIGTSTP
10991 signal(SIGTSTP, SIG_IGN);
10992#endif
10993 signal(SIGPIPE, SIG_DFL);
10994 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000010995 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010996 else
10997 expandhere(redir->nhere.doc, pip[1]);
10998 _exit(0);
10999 }
Eric Andersenc470f442003-07-28 09:56:35 +000011000out:
Eric Andersen62483552001-07-10 06:09:16 +000011001 close(pip[1]);
11002 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011003}
11004
Eric Andersenc470f442003-07-28 09:56:35 +000011005static int
11006openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011007{
Eric Andersencb57d552001-06-28 07:25:16 +000011008 char *fname;
11009 int f;
11010
11011 switch (redir->nfile.type) {
11012 case NFROM:
11013 fname = redir->nfile.expfname;
11014 if ((f = open(fname, O_RDONLY)) < 0)
11015 goto eopen;
11016 break;
11017 case NFROMTO:
11018 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011019 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011020 goto ecreate;
11021 break;
11022 case NTO:
11023 /* Take care of noclobber mode. */
11024 if (Cflag) {
11025 fname = redir->nfile.expfname;
11026 if ((f = noclobberopen(fname)) < 0)
11027 goto ecreate;
11028 break;
11029 }
Eric Andersenc470f442003-07-28 09:56:35 +000011030 /* FALLTHROUGH */
11031 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011032 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011033 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011034 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011035 break;
11036 case NAPPEND:
11037 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011038 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011039 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011040 break;
11041 default:
11042#ifdef DEBUG
11043 abort();
11044#endif
11045 /* Fall through to eliminate warning. */
11046 case NTOFD:
11047 case NFROMFD:
11048 f = -1;
11049 break;
11050 case NHERE:
11051 case NXHERE:
11052 f = openhere(redir);
11053 break;
11054 }
11055
11056 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011057ecreate:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011058 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011059eopen:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011060 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
Eric Andersencb57d552001-06-28 07:25:16 +000011061}
11062
Eric Andersenc470f442003-07-28 09:56:35 +000011063static inline void
11064dupredirect(union node *redir, int f)
11065{
11066 int fd = redir->nfile.fd;
11067
11068 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11069 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11070 copyfd(redir->ndup.dupfd, fd);
11071 }
11072 return;
11073 }
11074
11075 if (f != fd) {
11076 copyfd(f, fd);
11077 close(f);
11078 }
11079 return;
11080}
Eric Andersencb57d552001-06-28 07:25:16 +000011081
Eric Andersen62483552001-07-10 06:09:16 +000011082/*
11083 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11084 * old file descriptors are stashed away so that the redirection can be
11085 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11086 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011087 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011088 */
11089
Eric Andersenc470f442003-07-28 09:56:35 +000011090static void
11091redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011092{
11093 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011094 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011095 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011096 int fd;
11097 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011098 int *p;
11099 nullredirs++;
11100 if (!redir) {
11101 return;
Eric Andersen62483552001-07-10 06:09:16 +000011102 }
Eric Andersenc470f442003-07-28 09:56:35 +000011103 sv = NULL;
11104 INTOFF;
11105 if (flags & REDIR_PUSH) {
11106 struct redirtab *q;
11107 q = ckmalloc(sizeof (struct redirtab));
11108 q->next = redirlist;
11109 redirlist = q;
11110 q->nullredirs = nullredirs - 1;
11111 for (i = 0 ; i < 10 ; i++)
11112 q->renamed[i] = EMPTY;
11113 nullredirs = 0;
11114 sv = q;
11115 }
11116 n = redir;
11117 do {
Eric Andersen62483552001-07-10 06:09:16 +000011118 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011119 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011120 n->ndup.dupfd == fd)
11121 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011122
Eric Andersen62483552001-07-10 06:09:16 +000011123 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011124 if (fd == newfd)
11125 continue;
11126 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11127 i = fcntl(fd, F_DUPFD, 10);
11128
11129 if (i == -1) {
11130 i = errno;
11131 if (i != EBADF) {
11132 close(newfd);
11133 errno = i;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011134 sh_error("%d: %m", fd);
Eric Andersen62483552001-07-10 06:09:16 +000011135 /* NOTREACHED */
11136 }
Eric Andersenc470f442003-07-28 09:56:35 +000011137 } else {
11138 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011139 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011140 }
Eric Andersenc470f442003-07-28 09:56:35 +000011141 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011142 close(fd);
11143 }
Eric Andersenc470f442003-07-28 09:56:35 +000011144 dupredirect(n, newfd);
11145 } while ((n = n->nfile.next));
11146 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011147 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11148 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011149}
11150
11151
Eric Andersencb57d552001-06-28 07:25:16 +000011152/*
11153 * Undo the effects of the last redirection.
11154 */
11155
Eric Andersenc470f442003-07-28 09:56:35 +000011156void
11157popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011158{
Eric Andersenc470f442003-07-28 09:56:35 +000011159 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011160 int i;
11161
Eric Andersenc470f442003-07-28 09:56:35 +000011162 if (--nullredirs >= 0)
11163 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011164 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011165 rp = redirlist;
11166 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011167 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011168 if (!drop) {
11169 close(i);
11170 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011171 }
Eric Andersenc470f442003-07-28 09:56:35 +000011172 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011173 }
11174 }
11175 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011176 nullredirs = rp->nullredirs;
11177 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011178 INTON;
11179}
11180
11181/*
Eric Andersenc470f442003-07-28 09:56:35 +000011182 * Undo all redirections. Called on error or interrupt.
11183 */
11184
11185/*
Eric Andersencb57d552001-06-28 07:25:16 +000011186 * Discard all saved file descriptors.
11187 */
11188
Eric Andersenc470f442003-07-28 09:56:35 +000011189void
11190clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011191{
Eric Andersenc470f442003-07-28 09:56:35 +000011192 for (;;) {
11193 nullredirs = 0;
11194 if (!redirlist)
11195 break;
11196 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011197 }
Eric Andersencb57d552001-06-28 07:25:16 +000011198}
11199
11200
Eric Andersencb57d552001-06-28 07:25:16 +000011201/*
11202 * Copy a file descriptor to be >= to. Returns -1
11203 * if the source file descriptor is closed, EMPTY if there are no unused
11204 * file descriptors left.
11205 */
11206
Eric Andersenc470f442003-07-28 09:56:35 +000011207int
11208copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011209{
11210 int newfd;
11211
11212 newfd = fcntl(from, F_DUPFD, to);
11213 if (newfd < 0) {
11214 if (errno == EMFILE)
11215 return EMPTY;
11216 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011217 sh_error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011218 }
11219 return newfd;
11220}
11221
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011222
Eric Andersenc470f442003-07-28 09:56:35 +000011223int
11224redirectsafe(union node *redir, int flags)
11225{
11226 int err;
11227 volatile int saveint;
11228 struct jmploc *volatile savehandler = handler;
11229 struct jmploc jmploc;
11230
11231 SAVEINT(saveint);
11232 if (!(err = setjmp(jmploc.loc) * 2)) {
11233 handler = &jmploc;
11234 redirect(redir, flags);
11235 }
11236 handler = savehandler;
11237 if (err && exception != EXERROR)
11238 longjmp(handler->loc, 1);
11239 RESTOREINT(saveint);
11240 return err;
11241}
11242
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011243/* show.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011244
11245#ifdef DEBUG
11246static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011247static void shcmd(union node *, FILE *);
11248static void sharg(union node *, FILE *);
11249static void indent(int, char *, FILE *);
11250static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011251
11252
Eric Andersenc470f442003-07-28 09:56:35 +000011253void
11254showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011255{
11256 trputs("showtree called\n");
11257 shtree(n, 1, NULL, stdout);
11258}
Eric Andersencb57d552001-06-28 07:25:16 +000011259
Eric Andersenc470f442003-07-28 09:56:35 +000011260
11261static void
11262shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011263{
11264 struct nodelist *lp;
11265 const char *s;
11266
11267 if (n == NULL)
11268 return;
11269
11270 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011271 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011272 case NSEMI:
11273 s = "; ";
11274 goto binop;
11275 case NAND:
11276 s = " && ";
11277 goto binop;
11278 case NOR:
11279 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011280binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011281 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011282 /* if (ind < 0) */
11283 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011284 shtree(n->nbinary.ch2, ind, NULL, fp);
11285 break;
11286 case NCMD:
11287 shcmd(n, fp);
11288 if (ind >= 0)
11289 putc('\n', fp);
11290 break;
11291 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011292 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011293 shcmd(lp->n, fp);
11294 if (lp->next)
11295 fputs(" | ", fp);
11296 }
11297 if (n->npipe.backgnd)
11298 fputs(" &", fp);
11299 if (ind >= 0)
11300 putc('\n', fp);
11301 break;
11302 default:
11303 fprintf(fp, "<node type %d>", n->type);
11304 if (ind >= 0)
11305 putc('\n', fp);
11306 break;
11307 }
11308}
11309
11310
Eric Andersenc470f442003-07-28 09:56:35 +000011311static void
11312shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011313{
11314 union node *np;
11315 int first;
11316 const char *s;
11317 int dftfd;
11318
11319 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011320 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11321 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011322 putchar(' ');
11323 sharg(np, fp);
11324 first = 0;
11325 }
Eric Andersenc470f442003-07-28 09:56:35 +000011326 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11327 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011328 putchar(' ');
11329 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011330 case NTO: s = ">"; dftfd = 1; break;
11331 case NCLOBBER: s = ">|"; dftfd = 1; break;
11332 case NAPPEND: s = ">>"; dftfd = 1; break;
11333 case NTOFD: s = ">&"; dftfd = 1; break;
11334 case NFROM: s = "<"; dftfd = 0; break;
11335 case NFROMFD: s = "<&"; dftfd = 0; break;
11336 case NFROMTO: s = "<>"; dftfd = 0; break;
11337 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011338 }
11339 if (np->nfile.fd != dftfd)
11340 fprintf(fp, "%d", np->nfile.fd);
11341 fputs(s, fp);
11342 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11343 fprintf(fp, "%d", np->ndup.dupfd);
11344 } else {
11345 sharg(np->nfile.fname, fp);
11346 }
11347 first = 0;
11348 }
11349}
11350
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011351
Eric Andersenc470f442003-07-28 09:56:35 +000011352
11353static void
11354sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011355{
Eric Andersencb57d552001-06-28 07:25:16 +000011356 char *p;
11357 struct nodelist *bqlist;
11358 int subtype;
11359
11360 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011361 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011362 abort();
11363 }
11364 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011365 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011366 switch (*p) {
11367 case CTLESC:
11368 putc(*++p, fp);
11369 break;
11370 case CTLVAR:
11371 putc('$', fp);
11372 putc('{', fp);
11373 subtype = *++p;
11374 if (subtype == VSLENGTH)
11375 putc('#', fp);
11376
11377 while (*p != '=')
11378 putc(*p++, fp);
11379
11380 if (subtype & VSNUL)
11381 putc(':', fp);
11382
11383 switch (subtype & VSTYPE) {
11384 case VSNORMAL:
11385 putc('}', fp);
11386 break;
11387 case VSMINUS:
11388 putc('-', fp);
11389 break;
11390 case VSPLUS:
11391 putc('+', fp);
11392 break;
11393 case VSQUESTION:
11394 putc('?', fp);
11395 break;
11396 case VSASSIGN:
11397 putc('=', fp);
11398 break;
11399 case VSTRIMLEFT:
11400 putc('#', fp);
11401 break;
11402 case VSTRIMLEFTMAX:
11403 putc('#', fp);
11404 putc('#', fp);
11405 break;
11406 case VSTRIMRIGHT:
11407 putc('%', fp);
11408 break;
11409 case VSTRIMRIGHTMAX:
11410 putc('%', fp);
11411 putc('%', fp);
11412 break;
11413 case VSLENGTH:
11414 break;
11415 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011416 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011417 }
11418 break;
11419 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011420 putc('}', fp);
11421 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011422 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011423 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011424 putc('$', fp);
11425 putc('(', fp);
11426 shtree(bqlist->n, -1, NULL, fp);
11427 putc(')', fp);
11428 break;
11429 default:
11430 putc(*p, fp);
11431 break;
11432 }
11433 }
11434}
11435
11436
Eric Andersenc470f442003-07-28 09:56:35 +000011437static void
11438indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011439{
11440 int i;
11441
Eric Andersenc470f442003-07-28 09:56:35 +000011442 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011443 if (pfx && i == amount - 1)
11444 fputs(pfx, fp);
11445 putc('\t', fp);
11446 }
11447}
Eric Andersencb57d552001-06-28 07:25:16 +000011448
Eric Andersenc470f442003-07-28 09:56:35 +000011449
11450
11451/*
11452 * Debugging stuff.
11453 */
11454
11455
Eric Andersencb57d552001-06-28 07:25:16 +000011456FILE *tracefile;
11457
Eric Andersencb57d552001-06-28 07:25:16 +000011458
Eric Andersenc470f442003-07-28 09:56:35 +000011459void
11460trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011461{
Eric Andersenc470f442003-07-28 09:56:35 +000011462 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011463 return;
11464 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011465}
11466
Eric Andersenc470f442003-07-28 09:56:35 +000011467void
11468trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011469{
11470 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011471
Eric Andersenc470f442003-07-28 09:56:35 +000011472 if (debug != 1)
11473 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011474 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011475 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011476 va_end(va);
11477}
11478
Eric Andersenc470f442003-07-28 09:56:35 +000011479void
11480tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011481{
Eric Andersenc470f442003-07-28 09:56:35 +000011482 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011483 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011484 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011485}
11486
11487
Eric Andersenc470f442003-07-28 09:56:35 +000011488void
11489trputs(const char *s)
11490{
11491 if (debug != 1)
11492 return;
11493 fputs(s, tracefile);
11494}
11495
11496
11497static void
11498trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011499{
11500 char *p;
11501 char c;
11502
Eric Andersenc470f442003-07-28 09:56:35 +000011503 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011504 return;
11505 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011506 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011507 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011508 case '\n': c = 'n'; goto backslash;
11509 case '\t': c = 't'; goto backslash;
11510 case '\r': c = 'r'; goto backslash;
11511 case '"': c = '"'; goto backslash;
11512 case '\\': c = '\\'; goto backslash;
11513 case CTLESC: c = 'e'; goto backslash;
11514 case CTLVAR: c = 'v'; goto backslash;
11515 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11516 case CTLBACKQ: c = 'q'; goto backslash;
11517 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11518backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011519 putc(c, tracefile);
11520 break;
11521 default:
11522 if (*p >= ' ' && *p <= '~')
11523 putc(*p, tracefile);
11524 else {
11525 putc('\\', tracefile);
11526 putc(*p >> 6 & 03, tracefile);
11527 putc(*p >> 3 & 07, tracefile);
11528 putc(*p & 07, tracefile);
11529 }
11530 break;
11531 }
11532 }
11533 putc('"', tracefile);
11534}
11535
11536
Eric Andersenc470f442003-07-28 09:56:35 +000011537void
11538trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011539{
Eric Andersenc470f442003-07-28 09:56:35 +000011540 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011541 return;
11542 while (*ap) {
11543 trstring(*ap++);
11544 if (*ap)
11545 putc(' ', tracefile);
11546 else
11547 putc('\n', tracefile);
11548 }
Eric Andersencb57d552001-06-28 07:25:16 +000011549}
11550
11551
Eric Andersenc470f442003-07-28 09:56:35 +000011552void
11553opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011554{
Eric Andersencb57d552001-06-28 07:25:16 +000011555 char s[100];
11556#ifdef O_APPEND
11557 int flags;
11558#endif
11559
Eric Andersenc470f442003-07-28 09:56:35 +000011560 if (debug != 1) {
11561 if (tracefile)
11562 fflush(tracefile);
11563 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011564 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011565 }
Eric Andersenc470f442003-07-28 09:56:35 +000011566 scopy("./trace", s);
11567 if (tracefile) {
11568 if (!freopen(s, "a", tracefile)) {
11569 fprintf(stderr, "Can't re-open %s\n", s);
11570 debug = 0;
11571 return;
11572 }
11573 } else {
11574 if ((tracefile = fopen(s, "a")) == NULL) {
11575 fprintf(stderr, "Can't open %s\n", s);
11576 debug = 0;
11577 return;
11578 }
11579 }
Eric Andersencb57d552001-06-28 07:25:16 +000011580#ifdef O_APPEND
11581 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11582 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11583#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011584 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011585 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011586}
Eric Andersenc470f442003-07-28 09:56:35 +000011587#endif /* DEBUG */
11588
11589
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011590/* trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011591
11592/*
11593 * Sigmode records the current value of the signal handlers for the various
11594 * modes. A value of zero means that the current handler is not known.
11595 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11596 */
11597
11598#define S_DFL 1 /* default signal handling (SIG_DFL) */
11599#define S_CATCH 2 /* signal is caught */
11600#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11601#define S_HARD_IGN 4 /* signal is ignored permenantly */
11602#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11603
Eric Andersencb57d552001-06-28 07:25:16 +000011604
11605
11606/*
Eric Andersencb57d552001-06-28 07:25:16 +000011607 * The trap builtin.
11608 */
11609
Eric Andersenc470f442003-07-28 09:56:35 +000011610int
11611trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011612{
11613 char *action;
11614 char **ap;
11615 int signo;
11616
Eric Andersenc470f442003-07-28 09:56:35 +000011617 nextopt(nullstr);
11618 ap = argptr;
11619 if (!*ap) {
11620 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011621 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011622 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011623
Eric Andersenc470f442003-07-28 09:56:35 +000011624 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011625 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011626 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011627 out1fmt("trap -- %s %s\n",
11628 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011629 }
11630 }
11631 return 0;
11632 }
Eric Andersenc470f442003-07-28 09:56:35 +000011633 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011634 action = NULL;
11635 else
11636 action = *ap++;
11637 while (*ap) {
11638 if ((signo = decode_signal(*ap, 0)) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011639 sh_error("%s: bad trap", *ap);
Eric Andersencb57d552001-06-28 07:25:16 +000011640 INTOFF;
11641 if (action) {
11642 if (action[0] == '-' && action[1] == '\0')
11643 action = NULL;
11644 else
Eric Andersenc470f442003-07-28 09:56:35 +000011645 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011646 }
Eric Andersenc470f442003-07-28 09:56:35 +000011647 if (trap[signo])
11648 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011649 trap[signo] = action;
11650 if (signo != 0)
11651 setsignal(signo);
11652 INTON;
11653 ap++;
11654 }
11655 return 0;
11656}
11657
11658
Eric Andersenc470f442003-07-28 09:56:35 +000011659/*
11660 * Clear traps on a fork.
11661 */
11662
11663void
11664clear_traps(void)
11665{
11666 char **tp;
11667
11668 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11669 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11670 INTOFF;
11671 ckfree(*tp);
11672 *tp = NULL;
11673 if (tp != &trap[0])
11674 setsignal(tp - trap);
11675 INTON;
11676 }
11677 }
11678}
11679
11680
Eric Andersencb57d552001-06-28 07:25:16 +000011681/*
11682 * Set the signal handler for the specified signal. The routine figures
11683 * out what it should be set to.
11684 */
11685
Eric Andersenc470f442003-07-28 09:56:35 +000011686void
11687setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011688{
11689 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011690 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011691 struct sigaction act;
11692
11693 if ((t = trap[signo]) == NULL)
11694 action = S_DFL;
11695 else if (*t != '\0')
11696 action = S_CATCH;
11697 else
11698 action = S_IGN;
11699 if (rootshell && action == S_DFL) {
11700 switch (signo) {
11701 case SIGINT:
11702 if (iflag || minusc || sflag == 0)
11703 action = S_CATCH;
11704 break;
11705 case SIGQUIT:
11706#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011707 if (debug)
11708 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011709#endif
11710 /* FALLTHROUGH */
11711 case SIGTERM:
11712 if (iflag)
11713 action = S_IGN;
11714 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011715#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011716 case SIGTSTP:
11717 case SIGTTOU:
11718 if (mflag)
11719 action = S_IGN;
11720 break;
11721#endif
11722 }
11723 }
11724
11725 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011726 tsig = *t;
11727 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011728 /*
11729 * current setting unknown
11730 */
11731 if (sigaction(signo, 0, &act) == -1) {
11732 /*
11733 * Pretend it worked; maybe we should give a warning
11734 * here, but other shells don't. We don't alter
11735 * sigmode, so that we retry every time.
11736 */
11737 return;
11738 }
11739 if (act.sa_handler == SIG_IGN) {
11740 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011741 signo == SIGTTIN || signo == SIGTTOU)) {
11742 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011743 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011744 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011745 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011746 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011747 }
11748 }
Eric Andersenc470f442003-07-28 09:56:35 +000011749 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011750 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011751 switch (action) {
11752 case S_CATCH:
11753 act.sa_handler = onsig;
11754 break;
11755 case S_IGN:
11756 act.sa_handler = SIG_IGN;
11757 break;
11758 default:
11759 act.sa_handler = SIG_DFL;
11760 }
Eric Andersencb57d552001-06-28 07:25:16 +000011761 *t = action;
11762 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011763 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011764 sigaction(signo, &act, 0);
11765}
11766
11767/*
11768 * Ignore a signal.
11769 */
11770
Eric Andersenc470f442003-07-28 09:56:35 +000011771void
11772ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011773{
11774 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11775 signal(signo, SIG_IGN);
11776 }
11777 sigmode[signo - 1] = S_HARD_IGN;
11778}
11779
11780
Eric Andersencb57d552001-06-28 07:25:16 +000011781/*
11782 * Signal handler.
11783 */
11784
Eric Andersenc470f442003-07-28 09:56:35 +000011785void
11786onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011787{
Eric Andersencb57d552001-06-28 07:25:16 +000011788 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011789 pendingsigs = signo;
11790
11791 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11792 if (!suppressint)
11793 onint();
11794 intpending = 1;
11795 }
Eric Andersencb57d552001-06-28 07:25:16 +000011796}
11797
11798
Eric Andersencb57d552001-06-28 07:25:16 +000011799/*
11800 * Called to execute a trap. Perhaps we should avoid entering new trap
11801 * handlers while we are executing a trap handler.
11802 */
11803
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011804int
Eric Andersenc470f442003-07-28 09:56:35 +000011805dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011806{
Eric Andersenc470f442003-07-28 09:56:35 +000011807 char *p;
11808 char *q;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011809 int i;
Eric Andersencb57d552001-06-28 07:25:16 +000011810 int savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011811 int skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011812
Eric Andersenc470f442003-07-28 09:56:35 +000011813 savestatus = exitstatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011814 pendingsigs = 0;
11815 xbarrier();
11816
11817 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11818 if (!*q)
11819 continue;
11820 *q = 0;
11821
11822 p = trap[i + 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011823 if (!p)
11824 continue;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011825 skip = evalstring(p, SKIPEVAL);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011826 exitstatus = savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011827 if (skip)
11828 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011829 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011830
11831 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +000011832}
11833
Eric Andersenc470f442003-07-28 09:56:35 +000011834
Eric Andersenc470f442003-07-28 09:56:35 +000011835/*
11836 * Controls whether the shell is interactive or not.
11837 */
11838
Eric Andersenc470f442003-07-28 09:56:35 +000011839void
11840setinteractive(int on)
11841{
11842 static int is_interactive;
11843
11844 if (++on == is_interactive)
11845 return;
11846 is_interactive = on;
11847 setsignal(SIGINT);
11848 setsignal(SIGQUIT);
11849 setsignal(SIGTERM);
11850#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11851 if(is_interactive > 1) {
11852 /* Looks like they want an interactive shell */
11853 static int do_banner;
11854
11855 if(!do_banner) {
11856 out1fmt(
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +000011857 "\n\n%s Built-in shell (ash)\n"
11858 "Enter 'help' for a list of built-in commands.\n\n",
11859 BB_BANNER);
Eric Andersenc470f442003-07-28 09:56:35 +000011860 do_banner++;
11861 }
11862 }
11863#endif
11864}
11865
11866
11867#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11868/*** List the available builtins ***/
11869
11870static int helpcmd(int argc, char **argv)
11871{
11872 int col, i;
11873
11874 out1fmt("\nBuilt-in commands:\n-------------------\n");
11875 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11876 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11877 builtincmd[i].name + 1);
11878 if (col > 60) {
11879 out1fmt("\n");
11880 col = 0;
11881 }
11882 }
11883#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11884 {
11885 extern const struct BB_applet applets[];
11886 extern const size_t NUM_APPLETS;
11887
11888 for (i = 0; i < NUM_APPLETS; i++) {
11889
11890 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11891 if (col > 60) {
11892 out1fmt("\n");
11893 col = 0;
11894 }
11895 }
11896 }
11897#endif
11898 out1fmt("\n\n");
11899 return EXIT_SUCCESS;
11900}
11901#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11902
Eric Andersencb57d552001-06-28 07:25:16 +000011903/*
11904 * Called to exit the shell.
11905 */
11906
Eric Andersenc470f442003-07-28 09:56:35 +000011907void
11908exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011909{
Eric Andersenc470f442003-07-28 09:56:35 +000011910 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011911 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011912 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011913
Eric Andersenc470f442003-07-28 09:56:35 +000011914 status = exitstatus;
11915 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011916 if (setjmp(loc.loc)) {
11917 if (exception == EXEXIT)
11918 _exit(exitstatus);
Eric Andersenc470f442003-07-28 09:56:35 +000011919 goto out;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011920 }
Eric Andersenc470f442003-07-28 09:56:35 +000011921 handler = &loc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011922 if ((p = trap[0])) {
Eric Andersencb57d552001-06-28 07:25:16 +000011923 trap[0] = NULL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011924 evalstring(p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011925 }
Eric Andersencb57d552001-06-28 07:25:16 +000011926 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011927 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011928#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11929 if (iflag && rootshell) {
11930 const char *hp = lookupvar("HISTFILE");
11931
11932 if(hp != NULL )
11933 save_history ( hp );
11934 }
11935#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011936out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011937 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011938 /* NOTREACHED */
11939}
11940
11941static int decode_signal(const char *string, int minsig)
11942{
11943 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011944 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011945
Eric Andersen34506362001-08-02 05:02:46 +000011946 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011947}
Eric Andersen34506362001-08-02 05:02:46 +000011948
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011949/* var.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011950
11951static struct var *vartab[VTABSIZE];
11952
11953static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011954static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011955
11956/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011957 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011958 */
11959
Eric Andersenc470f442003-07-28 09:56:35 +000011960
11961#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011962/*
Eric Andersenc470f442003-07-28 09:56:35 +000011963 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011964 */
11965
Eric Andersenc470f442003-07-28 09:56:35 +000011966int
11967setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011968{
Eric Andersenc470f442003-07-28 09:56:35 +000011969 int err;
11970 volatile int saveint;
11971 struct jmploc *volatile savehandler = handler;
11972 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011973
Eric Andersenc470f442003-07-28 09:56:35 +000011974 SAVEINT(saveint);
11975 if (setjmp(jmploc.loc))
11976 err = 1;
11977 else {
11978 handler = &jmploc;
11979 setvar(name, val, flags);
11980 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011981 }
Eric Andersenc470f442003-07-28 09:56:35 +000011982 handler = savehandler;
11983 RESTOREINT(saveint);
11984 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011985}
Eric Andersenc470f442003-07-28 09:56:35 +000011986#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011987
11988/*
11989 * Set the value of a variable. The flags argument is ored with the
11990 * flags of the variable. If val is NULL, the variable is unset.
11991 */
11992
Eric Andersenc470f442003-07-28 09:56:35 +000011993static void
11994setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011995{
Eric Andersenc470f442003-07-28 09:56:35 +000011996 char *p, *q;
11997 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011998 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011999 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000012000
Eric Andersenc470f442003-07-28 09:56:35 +000012001 q = endofname(name);
12002 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012003 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000012004 if (!namelen || p != q)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012005 sh_error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012006 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012007 if (val == NULL) {
12008 flags |= VUNSET;
12009 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012010 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000012011 }
12012 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012013 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
Paul Fox8de331d2005-07-21 12:03:05 +000012014 if (val) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012015 *p++ = '=';
Eric Andersenc470f442003-07-28 09:56:35 +000012016 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000012017 }
Eric Andersenc470f442003-07-28 09:56:35 +000012018 *p = '\0';
12019 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012020 INTON;
12021}
12022
12023
Eric Andersencb57d552001-06-28 07:25:16 +000012024/*
12025 * Same as setvar except that the variable and value are passed in
12026 * the first argument as name=value. Since the first argument will
12027 * be actually stored in the table, it should not be a string that
12028 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012029 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012030 */
12031
Eric Andersenc470f442003-07-28 09:56:35 +000012032void
12033setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012034{
12035 struct var *vp, **vpp;
12036
12037 vpp = hashvar(s);
12038 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012039 vp = *findvar(vpp, s);
12040 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012041 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12042 const char *n;
12043
Eric Andersenc470f442003-07-28 09:56:35 +000012044 if (flags & VNOSAVE)
12045 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012046 n = vp->text;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012047 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012048 }
Eric Andersenc470f442003-07-28 09:56:35 +000012049
12050 if (flags & VNOSET)
12051 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012052
12053 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012054 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012055
Eric Andersenc470f442003-07-28 09:56:35 +000012056 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12057 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012058
Eric Andersenc470f442003-07-28 09:56:35 +000012059 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12060 } else {
12061 if (flags & VNOSET)
12062 return;
12063 /* not found */
12064 vp = ckmalloc(sizeof (*vp));
12065 vp->next = *vpp;
12066 vp->func = NULL;
12067 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012068 }
Eric Andersenc470f442003-07-28 09:56:35 +000012069 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12070 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012071 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012072 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012073}
12074
12075
Eric Andersencb57d552001-06-28 07:25:16 +000012076/*
12077 * Process a linked list of variable assignments.
12078 */
12079
Eric Andersenc470f442003-07-28 09:56:35 +000012080static void
12081listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012082{
Eric Andersenc470f442003-07-28 09:56:35 +000012083 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012084
Eric Andersenc470f442003-07-28 09:56:35 +000012085 if (!lp)
12086 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012087 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012088 do {
12089 setvareq(lp->text, flags);
12090 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012091 INTON;
12092}
12093
12094
Eric Andersencb57d552001-06-28 07:25:16 +000012095/*
12096 * Find the value of a variable. Returns NULL if not set.
12097 */
12098
Eric Andersenc470f442003-07-28 09:56:35 +000012099static char *
12100lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012101{
Eric Andersencb57d552001-06-28 07:25:16 +000012102 struct var *v;
12103
Eric Andersen16767e22004-03-16 05:14:10 +000012104 if ((v = *findvar(hashvar(name), name))) {
12105#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012106 /*
12107 * Dynamic variables are implemented roughly the same way they are
12108 * in bash. Namely, they're "special" so long as they aren't unset.
12109 * As soon as they're unset, they're no longer dynamic, and dynamic
12110 * lookup will no longer happen at that point. -- PFM.
12111 */
Eric Andersen16767e22004-03-16 05:14:10 +000012112 if((v->flags & VDYNAMIC))
12113 (*v->func)(NULL);
12114#endif
12115 if(!(v->flags & VUNSET))
12116 return strchrnul(v->text, '=') + 1;
12117 }
Eric Andersenef02f822004-03-11 13:34:24 +000012118
Eric Andersencb57d552001-06-28 07:25:16 +000012119 return NULL;
12120}
12121
12122
Eric Andersencb57d552001-06-28 07:25:16 +000012123/*
12124 * Search the environment of a builtin command.
12125 */
12126
Eric Andersenc470f442003-07-28 09:56:35 +000012127static char *
12128bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012129{
Eric Andersenc470f442003-07-28 09:56:35 +000012130 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012131
Eric Andersenc470f442003-07-28 09:56:35 +000012132 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012133 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012134 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012135 }
12136 return lookupvar(name);
12137}
12138
12139
Eric Andersencb57d552001-06-28 07:25:16 +000012140/*
Eric Andersenc470f442003-07-28 09:56:35 +000012141 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012142 */
12143
Eric Andersenc470f442003-07-28 09:56:35 +000012144static char **
12145listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012146{
Eric Andersencb57d552001-06-28 07:25:16 +000012147 struct var **vpp;
12148 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012149 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012150 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012151
Eric Andersenc470f442003-07-28 09:56:35 +000012152 STARTSTACKSTR(ep);
12153 vpp = vartab;
12154 mask = on | off;
12155 do {
12156 for (vp = *vpp ; vp ; vp = vp->next)
12157 if ((vp->flags & mask) == on) {
12158 if (ep == stackstrend())
12159 ep = growstackstr();
12160 *ep++ = (char *) vp->text;
12161 }
12162 } while (++vpp < vartab + VTABSIZE);
12163 if (ep == stackstrend())
12164 ep = growstackstr();
12165 if (end)
12166 *end = ep;
12167 *ep++ = NULL;
12168 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012169}
12170
12171
12172/*
Eric Andersenc470f442003-07-28 09:56:35 +000012173 * POSIX requires that 'set' (but not export or readonly) output the
12174 * variables in lexicographic order - by the locale's collating order (sigh).
12175 * Maybe we could keep them in an ordered balanced binary tree
12176 * instead of hashed lists.
12177 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012178 */
12179
Eric Andersenc470f442003-07-28 09:56:35 +000012180static int
12181showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012182{
Eric Andersenc470f442003-07-28 09:56:35 +000012183 const char *sep;
12184 char **ep, **epend;
12185
12186 ep = listvars(on, off, &epend);
12187 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12188
12189 sep = *sep_prefix ? spcstr : sep_prefix;
12190
12191 for (; ep < epend; ep++) {
12192 const char *p;
12193 const char *q;
12194
12195 p = strchrnul(*ep, '=');
12196 q = nullstr;
12197 if (*p)
12198 q = single_quote(++p);
12199
12200 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12201 }
12202
Eric Andersencb57d552001-06-28 07:25:16 +000012203 return 0;
12204}
12205
12206
12207
12208/*
12209 * The export and readonly commands.
12210 */
12211
Eric Andersenc470f442003-07-28 09:56:35 +000012212static int
12213exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012214{
12215 struct var *vp;
12216 char *name;
12217 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012218 char **aptr;
12219 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12220 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012221
Eric Andersenc470f442003-07-28 09:56:35 +000012222 notp = nextopt("p") - 'p';
12223 if (notp && ((name = *(aptr = argptr)))) {
12224 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012225 if ((p = strchr(name, '=')) != NULL) {
12226 p++;
12227 } else {
12228 if ((vp = *findvar(hashvar(name), name))) {
12229 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012230 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012231 }
12232 }
12233 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012234 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012235 } else {
12236 showvars(argv[0], flag, 0);
12237 }
12238 return 0;
12239}
12240
Eric Andersen34506362001-08-02 05:02:46 +000012241
Eric Andersencb57d552001-06-28 07:25:16 +000012242/*
Eric Andersencb57d552001-06-28 07:25:16 +000012243 * Make a variable a local variable. When a variable is made local, it's
12244 * value and flags are saved in a localvar structure. The saved values
12245 * will be restored when the shell function returns. We handle the name
12246 * "-" as a special case.
12247 */
12248
Eric Andersenc470f442003-07-28 09:56:35 +000012249static inline void
12250mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012251{
Eric Andersencb57d552001-06-28 07:25:16 +000012252 struct localvar *lvp;
12253 struct var **vpp;
12254 struct var *vp;
12255
12256 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012257 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012258 if (name[0] == '-' && name[1] == '\0') {
12259 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012260 p = ckmalloc(sizeof(optlist));
12261 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012262 vp = NULL;
12263 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012264 char *eq;
12265
Eric Andersencb57d552001-06-28 07:25:16 +000012266 vpp = hashvar(name);
12267 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012268 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012269 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012270 if (eq)
12271 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012272 else
12273 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012274 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012275 lvp->flags = VUNSET;
12276 } else {
12277 lvp->text = vp->text;
12278 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012279 vp->flags |= VSTRFIXED|VTEXTFIXED;
12280 if (eq)
12281 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012282 }
12283 }
12284 lvp->vp = vp;
12285 lvp->next = localvars;
12286 localvars = lvp;
12287 INTON;
12288}
12289
Eric Andersenc470f442003-07-28 09:56:35 +000012290/*
12291 * The "local" command.
12292 */
12293
12294static int
12295localcmd(int argc, char **argv)
12296{
12297 char *name;
12298
12299 argv = argptr;
12300 while ((name = *argv++) != NULL) {
12301 mklocal(name);
12302 }
12303 return 0;
12304}
12305
12306
Eric Andersencb57d552001-06-28 07:25:16 +000012307/*
12308 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012309 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012310 */
12311
Eric Andersenc470f442003-07-28 09:56:35 +000012312static void
12313poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012314{
Eric Andersencb57d552001-06-28 07:25:16 +000012315 struct localvar *lvp;
12316 struct var *vp;
12317
12318 while ((lvp = localvars) != NULL) {
12319 localvars = lvp->next;
12320 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012321 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12322 if (vp == NULL) { /* $- saved */
12323 memcpy(optlist, lvp->text, sizeof(optlist));
12324 ckfree(lvp->text);
12325 optschanged();
12326 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12327 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012328 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012329 if (vp->func)
12330 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12331 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12332 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012333 vp->flags = lvp->flags;
12334 vp->text = lvp->text;
12335 }
Eric Andersenc470f442003-07-28 09:56:35 +000012336 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012337 }
12338}
12339
12340
Eric Andersencb57d552001-06-28 07:25:16 +000012341/*
12342 * The unset builtin command. We unset the function before we unset the
12343 * variable to allow a function to be unset when there is a readonly variable
12344 * with the same name.
12345 */
12346
Eric Andersenc470f442003-07-28 09:56:35 +000012347int
12348unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012349{
12350 char **ap;
12351 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012352 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012353 int ret = 0;
12354
12355 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012356 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012357 }
Eric Andersencb57d552001-06-28 07:25:16 +000012358
Eric Andersenc470f442003-07-28 09:56:35 +000012359 for (ap = argptr; *ap ; ap++) {
12360 if (flag != 'f') {
12361 i = unsetvar(*ap);
12362 ret |= i;
12363 if (!(i & 2))
12364 continue;
12365 }
12366 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012367 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012368 }
Eric Andersenc470f442003-07-28 09:56:35 +000012369 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012370}
12371
12372
12373/*
12374 * Unset the specified variable.
12375 */
12376
Eric Andersenc470f442003-07-28 09:56:35 +000012377int
12378unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012379{
Eric Andersencb57d552001-06-28 07:25:16 +000012380 struct var **vpp;
12381 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012382 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012383
12384 vpp = findvar(hashvar(s), s);
12385 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012386 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012387 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012388 int flags = vp->flags;
12389
12390 retval = 1;
12391 if (flags & VREADONLY)
12392 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012393#ifdef DYNAMIC_VAR
12394 vp->flags &= ~VDYNAMIC;
12395#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012396 if (flags & VUNSET)
12397 goto ok;
12398 if ((flags & VSTRFIXED) == 0) {
12399 INTOFF;
12400 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12401 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012402 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012403 ckfree(vp);
12404 INTON;
12405 } else {
12406 setvar(s, 0, 0);
12407 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012408 }
Eric Andersenc470f442003-07-28 09:56:35 +000012409ok:
12410 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012411 }
12412
Eric Andersenc470f442003-07-28 09:56:35 +000012413out:
12414 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012415}
12416
12417
12418
12419/*
12420 * Find the appropriate entry in the hash table from the name.
12421 */
12422
Eric Andersenc470f442003-07-28 09:56:35 +000012423static struct var **
12424hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012425{
Eric Andersencb57d552001-06-28 07:25:16 +000012426 unsigned int hashval;
12427
12428 hashval = ((unsigned char) *p) << 4;
12429 while (*p && *p != '=')
12430 hashval += (unsigned char) *p++;
12431 return &vartab[hashval % VTABSIZE];
12432}
12433
12434
12435
12436/*
Eric Andersenc470f442003-07-28 09:56:35 +000012437 * Compares two strings up to the first = or '\0'. The first
12438 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012439 * either '=' or '\0'.
12440 */
12441
Eric Andersenc470f442003-07-28 09:56:35 +000012442int
12443varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012444{
Eric Andersenc470f442003-07-28 09:56:35 +000012445 int c, d;
12446
12447 while ((c = *p) == (d = *q)) {
12448 if (!c || c == '=')
12449 goto out;
12450 p++;
12451 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012452 }
Eric Andersenc470f442003-07-28 09:56:35 +000012453 if (c == '=')
12454 c = 0;
12455 if (d == '=')
12456 d = 0;
12457out:
12458 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012459}
12460
Eric Andersenc470f442003-07-28 09:56:35 +000012461static int
12462vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012463{
Eric Andersenc470f442003-07-28 09:56:35 +000012464 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012465}
12466
Eric Andersenc470f442003-07-28 09:56:35 +000012467static struct var **
12468findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012469{
12470 for (; *vpp; vpp = &(*vpp)->next) {
12471 if (varequal((*vpp)->text, name)) {
12472 break;
12473 }
12474 }
12475 return vpp;
12476}
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012477/* setmode.c */
Eric Andersencb57d552001-06-28 07:25:16 +000012478
Eric Andersenc470f442003-07-28 09:56:35 +000012479#include <sys/times.h>
12480
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012481static const unsigned char timescmd_str[] = {
12482 ' ', offsetof(struct tms, tms_utime),
12483 '\n', offsetof(struct tms, tms_stime),
12484 ' ', offsetof(struct tms, tms_cutime),
12485 '\n', offsetof(struct tms, tms_cstime),
12486 0
12487};
Eric Andersencb57d552001-06-28 07:25:16 +000012488
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012489static int timescmd(int ac, char **av)
12490{
12491 long int clk_tck, s, t;
12492 const unsigned char *p;
12493 struct tms buf;
12494
12495 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012496 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012497
12498 p = timescmd_str;
12499 do {
12500 t = *(clock_t *)(((char *) &buf) + p[1]);
12501 s = t / clk_tck;
12502 out1fmt("%ldm%ld.%.3lds%c",
12503 s/60, s%60,
12504 ((t - s * clk_tck) * 1000) / clk_tck,
12505 p[0]);
12506 } while (*(p += 2));
12507
Eric Andersencb57d552001-06-28 07:25:16 +000012508 return 0;
12509}
12510
Eric Andersend35c5df2002-01-09 15:37:36 +000012511#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012512static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012513dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012514{
Eric Andersened9ecf72004-06-22 08:29:45 +000012515 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012516 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012517
Eric Andersenc470f442003-07-28 09:56:35 +000012518 INTOFF;
12519 result = arith(s, &errcode);
12520 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012521 if (errcode == -3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012522 sh_error("exponent less than 0");
Eric Andersen90898442003-08-06 11:20:52 +000012523 else if (errcode == -2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012524 sh_error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012525 else if (errcode == -5)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012526 sh_error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012527 else
12528 synerror(s);
12529 }
12530 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012531
Eric Andersenc470f442003-07-28 09:56:35 +000012532 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012533}
Eric Andersenc470f442003-07-28 09:56:35 +000012534
12535
12536/*
Eric Andersen90898442003-08-06 11:20:52 +000012537 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12538 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12539 *
12540 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012541 */
Eric Andersen90898442003-08-06 11:20:52 +000012542
Eric Andersenc470f442003-07-28 09:56:35 +000012543static int
Eric Andersen90898442003-08-06 11:20:52 +000012544letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012545{
Eric Andersenc470f442003-07-28 09:56:35 +000012546 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012547 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012548
Eric Andersen90898442003-08-06 11:20:52 +000012549 ap = argv + 1;
12550 if(!*ap)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012551 sh_error("expression expected");
Eric Andersen90898442003-08-06 11:20:52 +000012552 for (ap = argv + 1; *ap; ap++) {
12553 i = dash_arith(*ap);
12554 }
Eric Andersenc470f442003-07-28 09:56:35 +000012555
Eric Andersen90898442003-08-06 11:20:52 +000012556 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012557}
12558#endif /* CONFIG_ASH_MATH_SUPPORT */
12559
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012560/* miscbltin.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012561
12562/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012563 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012564 */
12565
12566#undef rflag
12567
12568#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012569#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012570typedef enum __rlimit_resource rlim_t;
12571#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012572#endif
12573
12574
Eric Andersenc470f442003-07-28 09:56:35 +000012575/*
12576 * The read builtin. The -e option causes backslashes to escape the
12577 * following character.
12578 *
12579 * This uses unbuffered input, which may be avoidable in some cases.
12580 */
12581
12582static int
12583readcmd(int argc, char **argv)
12584{
12585 char **ap;
12586 int backslash;
12587 char c;
12588 int rflag;
12589 char *prompt;
12590 const char *ifs;
12591 char *p;
12592 int startword;
12593 int status;
12594 int i;
Paul Fox02eb9342005-09-07 16:56:02 +000012595#if defined(CONFIG_ASH_READ_NCHARS)
12596 int nch_flag = 0;
12597 int nchars = 0;
12598 int silent = 0;
12599 struct termios tty, old_tty;
12600#endif
12601#if defined(CONFIG_ASH_READ_TIMEOUT)
12602 fd_set set;
12603 struct timeval ts;
12604
12605 ts.tv_sec = ts.tv_usec = 0;
12606#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012607
12608 rflag = 0;
12609 prompt = NULL;
Paul Fox02eb9342005-09-07 16:56:02 +000012610#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12611 while ((i = nextopt("p:rt:n:s")) != '\0')
12612#elif defined(CONFIG_ASH_READ_NCHARS)
12613 while ((i = nextopt("p:rn:s")) != '\0')
12614#elif defined(CONFIG_ASH_READ_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012615 while ((i = nextopt("p:rt:")) != '\0')
12616#else
12617 while ((i = nextopt("p:r")) != '\0')
12618#endif
12619 {
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012620 switch(i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012621 case 'p':
Eric Andersenc470f442003-07-28 09:56:35 +000012622 prompt = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012623 break;
12624#if defined(CONFIG_ASH_READ_NCHARS)
12625 case 'n':
12626 nchars = strtol(optionarg, &p, 10);
12627 if (*p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012628 sh_error("invalid count");
Paul Fox02eb9342005-09-07 16:56:02 +000012629 nch_flag = (nchars > 0);
12630 break;
12631 case 's':
12632 silent = 1;
12633 break;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012634#endif
Paul Fox02eb9342005-09-07 16:56:02 +000012635#if defined(CONFIG_ASH_READ_TIMEOUT)
12636 case 't':
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012637 ts.tv_sec = strtol(optionarg, &p, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012638 ts.tv_usec = 0;
12639 if (*p == '.') {
12640 char *p2;
12641 if (*++p) {
12642 int scale;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012643 ts.tv_usec = strtol(p, &p2, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012644 if (*p2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012645 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012646 scale = p2 - p;
12647 /* normalize to usec */
12648 if (scale > 6)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012649 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012650 while (scale++ < 6)
12651 ts.tv_usec *= 10;
12652 }
12653 } else if (*p) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012654 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012655 }
12656 if ( ! ts.tv_sec && ! ts.tv_usec)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012657 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012658 break;
12659#endif
12660 case 'r':
12661 rflag = 1;
12662 break;
12663 default:
12664 break;
12665 }
Eric Andersenc470f442003-07-28 09:56:35 +000012666 }
12667 if (prompt && isatty(0)) {
12668 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012669 }
12670 if (*(ap = argptr) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012671 sh_error("arg count");
Eric Andersenc470f442003-07-28 09:56:35 +000012672 if ((ifs = bltinlookup("IFS")) == NULL)
12673 ifs = defifs;
Paul Fox02eb9342005-09-07 16:56:02 +000012674#if defined(CONFIG_ASH_READ_NCHARS)
12675 if (nch_flag || silent) {
12676 tcgetattr(0, &tty);
12677 old_tty = tty;
12678 if (nch_flag) {
12679 tty.c_lflag &= ~ICANON;
12680 tty.c_cc[VMIN] = nchars;
12681 }
12682 if (silent) {
12683 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12684
12685 }
12686 tcsetattr(0, TCSANOW, &tty);
12687 }
12688#endif
12689#if defined(CONFIG_ASH_READ_TIMEOUT)
12690 if (ts.tv_sec || ts.tv_usec) {
12691 FD_ZERO (&set);
12692 FD_SET (0, &set);
12693
12694 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12695 if (!i) {
12696#if defined(CONFIG_ASH_READ_NCHARS)
12697 if (nch_flag)
12698 tcsetattr(0, TCSANOW, &old_tty);
12699#endif
12700 return 1;
12701 }
12702 }
Ned Ludd2123b7c2005-02-09 21:07:23 +000012703#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012704 status = 0;
12705 startword = 1;
12706 backslash = 0;
12707 STARTSTACKSTR(p);
Paul Fox02eb9342005-09-07 16:56:02 +000012708#if defined(CONFIG_ASH_READ_NCHARS)
12709 while (!nch_flag || nchars--)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012710#else
12711 for (;;)
12712#endif
12713 {
Eric Andersenc470f442003-07-28 09:56:35 +000012714 if (read(0, &c, 1) != 1) {
12715 status = 1;
12716 break;
12717 }
12718 if (c == '\0')
12719 continue;
12720 if (backslash) {
12721 backslash = 0;
12722 if (c != '\n')
12723 goto put;
12724 continue;
12725 }
12726 if (!rflag && c == '\\') {
12727 backslash++;
12728 continue;
12729 }
12730 if (c == '\n')
12731 break;
12732 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12733 continue;
12734 }
12735 startword = 0;
12736 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12737 STACKSTRNUL(p);
12738 setvar(*ap, stackblock(), 0);
12739 ap++;
12740 startword = 1;
12741 STARTSTACKSTR(p);
12742 } else {
12743put:
12744 STPUTC(c, p);
12745 }
12746 }
Paul Fox02eb9342005-09-07 16:56:02 +000012747#if defined(CONFIG_ASH_READ_NCHARS)
12748 if (nch_flag || silent)
12749 tcsetattr(0, TCSANOW, &old_tty);
12750#endif
12751
Eric Andersenc470f442003-07-28 09:56:35 +000012752 STACKSTRNUL(p);
12753 /* Remove trailing blanks */
12754 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12755 *p = '\0';
12756 setvar(*ap, stackblock(), 0);
12757 while (*++ap != NULL)
12758 setvar(*ap, nullstr, 0);
12759 return status;
12760}
12761
12762
12763static int umaskcmd(int argc, char **argv)
12764{
12765 static const char permuser[3] = "ugo";
12766 static const char permmode[3] = "rwx";
12767 static const short int permmask[] = {
12768 S_IRUSR, S_IWUSR, S_IXUSR,
12769 S_IRGRP, S_IWGRP, S_IXGRP,
12770 S_IROTH, S_IWOTH, S_IXOTH
12771 };
12772
12773 char *ap;
12774 mode_t mask;
12775 int i;
12776 int symbolic_mode = 0;
12777
12778 while (nextopt("S") != '\0') {
12779 symbolic_mode = 1;
12780 }
12781
12782 INTOFF;
12783 mask = umask(0);
12784 umask(mask);
12785 INTON;
12786
12787 if ((ap = *argptr) == NULL) {
12788 if (symbolic_mode) {
12789 char buf[18];
12790 char *p = buf;
12791
12792 for (i = 0; i < 3; i++) {
12793 int j;
12794
12795 *p++ = permuser[i];
12796 *p++ = '=';
12797 for (j = 0; j < 3; j++) {
12798 if ((mask & permmask[3 * i + j]) == 0) {
12799 *p++ = permmode[j];
12800 }
12801 }
12802 *p++ = ',';
12803 }
12804 *--p = 0;
12805 puts(buf);
12806 } else {
12807 out1fmt("%.4o\n", mask);
12808 }
12809 } else {
12810 if (is_digit((unsigned char) *ap)) {
12811 mask = 0;
12812 do {
12813 if (*ap >= '8' || *ap < '0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012814 sh_error(illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012815 mask = (mask << 3) + (*ap - '0');
12816 } while (*++ap != '\0');
12817 umask(mask);
12818 } else {
12819 mask = ~mask & 0777;
12820 if (!bb_parse_mode(ap, &mask)) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012821 sh_error("Illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012822 }
12823 umask(~mask & 0777);
12824 }
12825 }
12826 return 0;
12827}
12828
12829/*
12830 * ulimit builtin
12831 *
12832 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12833 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12834 * ash by J.T. Conklin.
12835 *
12836 * Public domain.
12837 */
12838
12839struct limits {
12840 const char *name;
12841 int cmd;
12842 int factor; /* multiply by to get rlim_{cur,max} values */
12843 char option;
12844};
12845
12846static const struct limits limits[] = {
12847#ifdef RLIMIT_CPU
12848 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12849#endif
12850#ifdef RLIMIT_FSIZE
12851 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12852#endif
12853#ifdef RLIMIT_DATA
12854 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12855#endif
12856#ifdef RLIMIT_STACK
12857 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12858#endif
12859#ifdef RLIMIT_CORE
12860 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12861#endif
12862#ifdef RLIMIT_RSS
12863 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12864#endif
12865#ifdef RLIMIT_MEMLOCK
12866 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12867#endif
12868#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012869 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012870#endif
12871#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012872 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012873#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012874#ifdef RLIMIT_AS
12875 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012876#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012877#ifdef RLIMIT_LOCKS
12878 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012879#endif
12880 { (char *) 0, 0, 0, '\0' }
12881};
12882
Glenn L McGrath76620622004-01-13 10:19:37 +000012883enum limtype { SOFT = 0x1, HARD = 0x2 };
12884
12885static void printlim(enum limtype how, const struct rlimit *limit,
12886 const struct limits *l)
12887{
12888 rlim_t val;
12889
12890 val = limit->rlim_max;
12891 if (how & SOFT)
12892 val = limit->rlim_cur;
12893
12894 if (val == RLIM_INFINITY)
12895 out1fmt("unlimited\n");
12896 else {
12897 val /= l->factor;
12898 out1fmt("%lld\n", (long long) val);
12899 }
12900}
12901
Eric Andersenc470f442003-07-28 09:56:35 +000012902int
12903ulimitcmd(int argc, char **argv)
12904{
12905 int c;
12906 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012907 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012908 const struct limits *l;
12909 int set, all = 0;
12910 int optc, what;
12911 struct rlimit limit;
12912
12913 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012914 while ((optc = nextopt("HSa"
12915#ifdef RLIMIT_CPU
12916 "t"
12917#endif
12918#ifdef RLIMIT_FSIZE
12919 "f"
12920#endif
12921#ifdef RLIMIT_DATA
12922 "d"
12923#endif
12924#ifdef RLIMIT_STACK
12925 "s"
12926#endif
12927#ifdef RLIMIT_CORE
12928 "c"
12929#endif
12930#ifdef RLIMIT_RSS
12931 "m"
12932#endif
12933#ifdef RLIMIT_MEMLOCK
12934 "l"
12935#endif
12936#ifdef RLIMIT_NPROC
12937 "p"
12938#endif
12939#ifdef RLIMIT_NOFILE
12940 "n"
12941#endif
12942#ifdef RLIMIT_AS
12943 "v"
12944#endif
12945#ifdef RLIMIT_LOCKS
12946 "w"
12947#endif
12948 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012949 switch (optc) {
12950 case 'H':
12951 how = HARD;
12952 break;
12953 case 'S':
12954 how = SOFT;
12955 break;
12956 case 'a':
12957 all = 1;
12958 break;
12959 default:
12960 what = optc;
12961 }
12962
Glenn L McGrath76620622004-01-13 10:19:37 +000012963 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012964 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012965
12966 set = *argptr ? 1 : 0;
12967 if (set) {
12968 char *p = *argptr;
12969
12970 if (all || argptr[1])
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012971 sh_error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012972 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012973 val = RLIM_INFINITY;
12974 else {
12975 val = (rlim_t) 0;
12976
12977 while ((c = *p++) >= '0' && c <= '9')
12978 {
12979 val = (val * 10) + (long)(c - '0');
12980 if (val < (rlim_t) 0)
12981 break;
12982 }
12983 if (c)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012984 sh_error("bad number");
Eric Andersenc470f442003-07-28 09:56:35 +000012985 val *= l->factor;
12986 }
12987 }
12988 if (all) {
12989 for (l = limits; l->name; l++) {
12990 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012991 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012992 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012993 }
12994 return 0;
12995 }
12996
12997 getrlimit(l->cmd, &limit);
12998 if (set) {
12999 if (how & HARD)
13000 limit.rlim_max = val;
13001 if (how & SOFT)
13002 limit.rlim_cur = val;
13003 if (setrlimit(l->cmd, &limit) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000013004 sh_error("error setting limit (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +000013005 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000013006 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000013007 }
13008 return 0;
13009}
13010
Eric Andersen90898442003-08-06 11:20:52 +000013011
13012#ifdef CONFIG_ASH_MATH_SUPPORT
13013
13014/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
13015
13016 Permission is hereby granted, free of charge, to any person obtaining
13017 a copy of this software and associated documentation files (the
13018 "Software"), to deal in the Software without restriction, including
13019 without limitation the rights to use, copy, modify, merge, publish,
13020 distribute, sublicense, and/or sell copies of the Software, and to
13021 permit persons to whom the Software is furnished to do so, subject to
13022 the following conditions:
13023
13024 The above copyright notice and this permission notice shall be
13025 included in all copies or substantial portions of the Software.
13026
13027 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13028 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13029 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13030 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13031 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13032 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13033 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13034*/
13035
13036/* This is my infix parser/evaluator. It is optimized for size, intended
13037 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000013038 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000013039 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000013040 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000013041 * be that which POSIX specifies for shells. */
13042
13043/* The code uses a simple two-stack algorithm. See
13044 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000013045 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000013046 * this is based (this code differs in that it applies operators immediately
13047 * to the stack instead of adding them to a queue to end up with an
13048 * expression). */
13049
13050/* To use the routine, call it with an expression string and error return
13051 * pointer */
13052
13053/*
13054 * Aug 24, 2001 Manuel Novoa III
13055 *
13056 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13057 *
13058 * 1) In arith_apply():
13059 * a) Cached values of *numptr and &(numptr[-1]).
13060 * b) Removed redundant test for zero denominator.
13061 *
13062 * 2) In arith():
13063 * a) Eliminated redundant code for processing operator tokens by moving
13064 * to a table-based implementation. Also folded handling of parens
13065 * into the table.
13066 * b) Combined all 3 loops which called arith_apply to reduce generated
13067 * code size at the cost of speed.
13068 *
13069 * 3) The following expressions were treated as valid by the original code:
13070 * 1() , 0! , 1 ( *3 ) .
13071 * These bugs have been fixed by internally enclosing the expression in
13072 * parens and then checking that all binary ops and right parens are
13073 * preceded by a valid expression (NUM_TOKEN).
13074 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013075 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013076 * ctype's isspace() if it is used by another busybox applet or if additional
13077 * whitespace chars should be considered. Look below the "#include"s for a
13078 * precompiler test.
13079 */
13080
13081/*
13082 * Aug 26, 2001 Manuel Novoa III
13083 *
13084 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13085 *
13086 * Merge in Aaron's comments previously posted to the busybox list,
13087 * modified slightly to take account of my changes to the code.
13088 *
13089 */
13090
13091/*
13092 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13093 *
13094 * - allow access to variable,
13095 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13096 * - realize assign syntax (VAR=expr, +=, *= etc)
13097 * - realize exponentiation (** operator)
13098 * - realize comma separated - expr, expr
13099 * - realise ++expr --expr expr++ expr--
13100 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013101 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013102 * - was restored loses XOR operator
13103 * - remove one goto label, added three ;-)
13104 * - protect $((num num)) as true zero expr (Manuel`s error)
13105 * - always use special isspace(), see comment from bash ;-)
13106 */
13107
13108
13109#define arith_isspace(arithval) \
13110 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13111
13112
13113typedef unsigned char operator;
13114
13115/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013116 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013117 * precedence. The ID portion is so that multiple operators can have the
13118 * same precedence, ensuring that the leftmost one is evaluated first.
13119 * Consider * and /. */
13120
13121#define tok_decl(prec,id) (((id)<<5)|(prec))
13122#define PREC(op) ((op) & 0x1F)
13123
13124#define TOK_LPAREN tok_decl(0,0)
13125
13126#define TOK_COMMA tok_decl(1,0)
13127
13128#define TOK_ASSIGN tok_decl(2,0)
13129#define TOK_AND_ASSIGN tok_decl(2,1)
13130#define TOK_OR_ASSIGN tok_decl(2,2)
13131#define TOK_XOR_ASSIGN tok_decl(2,3)
13132#define TOK_PLUS_ASSIGN tok_decl(2,4)
13133#define TOK_MINUS_ASSIGN tok_decl(2,5)
13134#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13135#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13136
13137#define TOK_MUL_ASSIGN tok_decl(3,0)
13138#define TOK_DIV_ASSIGN tok_decl(3,1)
13139#define TOK_REM_ASSIGN tok_decl(3,2)
13140
13141/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13142#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13143
13144/* conditional is right associativity too */
13145#define TOK_CONDITIONAL tok_decl(4,0)
13146#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13147
13148#define TOK_OR tok_decl(5,0)
13149
13150#define TOK_AND tok_decl(6,0)
13151
13152#define TOK_BOR tok_decl(7,0)
13153
13154#define TOK_BXOR tok_decl(8,0)
13155
13156#define TOK_BAND tok_decl(9,0)
13157
13158#define TOK_EQ tok_decl(10,0)
13159#define TOK_NE tok_decl(10,1)
13160
13161#define TOK_LT tok_decl(11,0)
13162#define TOK_GT tok_decl(11,1)
13163#define TOK_GE tok_decl(11,2)
13164#define TOK_LE tok_decl(11,3)
13165
13166#define TOK_LSHIFT tok_decl(12,0)
13167#define TOK_RSHIFT tok_decl(12,1)
13168
13169#define TOK_ADD tok_decl(13,0)
13170#define TOK_SUB tok_decl(13,1)
13171
13172#define TOK_MUL tok_decl(14,0)
13173#define TOK_DIV tok_decl(14,1)
13174#define TOK_REM tok_decl(14,2)
13175
13176/* exponent is right associativity */
13177#define TOK_EXPONENT tok_decl(15,1)
13178
13179/* For now unary operators. */
13180#define UNARYPREC 16
13181#define TOK_BNOT tok_decl(UNARYPREC,0)
13182#define TOK_NOT tok_decl(UNARYPREC,1)
13183
13184#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13185#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13186
13187#define PREC_PRE (UNARYPREC+2)
13188
13189#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13190#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13191
13192#define PREC_POST (UNARYPREC+3)
13193
13194#define TOK_POST_INC tok_decl(PREC_POST, 0)
13195#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13196
13197#define SPEC_PREC (UNARYPREC+4)
13198
13199#define TOK_NUM tok_decl(SPEC_PREC, 0)
13200#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13201
13202#define NUMPTR (*numstackptr)
13203
13204static inline int tok_have_assign(operator op)
13205{
13206 operator prec = PREC(op);
13207
13208 convert_prec_is_assing(prec);
13209 return (prec == PREC(TOK_ASSIGN) ||
13210 prec == PREC_PRE || prec == PREC_POST);
13211}
13212
13213static inline int is_right_associativity(operator prec)
13214{
13215 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13216 prec == PREC(TOK_CONDITIONAL));
13217}
13218
13219
13220typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013221 arith_t val;
13222 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013223 char contidional_second_val_initialized;
13224 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013225 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013226} v_n_t;
13227
13228
13229typedef struct CHK_VAR_RECURSIVE_LOOPED {
13230 const char *var;
13231 struct CHK_VAR_RECURSIVE_LOOPED *next;
13232} chk_var_recursive_looped_t;
13233
13234static chk_var_recursive_looped_t *prev_chk_var_recursive;
13235
13236
13237static int arith_lookup_val(v_n_t *t)
13238{
13239 if(t->var) {
13240 const char * p = lookupvar(t->var);
13241
13242 if(p) {
13243 int errcode;
13244
13245 /* recursive try as expression */
13246 chk_var_recursive_looped_t *cur;
13247 chk_var_recursive_looped_t cur_save;
13248
13249 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13250 if(strcmp(cur->var, t->var) == 0) {
13251 /* expression recursion loop detected */
13252 return -5;
13253 }
13254 }
13255 /* save current lookuped var name */
13256 cur = prev_chk_var_recursive;
13257 cur_save.var = t->var;
13258 cur_save.next = cur;
13259 prev_chk_var_recursive = &cur_save;
13260
13261 t->val = arith (p, &errcode);
13262 /* restore previous ptr after recursiving */
13263 prev_chk_var_recursive = cur;
13264 return errcode;
13265 } else {
13266 /* allow undefined var as 0 */
13267 t->val = 0;
13268 }
13269 }
13270 return 0;
13271}
13272
13273/* "applying" a token means performing it on the top elements on the integer
13274 * stack. For a unary operator it will only change the top element, but a
13275 * binary operator will pop two arguments and push a result */
13276static inline int
13277arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13278{
Eric Andersen90898442003-08-06 11:20:52 +000013279 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013280 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013281 int ret_arith_lookup_val;
13282
13283 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13284 without arguments */
13285 numptr_m1 = NUMPTR - 1;
13286
13287 /* check operand is var with noninteger value */
13288 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13289 if(ret_arith_lookup_val)
13290 return ret_arith_lookup_val;
13291
13292 rez = numptr_m1->val;
13293 if (op == TOK_UMINUS)
13294 rez *= -1;
13295 else if (op == TOK_NOT)
13296 rez = !rez;
13297 else if (op == TOK_BNOT)
13298 rez = ~rez;
13299 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13300 rez++;
13301 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13302 rez--;
13303 else if (op != TOK_UPLUS) {
13304 /* Binary operators */
13305
13306 /* check and binary operators need two arguments */
13307 if (numptr_m1 == numstack) goto err;
13308
13309 /* ... and they pop one */
13310 --NUMPTR;
13311 numptr_val = rez;
13312 if (op == TOK_CONDITIONAL) {
13313 if(! numptr_m1->contidional_second_val_initialized) {
13314 /* protect $((expr1 ? expr2)) without ": expr" */
13315 goto err;
13316 }
13317 rez = numptr_m1->contidional_second_val;
13318 } else if(numptr_m1->contidional_second_val_initialized) {
13319 /* protect $((expr1 : expr2)) without "expr ? " */
13320 goto err;
13321 }
13322 numptr_m1 = NUMPTR - 1;
13323 if(op != TOK_ASSIGN) {
13324 /* check operand is var with noninteger value for not '=' */
13325 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13326 if(ret_arith_lookup_val)
13327 return ret_arith_lookup_val;
13328 }
13329 if (op == TOK_CONDITIONAL) {
13330 numptr_m1->contidional_second_val = rez;
13331 }
13332 rez = numptr_m1->val;
13333 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13334 rez |= numptr_val;
13335 else if (op == TOK_OR)
13336 rez = numptr_val || rez;
13337 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13338 rez &= numptr_val;
13339 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13340 rez ^= numptr_val;
13341 else if (op == TOK_AND)
13342 rez = rez && numptr_val;
13343 else if (op == TOK_EQ)
13344 rez = (rez == numptr_val);
13345 else if (op == TOK_NE)
13346 rez = (rez != numptr_val);
13347 else if (op == TOK_GE)
13348 rez = (rez >= numptr_val);
13349 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13350 rez >>= numptr_val;
13351 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13352 rez <<= numptr_val;
13353 else if (op == TOK_GT)
13354 rez = (rez > numptr_val);
13355 else if (op == TOK_LT)
13356 rez = (rez < numptr_val);
13357 else if (op == TOK_LE)
13358 rez = (rez <= numptr_val);
13359 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13360 rez *= numptr_val;
13361 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13362 rez += numptr_val;
13363 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13364 rez -= numptr_val;
13365 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13366 rez = numptr_val;
13367 else if (op == TOK_CONDITIONAL_SEP) {
13368 if (numptr_m1 == numstack) {
13369 /* protect $((expr : expr)) without "expr ? " */
13370 goto err;
13371 }
13372 numptr_m1->contidional_second_val_initialized = op;
13373 numptr_m1->contidional_second_val = numptr_val;
13374 }
13375 else if (op == TOK_CONDITIONAL) {
13376 rez = rez ?
13377 numptr_val : numptr_m1->contidional_second_val;
13378 }
13379 else if(op == TOK_EXPONENT) {
13380 if(numptr_val < 0)
13381 return -3; /* exponent less than 0 */
13382 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013383 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013384
13385 if(numptr_val)
13386 while(numptr_val--)
13387 c *= rez;
13388 rez = c;
13389 }
13390 }
13391 else if(numptr_val==0) /* zero divisor check */
13392 return -2;
13393 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13394 rez /= numptr_val;
13395 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13396 rez %= numptr_val;
13397 }
13398 if(tok_have_assign(op)) {
13399 char buf[32];
13400
13401 if(numptr_m1->var == NULL) {
13402 /* Hmm, 1=2 ? */
13403 goto err;
13404 }
13405 /* save to shell variable */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013406#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersena68ea1c2006-01-30 22:48:39 +000013407 snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013408#else
Eric Andersena68ea1c2006-01-30 22:48:39 +000013409 snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013410#endif
Eric Andersen90898442003-08-06 11:20:52 +000013411 setvar(numptr_m1->var, buf, 0);
13412 /* after saving, make previous value for v++ or v-- */
13413 if(op == TOK_POST_INC)
13414 rez--;
13415 else if(op == TOK_POST_DEC)
13416 rez++;
13417 }
13418 numptr_m1->val = rez;
13419 /* protect geting var value, is number now */
13420 numptr_m1->var = NULL;
13421 return 0;
13422err: return(-1);
13423}
13424
13425/* longest must first */
13426static const char op_tokens[] = {
13427 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13428 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13429 '<','<', 0, TOK_LSHIFT,
13430 '>','>', 0, TOK_RSHIFT,
13431 '|','|', 0, TOK_OR,
13432 '&','&', 0, TOK_AND,
13433 '!','=', 0, TOK_NE,
13434 '<','=', 0, TOK_LE,
13435 '>','=', 0, TOK_GE,
13436 '=','=', 0, TOK_EQ,
13437 '|','=', 0, TOK_OR_ASSIGN,
13438 '&','=', 0, TOK_AND_ASSIGN,
13439 '*','=', 0, TOK_MUL_ASSIGN,
13440 '/','=', 0, TOK_DIV_ASSIGN,
13441 '%','=', 0, TOK_REM_ASSIGN,
13442 '+','=', 0, TOK_PLUS_ASSIGN,
13443 '-','=', 0, TOK_MINUS_ASSIGN,
13444 '-','-', 0, TOK_POST_DEC,
13445 '^','=', 0, TOK_XOR_ASSIGN,
13446 '+','+', 0, TOK_POST_INC,
13447 '*','*', 0, TOK_EXPONENT,
13448 '!', 0, TOK_NOT,
13449 '<', 0, TOK_LT,
13450 '>', 0, TOK_GT,
13451 '=', 0, TOK_ASSIGN,
13452 '|', 0, TOK_BOR,
13453 '&', 0, TOK_BAND,
13454 '*', 0, TOK_MUL,
13455 '/', 0, TOK_DIV,
13456 '%', 0, TOK_REM,
13457 '+', 0, TOK_ADD,
13458 '-', 0, TOK_SUB,
13459 '^', 0, TOK_BXOR,
13460 /* uniq */
13461 '~', 0, TOK_BNOT,
13462 ',', 0, TOK_COMMA,
13463 '?', 0, TOK_CONDITIONAL,
13464 ':', 0, TOK_CONDITIONAL_SEP,
13465 ')', 0, TOK_RPAREN,
13466 '(', 0, TOK_LPAREN,
13467 0
13468};
13469/* ptr to ")" */
13470#define endexpression &op_tokens[sizeof(op_tokens)-7]
13471
13472
Eric Andersened9ecf72004-06-22 08:29:45 +000013473static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013474{
13475 register char arithval; /* Current character under analysis */
13476 operator lasttok, op;
13477 operator prec;
13478
13479 const char *p = endexpression;
13480 int errcode;
13481
13482 size_t datasizes = strlen(expr) + 2;
13483
13484 /* Stack of integers */
13485 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013486 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013487 * the reader. */
13488 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13489 *numstackptr = numstack;
13490 /* Stack of operator tokens */
13491 operator *stack = alloca((datasizes) * sizeof(operator)),
13492 *stackptr = stack;
13493
13494 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13495 *perrcode = errcode = 0;
13496
13497 while(1) {
13498 if ((arithval = *expr) == 0) {
13499 if (p == endexpression) {
13500 /* Null expression. */
13501 return 0;
13502 }
13503
13504 /* This is only reached after all tokens have been extracted from the
13505 * input stream. If there are still tokens on the operator stack, they
13506 * are to be applied in order. At the end, there should be a final
13507 * result on the integer stack */
13508
13509 if (expr != endexpression + 1) {
13510 /* If we haven't done so already, */
13511 /* append a closing right paren */
13512 expr = endexpression;
13513 /* and let the loop process it. */
13514 continue;
13515 }
13516 /* At this point, we're done with the expression. */
13517 if (numstackptr != numstack+1) {
13518 /* ... but if there isn't, it's bad */
13519 err:
13520 return (*perrcode = -1);
13521 }
13522 if(numstack->var) {
13523 /* expression is $((var)) only, lookup now */
13524 errcode = arith_lookup_val(numstack);
13525 }
13526 ret:
13527 *perrcode = errcode;
13528 return numstack->val;
13529 } else {
13530 /* Continue processing the expression. */
13531 if (arith_isspace(arithval)) {
13532 /* Skip whitespace */
13533 goto prologue;
13534 }
13535 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013536 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013537
13538 numstackptr->var = alloca(var_name_size);
13539 safe_strncpy(numstackptr->var, expr, var_name_size);
13540 expr = p;
13541 num:
13542 numstackptr->contidional_second_val_initialized = 0;
13543 numstackptr++;
13544 lasttok = TOK_NUM;
13545 continue;
13546 } else if (is_digit(arithval)) {
13547 numstackptr->var = NULL;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013548#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersenad63cb22004-10-08 09:43:34 +000013549 numstackptr->val = strtoll(expr, (char **) &expr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013550#else
13551 numstackptr->val = strtol(expr, (char **) &expr, 0);
13552#endif
Eric Andersen90898442003-08-06 11:20:52 +000013553 goto num;
13554 }
13555 for(p = op_tokens; ; p++) {
13556 const char *o;
13557
13558 if(*p == 0) {
13559 /* strange operator not found */
13560 goto err;
13561 }
13562 for(o = expr; *p && *o == *p; p++)
13563 o++;
13564 if(! *p) {
13565 /* found */
13566 expr = o - 1;
13567 break;
13568 }
13569 /* skip tail uncompared token */
13570 while(*p)
13571 p++;
13572 /* skip zero delim */
13573 p++;
13574 }
13575 op = p[1];
13576
13577 /* post grammar: a++ reduce to num */
13578 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13579 lasttok = TOK_NUM;
13580
13581 /* Plus and minus are binary (not unary) _only_ if the last
13582 * token was as number, or a right paren (which pretends to be
13583 * a number, since it evaluates to one). Think about it.
13584 * It makes sense. */
13585 if (lasttok != TOK_NUM) {
13586 switch(op) {
13587 case TOK_ADD:
13588 op = TOK_UPLUS;
13589 break;
13590 case TOK_SUB:
13591 op = TOK_UMINUS;
13592 break;
13593 case TOK_POST_INC:
13594 op = TOK_PRE_INC;
13595 break;
13596 case TOK_POST_DEC:
13597 op = TOK_PRE_DEC;
13598 break;
13599 }
13600 }
13601 /* We don't want a unary operator to cause recursive descent on the
13602 * stack, because there can be many in a row and it could cause an
13603 * operator to be evaluated before its argument is pushed onto the
13604 * integer stack. */
13605 /* But for binary operators, "apply" everything on the operator
13606 * stack until we find an operator with a lesser priority than the
13607 * one we have just extracted. */
13608 /* Left paren is given the lowest priority so it will never be
13609 * "applied" in this way.
13610 * if associativity is right and priority eq, applied also skip
13611 */
13612 prec = PREC(op);
13613 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13614 /* not left paren or unary */
13615 if (lasttok != TOK_NUM) {
13616 /* binary op must be preceded by a num */
13617 goto err;
13618 }
13619 while (stackptr != stack) {
13620 if (op == TOK_RPAREN) {
13621 /* The algorithm employed here is simple: while we don't
13622 * hit an open paren nor the bottom of the stack, pop
13623 * tokens and apply them */
13624 if (stackptr[-1] == TOK_LPAREN) {
13625 --stackptr;
13626 /* Any operator directly after a */
13627 lasttok = TOK_NUM;
13628 /* close paren should consider itself binary */
13629 goto prologue;
13630 }
13631 } else {
13632 operator prev_prec = PREC(stackptr[-1]);
13633
13634 convert_prec_is_assing(prec);
13635 convert_prec_is_assing(prev_prec);
13636 if (prev_prec < prec)
13637 break;
13638 /* check right assoc */
13639 if(prev_prec == prec && is_right_associativity(prec))
13640 break;
13641 }
13642 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13643 if(errcode) goto ret;
13644 }
13645 if (op == TOK_RPAREN) {
13646 goto err;
13647 }
13648 }
13649
13650 /* Push this operator to the stack and remember it. */
13651 *stackptr++ = lasttok = op;
13652
13653 prologue:
13654 ++expr;
13655 }
13656 }
13657}
13658#endif /* CONFIG_ASH_MATH_SUPPORT */
13659
13660
Eric Andersenc470f442003-07-28 09:56:35 +000013661#ifdef DEBUG
13662const char *bb_applet_name = "debug stuff usage";
13663int main(int argc, char **argv)
13664{
13665 return ash_main(argc, argv);
13666}
13667#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013668
Eric Andersendf82f612001-06-28 07:46:40 +000013669/*-
13670 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013671 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013672 *
13673 * This code is derived from software contributed to Berkeley by
13674 * Kenneth Almquist.
13675 *
13676 * Redistribution and use in source and binary forms, with or without
13677 * modification, are permitted provided that the following conditions
13678 * are met:
13679 * 1. Redistributions of source code must retain the above copyright
13680 * notice, this list of conditions and the following disclaimer.
13681 * 2. Redistributions in binary form must reproduce the above copyright
13682 * notice, this list of conditions and the following disclaimer in the
13683 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013684 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013685 * may be used to endorse or promote products derived from this software
13686 * without specific prior written permission.
13687 *
13688 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13689 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13690 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13691 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13692 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13693 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13694 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13695 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13696 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13697 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13698 * SUCH DAMAGE.
13699 */