blob: 754c1d72b6997b4a3a50540afb7f462f1b3fba9b [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
Bernhard Reutner-Fischer35492132006-06-21 18:19:53 +00001315/* make sure to keep these in proper order since it is searched via bsearch() */
Eric Andersenc470f442003-07-28 09:56:35 +00001316static const struct builtincmd builtincmd[] = {
1317 { BUILTIN_SPEC_REG ".", dotcmd },
1318 { BUILTIN_SPEC_REG ":", truecmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001319#ifdef CONFIG_ASH_BUILTIN_TEST
1320 { BUILTIN_REGULAR "[", testcmd },
1321 { BUILTIN_REGULAR "[[", testcmd },
1322#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001323#ifdef CONFIG_ASH_ALIAS
1324 { BUILTIN_REG_ASSG "alias", aliascmd },
1325#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001326#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001327 { BUILTIN_REGULAR "bg", bgcmd },
1328#endif
1329 { BUILTIN_SPEC_REG "break", breakcmd },
1330 { BUILTIN_REGULAR "cd", cdcmd },
1331 { BUILTIN_NOSPEC "chdir", cdcmd },
1332#ifdef CONFIG_ASH_CMDCMD
1333 { BUILTIN_REGULAR "command", commandcmd },
1334#endif
1335 { BUILTIN_SPEC_REG "continue", breakcmd },
Paul Fox0b621582005-08-09 19:38:05 +00001336#ifdef CONFIG_ASH_BUILTIN_ECHO
1337 { BUILTIN_REGULAR "echo", echocmd },
1338#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001339 { BUILTIN_SPEC_REG "eval", evalcmd },
1340 { BUILTIN_SPEC_REG "exec", execcmd },
1341 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001342 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1343 { BUILTIN_REGULAR "false", falsecmd },
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001344#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001345 { BUILTIN_REGULAR "fg", fgcmd },
1346#endif
1347#ifdef CONFIG_ASH_GETOPTS
1348 { BUILTIN_REGULAR "getopts", getoptscmd },
1349#endif
1350 { BUILTIN_NOSPEC "hash", hashcmd },
1351#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1352 { BUILTIN_NOSPEC "help", helpcmd },
1353#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001354#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001355 { BUILTIN_REGULAR "jobs", jobscmd },
1356 { BUILTIN_REGULAR "kill", killcmd },
1357#endif
1358#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001359 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001360#endif
1361 { BUILTIN_ASSIGN "local", localcmd },
1362 { BUILTIN_NOSPEC "pwd", pwdcmd },
1363 { BUILTIN_REGULAR "read", readcmd },
1364 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1365 { BUILTIN_SPEC_REG "return", returncmd },
1366 { BUILTIN_SPEC_REG "set", setcmd },
1367 { BUILTIN_SPEC_REG "shift", shiftcmd },
Mike Frysingerc2ad4f52006-06-21 18:04:49 +00001368 { BUILTIN_SPEC_REG "source", dotcmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001369#ifdef CONFIG_ASH_BUILTIN_TEST
1370 { BUILTIN_REGULAR "test", testcmd },
1371#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001372 { BUILTIN_SPEC_REG "times", timescmd },
1373 { BUILTIN_SPEC_REG "trap", trapcmd },
1374 { BUILTIN_REGULAR "true", truecmd },
1375 { BUILTIN_NOSPEC "type", typecmd },
1376 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1377 { BUILTIN_REGULAR "umask", umaskcmd },
1378#ifdef CONFIG_ASH_ALIAS
1379 { BUILTIN_REGULAR "unalias", unaliascmd },
1380#endif
1381 { BUILTIN_SPEC_REG "unset", unsetcmd },
1382 { BUILTIN_REGULAR "wait", waitcmd },
1383};
1384
1385#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1386
1387
1388
1389struct cmdentry {
1390 int cmdtype;
1391 union param {
1392 int index;
1393 const struct builtincmd *cmd;
1394 struct funcnode *func;
1395 } u;
1396};
1397
1398
1399/* action to find_command() */
1400#define DO_ERR 0x01 /* prints errors */
1401#define DO_ABS 0x02 /* checks absolute paths */
1402#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1403#define DO_ALTPATH 0x08 /* using alternate path */
1404#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1405
1406static const char *pathopt; /* set by padvance */
1407
1408static void shellexec(char **, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001409 ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00001410static char *padvance(const char **, const char *);
1411static void find_command(char *, struct cmdentry *, int, const char *);
1412static struct builtincmd *find_builtin(const char *);
1413static void hashcd(void);
1414static void changepath(const char *);
1415static void defun(char *, union node *);
1416static void unsetfunc(const char *);
1417
Eric Andersened9ecf72004-06-22 08:29:45 +00001418#ifdef CONFIG_ASH_MATH_SUPPORT_64
1419typedef int64_t arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001420#define arith_t_type (long long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001421#else
1422typedef long arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001423#define arith_t_type (long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001424#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001425
1426#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001427static arith_t dash_arith(const char *);
1428static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001429#endif
1430
Eric Andersen16767e22004-03-16 05:14:10 +00001431#ifdef CONFIG_ASH_RANDOM_SUPPORT
1432static unsigned long rseed;
1433static void change_random(const char *);
1434# ifndef DYNAMIC_VAR
1435# define DYNAMIC_VAR
1436# endif
1437#endif
1438
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001439/* init.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001440
1441static void reset(void);
1442
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001443/* var.h */
Eric Andersen2870d962001-07-02 17:27:21 +00001444
1445/*
1446 * Shell variables.
1447 */
1448
1449/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001450#define VEXPORT 0x01 /* variable is exported */
1451#define VREADONLY 0x02 /* variable cannot be modified */
1452#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1453#define VTEXTFIXED 0x08 /* text is statically allocated */
1454#define VSTACK 0x10 /* text is allocated on the stack */
1455#define VUNSET 0x20 /* the variable is not set */
1456#define VNOFUNC 0x40 /* don't call the callback function */
1457#define VNOSET 0x80 /* do not set variable - just readonly test */
1458#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001459#ifdef DYNAMIC_VAR
1460# define VDYNAMIC 0x200 /* dynamic variable */
1461# else
1462# define VDYNAMIC 0
1463#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001464
1465struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001466 struct var *next; /* next entry in hash list */
1467 int flags; /* flags are defined above */
1468 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001469 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001470 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001471};
1472
1473struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001474 struct localvar *next; /* next local variable in list */
1475 struct var *vp; /* the variable that was made local */
1476 int flags; /* saved flags */
1477 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001478};
1479
1480
Eric Andersen2870d962001-07-02 17:27:21 +00001481static struct localvar *localvars;
1482
Eric Andersenc470f442003-07-28 09:56:35 +00001483/*
1484 * Shell variables.
1485 */
1486
1487#ifdef CONFIG_ASH_GETOPTS
1488static void getoptsreset(const char *);
1489#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001490
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001491#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001492#include <locale.h>
1493static void change_lc_all(const char *value);
1494static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001495#endif
1496
Eric Andersenef02f822004-03-11 13:34:24 +00001497
Eric Andersen2870d962001-07-02 17:27:21 +00001498#define VTABSIZE 39
1499
Eric Andersen90898442003-08-06 11:20:52 +00001500static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001501#ifdef IFS_BROKEN
1502static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001503#define defifs (defifsvar + 4)
1504#else
Eric Andersenc470f442003-07-28 09:56:35 +00001505static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001506#endif
1507
Eric Andersenc470f442003-07-28 09:56:35 +00001508
1509static struct var varinit[] = {
1510#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001511 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001512#else
Eric Andersen16767e22004-03-16 05:14:10 +00001513 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001514#endif
1515
1516#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001517 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1518 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001519#endif
1520
Eric Andersen16767e22004-03-16 05:14:10 +00001521 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1522 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1523 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1524 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001525#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001526 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1527#endif
1528#ifdef CONFIG_ASH_RANDOM_SUPPORT
1529 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001530#endif
1531#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001532 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1533 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001534#endif
1535#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001536 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001537#endif
1538};
1539
1540#define vifs varinit[0]
1541#ifdef CONFIG_ASH_MAIL
1542#define vmail (&vifs)[1]
1543#define vmpath (&vmail)[1]
1544#else
1545#define vmpath vifs
1546#endif
1547#define vpath (&vmpath)[1]
1548#define vps1 (&vpath)[1]
1549#define vps2 (&vps1)[1]
1550#define vps4 (&vps2)[1]
1551#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001552#ifdef CONFIG_ASH_GETOPTS
1553#define vrandom (&voptind)[1]
1554#else
1555#define vrandom (&vps4)[1]
1556#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001557#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001558
1559/*
1560 * The following macros access the values of the above variables.
1561 * They have to skip over the name. They return the null string
1562 * for unset variables.
1563 */
1564
1565#define ifsval() (vifs.text + 4)
1566#define ifsset() ((vifs.flags & VUNSET) == 0)
1567#define mailval() (vmail.text + 5)
1568#define mpathval() (vmpath.text + 9)
1569#define pathval() (vpath.text + 5)
1570#define ps1val() (vps1.text + 4)
1571#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001572#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001573#define optindval() (voptind.text + 7)
1574
1575#define mpathset() ((vmpath.flags & VUNSET) == 0)
1576
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001577static void setvar(const char *, const char *, int);
1578static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001579static void listsetvar(struct strlist *, int);
1580static char *lookupvar(const char *);
1581static char *bltinlookup(const char *);
1582static char **listvars(int, int, char ***);
1583#define environment() listvars(VEXPORT, VUNSET, 0)
1584static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001585static void poplocalvars(void);
1586static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001587#ifdef CONFIG_ASH_GETOPTS
1588static int setvarsafe(const char *, const char *, int);
1589#endif
1590static int varcmp(const char *, const char *);
1591static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001592
1593
Rob Landley88621d72006-08-29 19:41:06 +00001594static int varequal(const char *a, const char *b) {
Eric Andersenc470f442003-07-28 09:56:35 +00001595 return !varcmp(a, b);
1596}
Eric Andersen2870d962001-07-02 17:27:21 +00001597
1598
Eric Andersenc470f442003-07-28 09:56:35 +00001599static int loopnest; /* current loop nesting level */
1600
Eric Andersenc470f442003-07-28 09:56:35 +00001601/*
1602 * The parsefile structure pointed to by the global variable parsefile
1603 * contains information about the current file being read.
1604 */
1605
1606
1607struct redirtab {
1608 struct redirtab *next;
1609 int renamed[10];
1610 int nullredirs;
1611};
1612
1613static struct redirtab *redirlist;
1614static int nullredirs;
1615
1616extern char **environ;
1617
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001618/* output.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001619
1620
1621static void outstr(const char *, FILE *);
1622static void outcslow(int, FILE *);
1623static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001624static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001625static int out1fmt(const char *, ...)
1626 __attribute__((__format__(__printf__,1,2)));
1627static int fmtstr(char *, size_t, const char *, ...)
1628 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001629
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001630static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001631
Eric Andersenc470f442003-07-28 09:56:35 +00001632
1633static void out1str(const char *p)
1634{
1635 outstr(p, stdout);
1636}
1637
1638static void out2str(const char *p)
1639{
1640 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001641 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001642}
1643
1644/*
1645 * Initialization code.
1646 */
1647
1648/*
1649 * This routine initializes the builtin variables.
1650 */
1651
Rob Landley88621d72006-08-29 19:41:06 +00001652static void initvar(void)
Eric Andersenc470f442003-07-28 09:56:35 +00001653{
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
Rob Landley88621d72006-08-29 19:41:06 +00001676static void init(void)
Eric Andersenc470f442003-07-28 09:56:35 +00001677{
1678
1679 /* from input.c: */
1680 {
1681 basepf.nextc = basepf.buf = basebuf;
1682 }
1683
1684 /* from trap.c: */
1685 {
1686 signal(SIGCHLD, SIG_DFL);
1687 }
1688
1689 /* from var.c: */
1690 {
1691 char **envp;
1692 char ppid[32];
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001693 const char *p;
1694 struct stat st1, st2;
Eric Andersenc470f442003-07-28 09:56:35 +00001695
1696 initvar();
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001697 for (envp = environ ; envp && *envp ; envp++) {
Eric Andersenc470f442003-07-28 09:56:35 +00001698 if (strchr(*envp, '=')) {
1699 setvareq(*envp, VEXPORT|VTEXTFIXED);
1700 }
1701 }
1702
1703 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1704 setvar("PPID", ppid, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001705
1706 p = lookupvar("PWD");
1707 if (p)
1708 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1709 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1710 p = 0;
1711 setpwd(p, 0);
Eric Andersenc470f442003-07-28 09:56:35 +00001712 }
1713}
1714
1715/* PEOF (the end of file marker) */
1716
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001717enum {
1718 INPUT_PUSH_FILE = 1,
1719 INPUT_NOFILE_OK = 2,
1720};
1721
Eric Andersenc470f442003-07-28 09:56:35 +00001722/*
1723 * The input line number. Input.c just defines this variable, and saves
1724 * and restores it when files are pushed and popped. The user of this
1725 * package must set its value.
1726 */
1727
1728static int pgetc(void);
1729static int pgetc2(void);
1730static int preadbuffer(void);
1731static void pungetc(void);
1732static void pushstring(char *, void *);
1733static void popstring(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001734static void setinputfd(int, int);
1735static void setinputstring(char *);
1736static void popfile(void);
1737static void popallfiles(void);
1738static void closescript(void);
1739
1740
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001741/* jobs.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001742
1743
1744/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1745#define FORK_FG 0
1746#define FORK_BG 1
1747#define FORK_NOJOB 2
1748
1749/* mode flags for showjob(s) */
1750#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1751#define SHOW_PID 0x04 /* include process pid */
1752#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1753
1754
1755/*
1756 * A job structure contains information about a job. A job is either a
1757 * single process or a set of processes contained in a pipeline. In the
1758 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1759 * array of pids.
1760 */
1761
1762struct procstat {
1763 pid_t pid; /* process id */
1764 int status; /* last process status from wait() */
1765 char *cmd; /* text of command being run */
1766};
1767
1768struct job {
1769 struct procstat ps0; /* status of process */
1770 struct procstat *ps; /* status or processes when more than one */
1771#if JOBS
1772 int stopstatus; /* status of a stopped job */
1773#endif
1774 uint32_t
1775 nprocs: 16, /* number of processes */
1776 state: 8,
1777#define JOBRUNNING 0 /* at least one proc running */
1778#define JOBSTOPPED 1 /* all procs are stopped */
1779#define JOBDONE 2 /* all procs are completed */
1780#if JOBS
1781 sigint: 1, /* job was killed by SIGINT */
1782 jobctl: 1, /* job running under job control */
1783#endif
1784 waited: 1, /* true if this entry has been waited for */
1785 used: 1, /* true if this entry is in used */
1786 changed: 1; /* true if status has changed */
1787 struct job *prev_job; /* previous job */
1788};
1789
1790static pid_t backgndpid; /* pid of last background process */
1791static int job_warning; /* user was warned about stopped jobs */
1792#if JOBS
1793static int jobctl; /* true if doing job control */
1794#endif
1795
1796static struct job *makejob(union node *, int);
1797static int forkshell(struct job *, union node *, int);
1798static int waitforjob(struct job *);
1799static int stoppedjobs(void);
1800
1801#if ! JOBS
1802#define setjobctl(on) /* do nothing */
1803#else
1804static void setjobctl(int);
1805static void showjobs(FILE *, int);
1806#endif
1807
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001808/* main.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001809
1810
1811/* pid of main shell */
1812static int rootpid;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001813/* shell level: 0 for the main shell, 1 for its children, and so on */
1814static int shlvl;
1815#define rootshell (!shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00001816
1817static void readcmdfile(char *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001818static int cmdloop(int);
Eric Andersenc470f442003-07-28 09:56:35 +00001819
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001820/* memalloc.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001821
1822
1823struct stackmark {
1824 struct stack_block *stackp;
1825 char *stacknxt;
1826 size_t stacknleft;
1827 struct stackmark *marknext;
1828};
1829
1830/* minimum size of a block */
1831#define MINSIZE SHELL_ALIGN(504)
1832
1833struct stack_block {
1834 struct stack_block *prev;
1835 char space[MINSIZE];
1836};
1837
1838static struct stack_block stackbase;
1839static struct stack_block *stackp = &stackbase;
1840static struct stackmark *markp;
1841static char *stacknxt = stackbase.space;
1842static size_t stacknleft = MINSIZE;
1843static char *sstrend = stackbase.space + MINSIZE;
1844static int herefd = -1;
1845
1846
1847static pointer ckmalloc(size_t);
1848static pointer ckrealloc(pointer, size_t);
1849static char *savestr(const char *);
1850static pointer stalloc(size_t);
1851static void stunalloc(pointer);
1852static void setstackmark(struct stackmark *);
1853static void popstackmark(struct stackmark *);
1854static void growstackblock(void);
1855static void *growstackstr(void);
1856static char *makestrspace(size_t, char *);
1857static char *stnputs(const char *, size_t, char *);
1858static char *stputs(const char *, char *);
1859
1860
Rob Landley88621d72006-08-29 19:41:06 +00001861static char *_STPUTC(int c, char *p) {
Eric Andersenc470f442003-07-28 09:56:35 +00001862 if (p == sstrend)
1863 p = growstackstr();
1864 *p++ = c;
1865 return p;
1866}
1867
1868#define stackblock() ((void *)stacknxt)
1869#define stackblocksize() stacknleft
1870#define STARTSTACKSTR(p) ((p) = stackblock())
1871#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1872#define CHECKSTRSPACE(n, p) \
1873 ({ \
1874 char *q = (p); \
1875 size_t l = (n); \
1876 size_t m = sstrend - q; \
1877 if (l > m) \
1878 (p) = makestrspace(l, q); \
1879 0; \
1880 })
1881#define USTPUTC(c, p) (*p++ = (c))
1882#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1883#define STUNPUTC(p) (--p)
1884#define STTOPC(p) p[-1]
1885#define STADJUST(amount, p) (p += (amount))
1886
1887#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1888#define ungrabstackstr(s, p) stunalloc((s))
1889#define stackstrend() ((void *)sstrend)
1890
1891#define ckfree(p) free((pointer)(p))
1892
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001893/* mystring.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001894
1895
1896#define DOLATSTRLEN 4
1897
1898static char *prefix(const char *, const char *);
1899static int number(const char *);
1900static int is_number(const char *);
1901static char *single_quote(const char *);
1902static char *sstrdup(const char *);
1903
1904#define equal(s1, s2) (strcmp(s1, s2) == 0)
1905#define scopy(s1, s2) ((void)strcpy(s2, s1))
1906
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001907/* options.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001908
1909struct shparam {
1910 int nparam; /* # of positional parameters (without $0) */
1911 unsigned char malloc; /* if parameter list dynamically allocated */
1912 char **p; /* parameter list */
1913#ifdef CONFIG_ASH_GETOPTS
1914 int optind; /* next parameter to be processed by getopts */
1915 int optoff; /* used by getopts */
1916#endif
1917};
1918
1919
1920#define eflag optlist[0]
1921#define fflag optlist[1]
1922#define Iflag optlist[2]
1923#define iflag optlist[3]
1924#define mflag optlist[4]
1925#define nflag optlist[5]
1926#define sflag optlist[6]
1927#define xflag optlist[7]
1928#define vflag optlist[8]
1929#define Cflag optlist[9]
1930#define aflag optlist[10]
1931#define bflag optlist[11]
1932#define uflag optlist[12]
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001933#define viflag optlist[13]
Eric Andersenc470f442003-07-28 09:56:35 +00001934
1935#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001936#define nolog optlist[14]
1937#define debug optlist[15]
Paul Fox3f11b1b2005-08-04 19:04:46 +00001938#endif
1939
1940#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1941#define setvimode(on) viflag = 0 /* forcibly keep the option off */
Eric Andersenc470f442003-07-28 09:56:35 +00001942#endif
1943
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001944/* options.c */
Eric Andersenc470f442003-07-28 09:56:35 +00001945
1946
Paul Fox3f11b1b2005-08-04 19:04:46 +00001947static const char *const optletters_optnames[] = {
Eric Andersenc470f442003-07-28 09:56:35 +00001948 "e" "errexit",
1949 "f" "noglob",
1950 "I" "ignoreeof",
1951 "i" "interactive",
1952 "m" "monitor",
1953 "n" "noexec",
1954 "s" "stdin",
1955 "x" "xtrace",
1956 "v" "verbose",
1957 "C" "noclobber",
1958 "a" "allexport",
1959 "b" "notify",
1960 "u" "nounset",
Paul Fox3f11b1b2005-08-04 19:04:46 +00001961 "\0" "vi",
Eric Andersenc470f442003-07-28 09:56:35 +00001962#ifdef DEBUG
1963 "\0" "nolog",
1964 "\0" "debug",
1965#endif
1966};
1967
1968#define optletters(n) optletters_optnames[(n)][0]
1969#define optnames(n) (&optletters_optnames[(n)][1])
1970
Paul Fox3f11b1b2005-08-04 19:04:46 +00001971#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001972
1973static char optlist[NOPTS];
1974
1975
1976static char *arg0; /* value of $0 */
1977static struct shparam shellparam; /* $@ current positional parameters */
1978static char **argptr; /* argument list for builtin commands */
1979static char *optionarg; /* set by nextopt (like getopt) */
1980static char *optptr; /* used by nextopt */
1981
1982static char *minusc; /* argument to -c option */
1983
1984
1985static void procargs(int, char **);
1986static void optschanged(void);
1987static void setparam(char **);
1988static void freeparam(volatile struct shparam *);
1989static int shiftcmd(int, char **);
1990static int setcmd(int, char **);
1991static int nextopt(const char *);
1992
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001993/* redir.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001994
1995/* flags passed to redirect */
1996#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001997#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00001998
1999union node;
2000static void redirect(union node *, int);
2001static void popredir(int);
2002static void clearredir(int);
2003static int copyfd(int, int);
2004static int redirectsafe(union node *, int);
2005
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002006/* show.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002007
2008
2009#ifdef DEBUG
2010static void showtree(union node *);
2011static void trace(const char *, ...);
2012static void tracev(const char *, va_list);
2013static void trargs(char **);
2014static void trputc(int);
2015static void trputs(const char *);
2016static void opentrace(void);
2017#endif
2018
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002019/* trap.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002020
2021
2022/* trap handler commands */
2023static char *trap[NSIG];
2024/* current value of signal */
2025static char sigmode[NSIG - 1];
2026/* indicates specified signal received */
2027static char gotsig[NSIG - 1];
2028
2029static void clear_traps(void);
2030static void setsignal(int);
2031static void ignoresig(int);
2032static void onsig(int);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002033static int dotrap(void);
Eric Andersenc470f442003-07-28 09:56:35 +00002034static void setinteractive(int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002035static void exitshell(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00002036
2037/*
2038 * This routine is called when an error or an interrupt occurs in an
2039 * interactive shell and control is returned to the main command loop.
2040 */
2041
2042static void
2043reset(void)
2044{
2045 /* from eval.c: */
2046 {
2047 evalskip = 0;
2048 loopnest = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002049 }
2050
2051 /* from input.c: */
2052 {
2053 parselleft = parsenleft = 0; /* clear input buffer */
2054 popallfiles();
2055 }
2056
2057 /* from parser.c: */
2058 {
2059 tokpushback = 0;
2060 checkkwd = 0;
2061 }
2062
2063 /* from redir.c: */
2064 {
2065 clearredir(0);
2066 }
2067
2068}
2069
2070#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002071static struct alias *atab[ATABSIZE];
2072
Eric Andersenc470f442003-07-28 09:56:35 +00002073static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002074static struct alias *freealias(struct alias *);
2075static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002076
Eric Andersenc470f442003-07-28 09:56:35 +00002077static void
2078setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002079{
2080 struct alias *ap, **app;
2081
2082 app = __lookupalias(name);
2083 ap = *app;
2084 INTOFF;
2085 if (ap) {
2086 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002087 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002088 }
Eric Andersenc470f442003-07-28 09:56:35 +00002089 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002090 ap->flag &= ~ALIASDEAD;
2091 } else {
2092 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002093 ap = ckmalloc(sizeof (struct alias));
2094 ap->name = savestr(name);
2095 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002096 ap->flag = 0;
2097 ap->next = 0;
2098 *app = ap;
2099 }
2100 INTON;
2101}
2102
Eric Andersenc470f442003-07-28 09:56:35 +00002103static int
2104unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002105{
Eric Andersencb57d552001-06-28 07:25:16 +00002106 struct alias **app;
2107
2108 app = __lookupalias(name);
2109
2110 if (*app) {
2111 INTOFF;
2112 *app = freealias(*app);
2113 INTON;
2114 return (0);
2115 }
2116
2117 return (1);
2118}
2119
Eric Andersenc470f442003-07-28 09:56:35 +00002120static void
2121rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002122{
Eric Andersencb57d552001-06-28 07:25:16 +00002123 struct alias *ap, **app;
2124 int i;
2125
2126 INTOFF;
2127 for (i = 0; i < ATABSIZE; i++) {
2128 app = &atab[i];
2129 for (ap = *app; ap; ap = *app) {
2130 *app = freealias(*app);
2131 if (ap == *app) {
2132 app = &ap->next;
2133 }
2134 }
2135 }
2136 INTON;
2137}
2138
Eric Andersenc470f442003-07-28 09:56:35 +00002139static struct alias *
2140lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002141{
Eric Andersenc470f442003-07-28 09:56:35 +00002142 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002143
Eric Andersenc470f442003-07-28 09:56:35 +00002144 if (check && ap && (ap->flag & ALIASINUSE))
2145 return (NULL);
2146 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002147}
2148
Eric Andersencb57d552001-06-28 07:25:16 +00002149/*
2150 * TODO - sort output
2151 */
Eric Andersenc470f442003-07-28 09:56:35 +00002152static int
2153aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002154{
2155 char *n, *v;
2156 int ret = 0;
2157 struct alias *ap;
2158
2159 if (argc == 1) {
2160 int i;
2161
2162 for (i = 0; i < ATABSIZE; i++)
2163 for (ap = atab[i]; ap; ap = ap->next) {
2164 printalias(ap);
2165 }
2166 return (0);
2167 }
2168 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002169 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002170 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002171 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002172 ret = 1;
2173 } else
2174 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002175 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002176 *v++ = '\0';
2177 setalias(n, v);
2178 }
2179 }
2180
2181 return (ret);
2182}
2183
Eric Andersenc470f442003-07-28 09:56:35 +00002184static int
2185unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002186{
2187 int i;
2188
2189 while ((i = nextopt("a")) != '\0') {
2190 if (i == 'a') {
2191 rmaliases();
2192 return (0);
2193 }
2194 }
2195 for (i = 0; *argptr; argptr++) {
2196 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002197 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002198 i = 1;
2199 }
2200 }
2201
2202 return (i);
2203}
2204
Eric Andersenc470f442003-07-28 09:56:35 +00002205static struct alias *
2206freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002207 struct alias *next;
2208
2209 if (ap->flag & ALIASINUSE) {
2210 ap->flag |= ALIASDEAD;
2211 return ap;
2212 }
2213
2214 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002215 ckfree(ap->name);
2216 ckfree(ap->val);
2217 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002218 return next;
2219}
2220
Eric Andersenc470f442003-07-28 09:56:35 +00002221static void
2222printalias(const struct alias *ap) {
2223 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2224}
Eric Andersencb57d552001-06-28 07:25:16 +00002225
Eric Andersenc470f442003-07-28 09:56:35 +00002226static struct alias **
2227__lookupalias(const char *name) {
2228 unsigned int hashval;
2229 struct alias **app;
2230 const char *p;
2231 unsigned int ch;
2232
2233 p = name;
2234
2235 ch = (unsigned char)*p;
2236 hashval = ch << 4;
2237 while (ch) {
2238 hashval += ch;
2239 ch = (unsigned char)*++p;
2240 }
2241 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002242
2243 for (; *app; app = &(*app)->next) {
2244 if (equal(name, (*app)->name)) {
2245 break;
2246 }
2247 }
2248
2249 return app;
2250}
Eric Andersenc470f442003-07-28 09:56:35 +00002251#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002252
Eric Andersencb57d552001-06-28 07:25:16 +00002253
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002254/* cd.c */
Eric Andersen2870d962001-07-02 17:27:21 +00002255
Eric Andersencb57d552001-06-28 07:25:16 +00002256/*
Eric Andersenc470f442003-07-28 09:56:35 +00002257 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002258 */
2259
Eric Andersenc470f442003-07-28 09:56:35 +00002260#define CD_PHYSICAL 1
2261#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002262
Eric Andersenc470f442003-07-28 09:56:35 +00002263static int docd(const char *, int);
2264static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002265
Eric Andersenc470f442003-07-28 09:56:35 +00002266static char *curdir = nullstr; /* current working directory */
2267static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002268
Eric Andersenc470f442003-07-28 09:56:35 +00002269static int
2270cdopt(void)
2271{
2272 int flags = 0;
2273 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002274
Eric Andersenc470f442003-07-28 09:56:35 +00002275 j = 'L';
2276 while ((i = nextopt("LP"))) {
2277 if (i != j) {
2278 flags ^= CD_PHYSICAL;
2279 j = i;
2280 }
2281 }
Eric Andersencb57d552001-06-28 07:25:16 +00002282
Eric Andersenc470f442003-07-28 09:56:35 +00002283 return flags;
2284}
Eric Andersen2870d962001-07-02 17:27:21 +00002285
Eric Andersenc470f442003-07-28 09:56:35 +00002286static int
2287cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002288{
2289 const char *dest;
2290 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002291 const char *p;
2292 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002293 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002294 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002295
Eric Andersenc470f442003-07-28 09:56:35 +00002296 flags = cdopt();
2297 dest = *argptr;
2298 if (!dest)
2299 dest = bltinlookup(homestr);
2300 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002301 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002302 flags |= CD_PRINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002303 }
Eric Andersenc470f442003-07-28 09:56:35 +00002304 if (!dest)
2305 dest = nullstr;
2306 if (*dest == '/')
2307 goto step7;
2308 if (*dest == '.') {
2309 c = dest[1];
2310dotdot:
2311 switch (c) {
2312 case '\0':
2313 case '/':
2314 goto step6;
2315 case '.':
2316 c = dest[2];
2317 if (c != '.')
2318 goto dotdot;
2319 }
2320 }
2321 if (!*dest)
2322 dest = ".";
2323 if (!(path = bltinlookup("CDPATH"))) {
2324step6:
2325step7:
2326 p = dest;
2327 goto docd;
2328 }
2329 do {
2330 c = *path;
2331 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002332 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002333 if (c && c != ':')
2334 flags |= CD_PRINT;
2335docd:
2336 if (!docd(p, flags))
2337 goto out;
2338 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002339 }
Eric Andersenc470f442003-07-28 09:56:35 +00002340 } while (path);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002341 sh_error("can't cd to %s", dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002342 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002343out:
2344 if (flags & CD_PRINT)
2345 out1fmt(snlfmt, curdir);
2346 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002347}
2348
2349
2350/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002351 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002352 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002353 */
2354
Rob Landley88621d72006-08-29 19:41:06 +00002355static const char * updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002356{
Eric Andersenc470f442003-07-28 09:56:35 +00002357 char *new;
2358 char *p;
2359 char *cdcomppath;
2360 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002361
Eric Andersenc470f442003-07-28 09:56:35 +00002362 cdcomppath = sstrdup(dir);
2363 STARTSTACKSTR(new);
2364 if (*dir != '/') {
2365 if (curdir == nullstr)
2366 return 0;
2367 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002368 }
Eric Andersenc470f442003-07-28 09:56:35 +00002369 new = makestrspace(strlen(dir) + 2, new);
2370 lim = stackblock() + 1;
2371 if (*dir != '/') {
2372 if (new[-1] != '/')
2373 USTPUTC('/', new);
2374 if (new > lim && *lim == '/')
2375 lim++;
2376 } else {
2377 USTPUTC('/', new);
2378 cdcomppath++;
2379 if (dir[1] == '/' && dir[2] != '/') {
2380 USTPUTC('/', new);
2381 cdcomppath++;
2382 lim++;
2383 }
2384 }
2385 p = strtok(cdcomppath, "/");
2386 while (p) {
2387 switch(*p) {
2388 case '.':
2389 if (p[1] == '.' && p[2] == '\0') {
2390 while (new > lim) {
2391 STUNPUTC(new);
2392 if (new[-1] == '/')
2393 break;
2394 }
2395 break;
2396 } else if (p[1] == '\0')
2397 break;
2398 /* fall through */
2399 default:
2400 new = stputs(p, new);
2401 USTPUTC('/', new);
2402 }
2403 p = strtok(0, "/");
2404 }
2405 if (new > lim)
2406 STUNPUTC(new);
2407 *new = 0;
2408 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002409}
2410
2411/*
Eric Andersenc470f442003-07-28 09:56:35 +00002412 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2413 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002414 */
2415
Eric Andersenc470f442003-07-28 09:56:35 +00002416static int
2417docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002418{
Eric Andersenc470f442003-07-28 09:56:35 +00002419 const char *dir = 0;
2420 int err;
2421
2422 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2423
Eric Andersencb57d552001-06-28 07:25:16 +00002424 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002425 if (!(flags & CD_PHYSICAL)) {
2426 dir = updatepwd(dest);
2427 if (dir)
2428 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002429 }
Eric Andersenc470f442003-07-28 09:56:35 +00002430 err = chdir(dest);
2431 if (err)
2432 goto out;
2433 setpwd(dir, 1);
2434 hashcd();
2435out:
Eric Andersencb57d552001-06-28 07:25:16 +00002436 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002437 return err;
2438}
2439
2440/*
2441 * Find out what the current directory is. If we already know the current
2442 * directory, this routine returns immediately.
2443 */
Rob Landley88621d72006-08-29 19:41:06 +00002444static char * getpwd(void)
Eric Andersenc470f442003-07-28 09:56:35 +00002445{
2446 char *dir = getcwd(0, 0);
2447 return dir ? dir : nullstr;
2448}
2449
2450static int
2451pwdcmd(int argc, char **argv)
2452{
2453 int flags;
2454 const char *dir = curdir;
2455
2456 flags = cdopt();
2457 if (flags) {
2458 if (physdir == nullstr)
2459 setpwd(dir, 0);
2460 dir = physdir;
2461 }
2462 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002463 return 0;
2464}
2465
Eric Andersenc470f442003-07-28 09:56:35 +00002466static void
2467setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002468{
Eric Andersenc470f442003-07-28 09:56:35 +00002469 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002470
Eric Andersenc470f442003-07-28 09:56:35 +00002471 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002472
Eric Andersencb57d552001-06-28 07:25:16 +00002473 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002474 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002475 }
2476 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002477 if (physdir != nullstr) {
2478 if (physdir != oldcur)
2479 free(physdir);
2480 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002481 }
Eric Andersenc470f442003-07-28 09:56:35 +00002482 if (oldcur == val || !val) {
2483 char *s = getpwd();
2484 physdir = s;
2485 if (!val)
2486 dir = s;
2487 } else
2488 dir = savestr(val);
2489 if (oldcur != dir && oldcur != nullstr) {
2490 free(oldcur);
2491 }
2492 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002493 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002494 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002495}
2496
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002497/* error.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002498
Eric Andersencb57d552001-06-28 07:25:16 +00002499/*
2500 * Errors and exceptions.
2501 */
2502
2503/*
2504 * Code to handle exceptions in C.
2505 */
2506
Eric Andersen2870d962001-07-02 17:27:21 +00002507
Eric Andersencb57d552001-06-28 07:25:16 +00002508
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002509static void exverror(int, const char *, va_list)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002510 ATTRIBUTE_NORETURN;
Eric Andersencb57d552001-06-28 07:25:16 +00002511
2512/*
2513 * Called to raise an exception. Since C doesn't include exceptions, we
2514 * just do a longjmp to the exception handler. The type of exception is
2515 * stored in the global variable "exception".
2516 */
2517
Eric Andersenc470f442003-07-28 09:56:35 +00002518static void
2519exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002520{
2521#ifdef DEBUG
2522 if (handler == NULL)
2523 abort();
2524#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002525 INTOFF;
2526
Eric Andersencb57d552001-06-28 07:25:16 +00002527 exception = e;
2528 longjmp(handler->loc, 1);
2529}
2530
2531
2532/*
2533 * Called from trap.c when a SIGINT is received. (If the user specifies
2534 * that SIGINT is to be trapped or ignored using the trap builtin, then
2535 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002536 * are held using the INTOFF macro. (The test for iflag is just
2537 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002538 */
2539
Eric Andersenc470f442003-07-28 09:56:35 +00002540static void
2541onint(void) {
2542 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002543
Eric Andersencb57d552001-06-28 07:25:16 +00002544 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002545 i = EXSIG;
2546 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2547 if (!(rootshell && iflag)) {
2548 signal(SIGINT, SIG_DFL);
2549 raise(SIGINT);
2550 }
2551 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002552 }
Eric Andersenc470f442003-07-28 09:56:35 +00002553 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002554 /* NOTREACHED */
2555}
2556
Eric Andersenc470f442003-07-28 09:56:35 +00002557static void
2558exvwarning(const char *msg, va_list ap)
2559{
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002560 FILE *errs;
Eric Andersencb57d552001-06-28 07:25:16 +00002561
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002562 errs = stderr;
2563 fprintf(errs, "%s: ", arg0);
2564 if (commandname) {
2565 const char *fmt = (!iflag || parsefile->fd) ?
2566 "%s: %d: " : "%s: ";
2567 fprintf(errs, fmt, commandname, startlinno);
2568 }
2569 vfprintf(errs, msg, ap);
2570 outcslow('\n', errs);
Eric Andersenc470f442003-07-28 09:56:35 +00002571}
Eric Andersen2870d962001-07-02 17:27:21 +00002572
Eric Andersencb57d552001-06-28 07:25:16 +00002573/*
Eric Andersenc470f442003-07-28 09:56:35 +00002574 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002575 * is not NULL then error prints an error message using printf style
2576 * formatting. It then raises the error exception.
2577 */
Eric Andersenc470f442003-07-28 09:56:35 +00002578static void
2579exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002580{
Eric Andersencb57d552001-06-28 07:25:16 +00002581#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002582 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002583 TRACE(("exverror(%d, \"", cond));
2584 TRACEV((msg, ap));
2585 TRACE(("\") pid=%d\n", getpid()));
2586 } else
2587 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2588 if (msg)
2589#endif
2590 exvwarning(msg, ap);
2591
2592 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002593 exraise(cond);
2594 /* NOTREACHED */
2595}
2596
2597
Eric Andersenc470f442003-07-28 09:56:35 +00002598static void
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002599sh_error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002600{
Eric Andersencb57d552001-06-28 07:25:16 +00002601 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002602
Eric Andersencb57d552001-06-28 07:25:16 +00002603 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002604 exverror(EXERROR, msg, ap);
2605 /* NOTREACHED */
2606 va_end(ap);
2607}
2608
2609
Eric Andersenc470f442003-07-28 09:56:35 +00002610static void
2611exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002612{
Eric Andersencb57d552001-06-28 07:25:16 +00002613 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002614
Eric Andersencb57d552001-06-28 07:25:16 +00002615 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002616 exverror(cond, msg, ap);
2617 /* NOTREACHED */
2618 va_end(ap);
2619}
2620
Eric Andersencb57d552001-06-28 07:25:16 +00002621/*
Eric Andersenc470f442003-07-28 09:56:35 +00002622 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002623 */
2624
Eric Andersenc470f442003-07-28 09:56:35 +00002625static void
2626sh_warnx(const char *fmt, ...)
2627{
2628 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002629
Eric Andersenc470f442003-07-28 09:56:35 +00002630 va_start(ap, fmt);
2631 exvwarning(fmt, ap);
2632 va_end(ap);
2633}
Eric Andersen2870d962001-07-02 17:27:21 +00002634
Eric Andersencb57d552001-06-28 07:25:16 +00002635
2636/*
2637 * Return a string describing an error. The returned string may be a
2638 * pointer to a static buffer that will be overwritten on the next call.
2639 * Action describes the operation that got the error.
2640 */
2641
Eric Andersenc470f442003-07-28 09:56:35 +00002642static const char *
2643errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002644{
Eric Andersenc470f442003-07-28 09:56:35 +00002645 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002646
Eric Andersenc470f442003-07-28 09:56:35 +00002647 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002648 }
Eric Andersenc470f442003-07-28 09:56:35 +00002649 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002650}
2651
2652
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002653/* eval.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002654
2655/*
2656 * Evaluate a command.
2657 */
Eric Andersencb57d552001-06-28 07:25:16 +00002658
2659/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002660#define EV_EXIT 01 /* exit after evaluating tree */
2661#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2662#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002663
2664
Eric Andersenc470f442003-07-28 09:56:35 +00002665static void evalloop(union node *, int);
2666static void evalfor(union node *, int);
2667static void evalcase(union node *, int);
2668static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002669static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002670static void evalpipe(union node *, int);
2671static void evalcommand(union node *, int);
2672static int evalbltin(const struct builtincmd *, int, char **);
2673static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002674static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002675static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002676
Eric Andersenc470f442003-07-28 09:56:35 +00002677
2678static const struct builtincmd bltin = {
2679 "\0\0", bltincmd
2680};
2681
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002682
Eric Andersencb57d552001-06-28 07:25:16 +00002683/*
2684 * Called to reset things after an exception.
2685 */
2686
Eric Andersencb57d552001-06-28 07:25:16 +00002687/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002688 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002689 */
2690
Eric Andersenc470f442003-07-28 09:56:35 +00002691static int
2692evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002693{
Eric Andersen2870d962001-07-02 17:27:21 +00002694 char *p;
2695 char *concat;
2696 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002697
Eric Andersen2870d962001-07-02 17:27:21 +00002698 if (argc > 1) {
2699 p = argv[1];
2700 if (argc > 2) {
2701 STARTSTACKSTR(concat);
2702 ap = argv + 2;
2703 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002704 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002705 if ((p = *ap++) == NULL)
2706 break;
2707 STPUTC(' ', concat);
2708 }
2709 STPUTC('\0', concat);
2710 p = grabstackstr(concat);
2711 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002712 evalstring(p, ~SKIPEVAL);
2713
Eric Andersen2870d962001-07-02 17:27:21 +00002714 }
2715 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002716}
2717
Eric Andersenc470f442003-07-28 09:56:35 +00002718
Eric Andersencb57d552001-06-28 07:25:16 +00002719/*
2720 * Execute a command or commands contained in a string.
2721 */
2722
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002723static int
2724evalstring(char *s, int mask)
Eric Andersen2870d962001-07-02 17:27:21 +00002725{
Eric Andersencb57d552001-06-28 07:25:16 +00002726 union node *n;
2727 struct stackmark smark;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002728 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002729
Eric Andersencb57d552001-06-28 07:25:16 +00002730 setinputstring(s);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002731 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002732
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002733 skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002734 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002735 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002736 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002737 skip = evalskip;
2738 if (skip)
Eric Andersenc470f442003-07-28 09:56:35 +00002739 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002740 }
2741 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002742
2743 skip &= mask;
2744 evalskip = skip;
2745 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002746}
2747
Eric Andersenc470f442003-07-28 09:56:35 +00002748
Eric Andersen62483552001-07-10 06:09:16 +00002749
2750/*
Eric Andersenc470f442003-07-28 09:56:35 +00002751 * Evaluate a parse tree. The value is left in the global variable
2752 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002753 */
2754
Eric Andersenc470f442003-07-28 09:56:35 +00002755static void
2756evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002757{
Eric Andersenc470f442003-07-28 09:56:35 +00002758 int checkexit = 0;
2759 void (*evalfn)(union node *, int);
2760 unsigned isor;
2761 int status;
2762 if (n == NULL) {
2763 TRACE(("evaltree(NULL) called\n"));
2764 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002765 }
Eric Andersenc470f442003-07-28 09:56:35 +00002766 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2767 getpid(), n, n->type, flags));
2768 switch (n->type) {
2769 default:
2770#ifdef DEBUG
2771 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002772 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002773 break;
2774#endif
2775 case NNOT:
2776 evaltree(n->nnot.com, EV_TESTED);
2777 status = !exitstatus;
2778 goto setstatus;
2779 case NREDIR:
2780 expredir(n->nredir.redirect);
2781 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2782 if (!status) {
2783 evaltree(n->nredir.n, flags & EV_TESTED);
2784 status = exitstatus;
2785 }
2786 popredir(0);
2787 goto setstatus;
2788 case NCMD:
2789 evalfn = evalcommand;
2790checkexit:
2791 if (eflag && !(flags & EV_TESTED))
2792 checkexit = ~0;
2793 goto calleval;
2794 case NFOR:
2795 evalfn = evalfor;
2796 goto calleval;
2797 case NWHILE:
2798 case NUNTIL:
2799 evalfn = evalloop;
2800 goto calleval;
2801 case NSUBSHELL:
2802 case NBACKGND:
2803 evalfn = evalsubshell;
2804 goto calleval;
2805 case NPIPE:
2806 evalfn = evalpipe;
2807 goto checkexit;
2808 case NCASE:
2809 evalfn = evalcase;
2810 goto calleval;
2811 case NAND:
2812 case NOR:
2813 case NSEMI:
2814#if NAND + 1 != NOR
2815#error NAND + 1 != NOR
2816#endif
2817#if NOR + 1 != NSEMI
2818#error NOR + 1 != NSEMI
2819#endif
2820 isor = n->type - NAND;
2821 evaltree(
2822 n->nbinary.ch1,
2823 (flags | ((isor >> 1) - 1)) & EV_TESTED
2824 );
2825 if (!exitstatus == isor)
2826 break;
2827 if (!evalskip) {
2828 n = n->nbinary.ch2;
2829evaln:
2830 evalfn = evaltree;
2831calleval:
2832 evalfn(n, flags);
2833 break;
2834 }
2835 break;
2836 case NIF:
2837 evaltree(n->nif.test, EV_TESTED);
2838 if (evalskip)
2839 break;
2840 if (exitstatus == 0) {
2841 n = n->nif.ifpart;
2842 goto evaln;
2843 } else if (n->nif.elsepart) {
2844 n = n->nif.elsepart;
2845 goto evaln;
2846 }
2847 goto success;
2848 case NDEFUN:
2849 defun(n->narg.text, n->narg.next);
2850success:
2851 status = 0;
2852setstatus:
2853 exitstatus = status;
2854 break;
2855 }
2856out:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002857 if ((checkexit & exitstatus))
2858 evalskip |= SKIPEVAL;
2859 else if (pendingsigs && dotrap())
2860 goto exexit;
2861
2862 if (flags & EV_EXIT) {
2863exexit:
Eric Andersenc470f442003-07-28 09:56:35 +00002864 exraise(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002865 }
Eric Andersen62483552001-07-10 06:09:16 +00002866}
2867
Eric Andersenc470f442003-07-28 09:56:35 +00002868
2869#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2870static
2871#endif
2872void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2873
2874
2875static void
2876evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002877{
2878 int status;
2879
2880 loopnest++;
2881 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002882 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002883 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002884 int i;
2885
Eric Andersencb57d552001-06-28 07:25:16 +00002886 evaltree(n->nbinary.ch1, EV_TESTED);
2887 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002888skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002889 evalskip = 0;
2890 continue;
2891 }
2892 if (evalskip == SKIPBREAK && --skipcount <= 0)
2893 evalskip = 0;
2894 break;
2895 }
Eric Andersenc470f442003-07-28 09:56:35 +00002896 i = exitstatus;
2897 if (n->type != NWHILE)
2898 i = !i;
2899 if (i != 0)
2900 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002901 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002902 status = exitstatus;
2903 if (evalskip)
2904 goto skipping;
2905 }
2906 loopnest--;
2907 exitstatus = status;
2908}
2909
Eric Andersenc470f442003-07-28 09:56:35 +00002910
2911
2912static void
2913evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002914{
2915 struct arglist arglist;
2916 union node *argp;
2917 struct strlist *sp;
2918 struct stackmark smark;
2919
2920 setstackmark(&smark);
2921 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002922 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002923 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002924 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002925 if (evalskip)
2926 goto out;
2927 }
2928 *arglist.lastp = NULL;
2929
2930 exitstatus = 0;
2931 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002932 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002933 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002934 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002935 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002936 if (evalskip) {
2937 if (evalskip == SKIPCONT && --skipcount <= 0) {
2938 evalskip = 0;
2939 continue;
2940 }
2941 if (evalskip == SKIPBREAK && --skipcount <= 0)
2942 evalskip = 0;
2943 break;
2944 }
2945 }
2946 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002947out:
Eric Andersencb57d552001-06-28 07:25:16 +00002948 popstackmark(&smark);
2949}
2950
Eric Andersenc470f442003-07-28 09:56:35 +00002951
2952
2953static void
2954evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002955{
2956 union node *cp;
2957 union node *patp;
2958 struct arglist arglist;
2959 struct stackmark smark;
2960
2961 setstackmark(&smark);
2962 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002963 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002964 exitstatus = 0;
2965 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2966 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002967 if (casematch(patp, arglist.list->text)) {
2968 if (evalskip == 0) {
2969 evaltree(cp->nclist.body, flags);
2970 }
2971 goto out;
2972 }
2973 }
2974 }
Eric Andersenc470f442003-07-28 09:56:35 +00002975out:
Eric Andersencb57d552001-06-28 07:25:16 +00002976 popstackmark(&smark);
2977}
2978
Eric Andersenc470f442003-07-28 09:56:35 +00002979
2980
2981/*
2982 * Kick off a subshell to evaluate a tree.
2983 */
2984
2985static void
2986evalsubshell(union node *n, int flags)
2987{
2988 struct job *jp;
2989 int backgnd = (n->type == NBACKGND);
2990 int status;
2991
2992 expredir(n->nredir.redirect);
2993 if (!backgnd && flags & EV_EXIT && !trap[0])
2994 goto nofork;
2995 INTOFF;
2996 jp = makejob(n, 1);
2997 if (forkshell(jp, n, backgnd) == 0) {
2998 INTON;
2999 flags |= EV_EXIT;
3000 if (backgnd)
3001 flags &=~ EV_TESTED;
3002nofork:
3003 redirect(n->nredir.redirect, 0);
3004 evaltreenr(n->nredir.n, flags);
3005 /* never returns */
3006 }
3007 status = 0;
3008 if (! backgnd)
3009 status = waitforjob(jp);
3010 exitstatus = status;
3011 INTON;
3012}
3013
3014
3015
3016/*
3017 * Compute the names of the files in a redirection list.
3018 */
3019
3020static void
3021expredir(union node *n)
3022{
3023 union node *redir;
3024
3025 for (redir = n ; redir ; redir = redir->nfile.next) {
3026 struct arglist fn;
3027 fn.lastp = &fn.list;
3028 switch (redir->type) {
3029 case NFROMTO:
3030 case NFROM:
3031 case NTO:
3032 case NCLOBBER:
3033 case NAPPEND:
3034 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3035 redir->nfile.expfname = fn.list->text;
3036 break;
3037 case NFROMFD:
3038 case NTOFD:
3039 if (redir->ndup.vname) {
3040 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3041 fixredir(redir, fn.list->text, 1);
3042 }
3043 break;
3044 }
3045 }
3046}
3047
3048
3049
Eric Andersencb57d552001-06-28 07:25:16 +00003050/*
Eric Andersencb57d552001-06-28 07:25:16 +00003051 * Evaluate a pipeline. All the processes in the pipeline are children
3052 * of the process creating the pipeline. (This differs from some versions
3053 * of the shell, which make the last process in a pipeline the parent
3054 * of all the rest.)
3055 */
3056
Eric Andersenc470f442003-07-28 09:56:35 +00003057static void
3058evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003059{
3060 struct job *jp;
3061 struct nodelist *lp;
3062 int pipelen;
3063 int prevfd;
3064 int pip[2];
3065
Eric Andersenc470f442003-07-28 09:56:35 +00003066 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003067 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003068 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003069 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003070 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003071 INTOFF;
3072 jp = makejob(n, pipelen);
3073 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003074 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003075 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003076 pip[1] = -1;
3077 if (lp->next) {
3078 if (pipe(pip) < 0) {
3079 close(prevfd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003080 sh_error("Pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00003081 }
3082 }
3083 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3084 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003085 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003086 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003087 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003088 if (prevfd > 0) {
3089 dup2(prevfd, 0);
3090 close(prevfd);
3091 }
3092 if (pip[1] > 1) {
3093 dup2(pip[1], 1);
3094 close(pip[1]);
3095 }
Eric Andersenc470f442003-07-28 09:56:35 +00003096 evaltreenr(lp->n, flags);
3097 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003098 }
3099 if (prevfd >= 0)
3100 close(prevfd);
3101 prevfd = pip[0];
3102 close(pip[1]);
3103 }
Eric Andersencb57d552001-06-28 07:25:16 +00003104 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003105 exitstatus = waitforjob(jp);
3106 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003107 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003108 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003109}
3110
Eric Andersen62483552001-07-10 06:09:16 +00003111
3112
3113/*
3114 * Execute a command inside back quotes. If it's a builtin command, we
3115 * want to save its output in a block obtained from malloc. Otherwise
3116 * we fork off a subprocess and get the output of the command via a pipe.
3117 * Should be called with interrupts off.
3118 */
3119
Eric Andersenc470f442003-07-28 09:56:35 +00003120static void
3121evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003122{
Eric Andersenc470f442003-07-28 09:56:35 +00003123 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003124
Eric Andersen62483552001-07-10 06:09:16 +00003125 result->fd = -1;
3126 result->buf = NULL;
3127 result->nleft = 0;
3128 result->jp = NULL;
3129 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003130 goto out;
3131 }
Eric Andersenc470f442003-07-28 09:56:35 +00003132
3133 saveherefd = herefd;
3134 herefd = -1;
3135
3136 {
3137 int pip[2];
3138 struct job *jp;
3139
3140 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003141 sh_error("Pipe call failed");
Eric Andersenc470f442003-07-28 09:56:35 +00003142 jp = makejob(n, 1);
3143 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3144 FORCEINTON;
3145 close(pip[0]);
3146 if (pip[1] != 1) {
3147 close(1);
3148 copyfd(pip[1], 1);
3149 close(pip[1]);
3150 }
3151 eflag = 0;
3152 evaltreenr(n, EV_EXIT);
3153 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003154 }
Eric Andersenc470f442003-07-28 09:56:35 +00003155 close(pip[1]);
3156 result->fd = pip[0];
3157 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003158 }
Eric Andersenc470f442003-07-28 09:56:35 +00003159 herefd = saveherefd;
3160out:
Eric Andersen62483552001-07-10 06:09:16 +00003161 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003162 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003163}
3164
Eric Andersenc470f442003-07-28 09:56:35 +00003165#ifdef CONFIG_ASH_CMDCMD
Rob Landley88621d72006-08-29 19:41:06 +00003166static char ** parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00003167{
3168 char *cp, c;
3169
3170 for (;;) {
3171 cp = *++argv;
3172 if (!cp)
3173 return 0;
3174 if (*cp++ != '-')
3175 break;
3176 if (!(c = *cp++))
3177 break;
3178 if (c == '-' && !*cp) {
3179 argv++;
3180 break;
3181 }
3182 do {
3183 switch (c) {
3184 case 'p':
3185 *path = defpath;
3186 break;
3187 default:
3188 /* run 'typecmd' for other options */
3189 return 0;
3190 }
3191 } while ((c = *cp++));
3192 }
3193 return argv;
3194}
3195#endif
3196
Rob Landley88621d72006-08-29 19:41:06 +00003197static int isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00003198{
3199 const char *q = endofname(p);
3200 if (p == q)
3201 return 0;
3202 return *q == '=';
3203}
Eric Andersen62483552001-07-10 06:09:16 +00003204
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003205#ifdef CONFIG_ASH_EXPAND_PRMT
3206static const char *expandstr(const char *ps);
3207#else
3208#define expandstr(s) s
3209#endif
3210
Eric Andersen62483552001-07-10 06:09:16 +00003211/*
3212 * Execute a simple command.
3213 */
Eric Andersencb57d552001-06-28 07:25:16 +00003214
Eric Andersenc470f442003-07-28 09:56:35 +00003215static void
3216evalcommand(union node *cmd, int flags)
3217{
3218 struct stackmark smark;
3219 union node *argp;
3220 struct arglist arglist;
3221 struct arglist varlist;
3222 char **argv;
3223 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003224 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003225 struct cmdentry cmdentry;
3226 struct job *jp;
3227 char *lastarg;
3228 const char *path;
3229 int spclbltin;
3230 int cmd_is_exec;
3231 int status;
3232 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003233 struct builtincmd *bcmd;
3234 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003235
3236 /* First expand the arguments. */
3237 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3238 setstackmark(&smark);
3239 back_exitstatus = 0;
3240
3241 cmdentry.cmdtype = CMDBUILTIN;
3242 cmdentry.u.cmd = &bltin;
3243 varlist.lastp = &varlist.list;
3244 *varlist.lastp = NULL;
3245 arglist.lastp = &arglist.list;
3246 *arglist.lastp = NULL;
3247
3248 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003249 if (cmd->ncmd.args)
3250 {
3251 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3252 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3253 }
3254
Eric Andersenc470f442003-07-28 09:56:35 +00003255 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3256 struct strlist **spp;
3257
3258 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003259 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00003260 expandarg(argp, &arglist, EXP_VARTILDE);
3261 else
3262 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3263
Eric Andersenc470f442003-07-28 09:56:35 +00003264 for (sp = *spp; sp; sp = sp->next)
3265 argc++;
3266 }
3267
3268 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3269 for (sp = arglist.list ; sp ; sp = sp->next) {
3270 TRACE(("evalcommand arg: %s\n", sp->text));
3271 *nargv++ = sp->text;
3272 }
3273 *nargv = NULL;
3274
3275 lastarg = NULL;
3276 if (iflag && funcnest == 0 && argc > 0)
3277 lastarg = nargv[-1];
3278
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003279 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003280 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003281 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003282
3283 path = vpath.text;
3284 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3285 struct strlist **spp;
3286 char *p;
3287
3288 spp = varlist.lastp;
3289 expandarg(argp, &varlist, EXP_VARTILDE);
3290
3291 /*
3292 * Modify the command lookup path, if a PATH= assignment
3293 * is present
3294 */
3295 p = (*spp)->text;
3296 if (varequal(p, path))
3297 path = p;
3298 }
3299
3300 /* Print the command if xflag is set. */
3301 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003302 int n;
3303 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003304
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003305 p++;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003306 dprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003307
3308 sp = varlist.list;
3309 for(n = 0; n < 2; n++) {
3310 while (sp) {
3311 dprintf(preverrout_fd, p, sp->text);
3312 sp = sp->next;
3313 if(*p == '%') {
3314 p--;
3315 }
3316 }
3317 sp = arglist.list;
3318 }
Rob Landley53437472006-07-16 08:14:35 +00003319 full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003320 }
3321
3322 cmd_is_exec = 0;
3323 spclbltin = -1;
3324
3325 /* Now locate the command. */
3326 if (argc) {
3327 const char *oldpath;
3328 int cmd_flag = DO_ERR;
3329
3330 path += 5;
3331 oldpath = path;
3332 for (;;) {
3333 find_command(argv[0], &cmdentry, cmd_flag, path);
3334 if (cmdentry.cmdtype == CMDUNKNOWN) {
3335 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003336 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003337 goto bail;
3338 }
3339
3340 /* implement bltin and command here */
3341 if (cmdentry.cmdtype != CMDBUILTIN)
3342 break;
3343 if (spclbltin < 0)
3344 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3345 if (cmdentry.u.cmd == EXECCMD)
3346 cmd_is_exec++;
3347#ifdef CONFIG_ASH_CMDCMD
3348 if (cmdentry.u.cmd == COMMANDCMD) {
3349
3350 path = oldpath;
3351 nargv = parse_command_args(argv, &path);
3352 if (!nargv)
3353 break;
3354 argc -= nargv - argv;
3355 argv = nargv;
3356 cmd_flag |= DO_NOFUNC;
3357 } else
3358#endif
3359 break;
3360 }
3361 }
3362
3363 if (status) {
3364 /* We have a redirection error. */
3365 if (spclbltin > 0)
3366 exraise(EXERROR);
3367bail:
3368 exitstatus = status;
3369 goto out;
3370 }
3371
3372 /* Execute the command. */
3373 switch (cmdentry.cmdtype) {
3374 default:
3375 /* Fork off a child process if necessary. */
3376 if (!(flags & EV_EXIT) || trap[0]) {
3377 INTOFF;
3378 jp = makejob(cmd, 1);
3379 if (forkshell(jp, cmd, FORK_FG) != 0) {
3380 exitstatus = waitforjob(jp);
3381 INTON;
3382 break;
3383 }
3384 FORCEINTON;
3385 }
3386 listsetvar(varlist.list, VEXPORT|VSTACK);
3387 shellexec(argv, path, cmdentry.u.index);
3388 /* NOTREACHED */
3389
3390 case CMDBUILTIN:
3391 cmdenviron = varlist.list;
3392 if (cmdenviron) {
3393 struct strlist *list = cmdenviron;
3394 int i = VNOSET;
3395 if (spclbltin > 0 || argc == 0) {
3396 i = 0;
3397 if (cmd_is_exec && argc > 1)
3398 i = VEXPORT;
3399 }
3400 listsetvar(list, i);
3401 }
3402 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3403 int exit_status;
3404 int i, j;
3405
3406 i = exception;
3407 if (i == EXEXIT)
3408 goto raise;
3409
3410 exit_status = 2;
3411 j = 0;
3412 if (i == EXINT)
3413 j = SIGINT;
3414 if (i == EXSIG)
3415 j = pendingsigs;
3416 if (j)
3417 exit_status = j + 128;
3418 exitstatus = exit_status;
3419
3420 if (i == EXINT || spclbltin > 0) {
3421raise:
3422 longjmp(handler->loc, 1);
3423 }
3424 FORCEINTON;
3425 }
3426 break;
3427
3428 case CMDFUNCTION:
3429 listsetvar(varlist.list, 0);
3430 if (evalfun(cmdentry.u.func, argc, argv, flags))
3431 goto raise;
3432 break;
3433 }
3434
3435out:
3436 popredir(cmd_is_exec);
3437 if (lastarg)
3438 /* dsl: I think this is intended to be used to support
3439 * '_' in 'vi' command mode during line editing...
3440 * However I implemented that within libedit itself.
3441 */
3442 setvar("_", lastarg, 0);
3443 popstackmark(&smark);
3444}
3445
3446static int
3447evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3448 char *volatile savecmdname;
3449 struct jmploc *volatile savehandler;
3450 struct jmploc jmploc;
3451 int i;
3452
3453 savecmdname = commandname;
3454 if ((i = setjmp(jmploc.loc)))
3455 goto cmddone;
3456 savehandler = handler;
3457 handler = &jmploc;
3458 commandname = argv[0];
3459 argptr = argv + 1;
3460 optptr = NULL; /* initialize nextopt */
3461 exitstatus = (*cmd->builtin)(argc, argv);
3462 flushall();
3463cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003464 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00003465 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003466 commandname = savecmdname;
3467 exsig = 0;
3468 handler = savehandler;
3469
3470 return i;
3471}
3472
3473static int
3474evalfun(struct funcnode *func, int argc, char **argv, int flags)
3475{
3476 volatile struct shparam saveparam;
3477 struct localvar *volatile savelocalvars;
3478 struct jmploc *volatile savehandler;
3479 struct jmploc jmploc;
3480 int e;
3481
3482 saveparam = shellparam;
3483 savelocalvars = localvars;
3484 if ((e = setjmp(jmploc.loc))) {
3485 goto funcdone;
3486 }
3487 INTOFF;
3488 savehandler = handler;
3489 handler = &jmploc;
3490 localvars = NULL;
3491 shellparam.malloc = 0;
3492 func->count++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003493 funcnest++;
Eric Andersenc470f442003-07-28 09:56:35 +00003494 INTON;
3495 shellparam.nparam = argc - 1;
3496 shellparam.p = argv + 1;
3497#ifdef CONFIG_ASH_GETOPTS
3498 shellparam.optind = 1;
3499 shellparam.optoff = -1;
3500#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003501 evaltree(&func->n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00003502funcdone:
3503 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003504 funcnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00003505 freefunc(func);
3506 poplocalvars();
3507 localvars = savelocalvars;
3508 freeparam(&shellparam);
3509 shellparam = saveparam;
3510 handler = savehandler;
3511 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003512 evalskip &= ~SKIPFUNC;
Eric Andersenc470f442003-07-28 09:56:35 +00003513 return e;
3514}
3515
3516
Rob Landley88621d72006-08-29 19:41:06 +00003517static int goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003518{
3519 return !*endofname(p);
3520}
3521
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003522/*
3523 * Search for a command. This is called before we fork so that the
3524 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003525 * the child. The check for "goodname" is an overly conservative
3526 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003527 */
3528
Eric Andersenc470f442003-07-28 09:56:35 +00003529static void
3530prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003531{
3532 struct cmdentry entry;
3533
3534 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003535 if (goodname(n->ncmd.args->narg.text))
3536 find_command(n->ncmd.args->narg.text, &entry, 0,
3537 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003538}
3539
Eric Andersencb57d552001-06-28 07:25:16 +00003540
Eric Andersenc470f442003-07-28 09:56:35 +00003541
Eric Andersencb57d552001-06-28 07:25:16 +00003542/*
3543 * Builtin commands. Builtin commands whose functions are closely
3544 * tied to evaluation are implemented here.
3545 */
3546
3547/*
Eric Andersenc470f442003-07-28 09:56:35 +00003548 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003549 */
3550
Eric Andersenc470f442003-07-28 09:56:35 +00003551static int
3552bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003553{
3554 /*
3555 * Preserve exitstatus of a previous possible redirection
3556 * as POSIX mandates
3557 */
Eric Andersenc470f442003-07-28 09:56:35 +00003558 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003559}
3560
3561
3562/*
3563 * Handle break and continue commands. Break, continue, and return are
3564 * all handled by setting the evalskip flag. The evaluation routines
3565 * above all check this flag, and if it is set they start skipping
3566 * commands rather than executing them. The variable skipcount is
3567 * the number of loops to break/continue, or the number of function
3568 * levels to return. (The latter is always 1.) It should probably
3569 * be an error to break out of more loops than exist, but it isn't
3570 * in the standard shell so we don't make it one here.
3571 */
3572
Eric Andersenc470f442003-07-28 09:56:35 +00003573static int
3574breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003575{
3576 int n = argc > 1 ? number(argv[1]) : 1;
3577
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003578 if (n <= 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003579 sh_error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003580 if (n > loopnest)
3581 n = loopnest;
3582 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003583 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003584 skipcount = n;
3585 }
3586 return 0;
3587}
3588
3589
3590/*
3591 * The return command.
3592 */
3593
Eric Andersenc470f442003-07-28 09:56:35 +00003594static int
3595returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003596{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003597 /*
3598 * If called outside a function, do what ksh does;
3599 * skip the rest of the file.
3600 */
3601 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
3602 return argv[1] ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003603}
3604
3605
Eric Andersenc470f442003-07-28 09:56:35 +00003606static int
3607falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003608{
3609 return 1;
3610}
3611
Eric Andersenc470f442003-07-28 09:56:35 +00003612
3613static int
3614truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003615{
3616 return 0;
3617}
Eric Andersen2870d962001-07-02 17:27:21 +00003618
Eric Andersencb57d552001-06-28 07:25:16 +00003619
Eric Andersenc470f442003-07-28 09:56:35 +00003620static int
3621execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003622{
3623 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003624 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003625 mflag = 0;
3626 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003627 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003628 }
3629 return 0;
3630}
3631
Eric Andersenc470f442003-07-28 09:56:35 +00003632
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003633/* exec.c */
Eric Andersenc470f442003-07-28 09:56:35 +00003634
3635/*
3636 * When commands are first encountered, they are entered in a hash table.
3637 * This ensures that a full path search will not have to be done for them
3638 * on each invocation.
3639 *
3640 * We should investigate converting to a linear search, even though that
3641 * would make the command name "hash" a misnomer.
3642 */
3643
3644#define CMDTABLESIZE 31 /* should be prime */
3645#define ARB 1 /* actual size determined at run time */
3646
3647
3648
3649struct tblentry {
3650 struct tblentry *next; /* next entry in hash chain */
3651 union param param; /* definition of builtin function */
3652 short cmdtype; /* index identifying command */
3653 char rehash; /* if set, cd done since entry created */
3654 char cmdname[ARB]; /* name of command */
3655};
3656
3657
3658static struct tblentry *cmdtable[CMDTABLESIZE];
3659static int builtinloc = -1; /* index in path of %builtin, or -1 */
3660
3661
3662static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003663static void clearcmdentry(int);
3664static struct tblentry *cmdlookup(const char *, int);
3665static void delete_cmd_entry(void);
3666
Eric Andersencb57d552001-06-28 07:25:16 +00003667
3668/*
3669 * Exec a program. Never returns. If you change this routine, you may
3670 * have to change the find_command routine as well.
3671 */
3672
Eric Andersenc470f442003-07-28 09:56:35 +00003673static void
3674shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003675{
3676 char *cmdname;
3677 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003678 char **envp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003679 int exerrno;
Eric Andersencb57d552001-06-28 07:25:16 +00003680
Eric Andersenc470f442003-07-28 09:56:35 +00003681 clearredir(1);
3682 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003683 if (strchr(argv[0], '/') != NULL
3684#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3685 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003686#endif
3687 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003688 tryexec(argv[0], argv, envp);
3689 e = errno;
3690 } else {
3691 e = ENOENT;
3692 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3693 if (--idx < 0 && pathopt == NULL) {
3694 tryexec(cmdname, argv, envp);
3695 if (errno != ENOENT && errno != ENOTDIR)
3696 e = errno;
3697 }
3698 stunalloc(cmdname);
3699 }
3700 }
3701
3702 /* Map to POSIX errors */
3703 switch (e) {
3704 case EACCES:
3705 exerrno = 126;
3706 break;
3707 case ENOENT:
3708 exerrno = 127;
3709 break;
3710 default:
3711 exerrno = 2;
3712 break;
3713 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003714 exitstatus = exerrno;
Eric Andersenc470f442003-07-28 09:56:35 +00003715 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3716 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003717 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3718 /* NOTREACHED */
3719}
3720
Eric Andersen2870d962001-07-02 17:27:21 +00003721
Eric Andersenc470f442003-07-28 09:56:35 +00003722static void
3723tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003724{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003725 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003726#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003727 if(find_applet_by_name(cmd) != NULL) {
3728 /* re-exec ourselves with the new arguments */
Rob Landleya34b48a2006-06-14 01:27:01 +00003729 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp);
Rob Landley0fcd9432005-05-07 08:27:34 +00003730 /* If they called chroot or otherwise made the binary no longer
3731 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003732 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003733#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003734
3735repeat:
3736#ifdef SYSV
3737 do {
3738 execve(cmd, argv, envp);
3739 } while (errno == EINTR);
3740#else
Eric Andersencb57d552001-06-28 07:25:16 +00003741 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003742#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003743 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003744 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003745 } else if (errno == ENOEXEC) {
3746 char **ap;
3747 char **new;
3748
Eric Andersenc470f442003-07-28 09:56:35 +00003749 for (ap = argv; *ap; ap++)
3750 ;
3751 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003752 ap[1] = cmd;
3753 *ap = cmd = (char *)DEFAULT_SHELL;
3754 ap += 2;
3755 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003756 while ((*ap++ = *argv++))
3757 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003758 argv = new;
3759 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003760 }
Eric Andersencb57d552001-06-28 07:25:16 +00003761}
3762
Eric Andersenc470f442003-07-28 09:56:35 +00003763
Eric Andersencb57d552001-06-28 07:25:16 +00003764
3765/*
3766 * Do a path search. The variable path (passed by reference) should be
3767 * set to the start of the path before the first call; padvance will update
3768 * this value as it proceeds. Successive calls to padvance will return
3769 * the possible path expansions in sequence. If an option (indicated by
3770 * a percent sign) appears in the path entry then the global variable
3771 * pathopt will be set to point to it; otherwise pathopt will be set to
3772 * NULL.
3773 */
3774
Eric Andersenc470f442003-07-28 09:56:35 +00003775static char *
3776padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003777{
Eric Andersencb57d552001-06-28 07:25:16 +00003778 const char *p;
3779 char *q;
3780 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003781 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003782
3783 if (*path == NULL)
3784 return NULL;
3785 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003786 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3787 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003788 while (stackblocksize() < len)
3789 growstackblock();
3790 q = stackblock();
3791 if (p != start) {
3792 memcpy(q, start, p - start);
3793 q += p - start;
3794 *q++ = '/';
3795 }
3796 strcpy(q, name);
3797 pathopt = NULL;
3798 if (*p == '%') {
3799 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003800 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003801 }
3802 if (*p == ':')
3803 *path = p + 1;
3804 else
3805 *path = NULL;
3806 return stalloc(len);
3807}
3808
3809
Eric Andersencb57d552001-06-28 07:25:16 +00003810/*** Command hashing code ***/
3811
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003812static void
3813printentry(struct tblentry *cmdp)
3814{
3815 int idx;
3816 const char *path;
3817 char *name;
3818
3819 idx = cmdp->param.index;
3820 path = pathval();
3821 do {
3822 name = padvance(&path, cmdp->cmdname);
3823 stunalloc(name);
3824 } while (--idx >= 0);
3825 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3826}
3827
Eric Andersenc470f442003-07-28 09:56:35 +00003828
3829static int
3830hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003831{
3832 struct tblentry **pp;
3833 struct tblentry *cmdp;
3834 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003835 struct cmdentry entry;
3836 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003837
Eric Andersenc470f442003-07-28 09:56:35 +00003838 while ((c = nextopt("r")) != '\0') {
3839 clearcmdentry(0);
3840 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003841 }
3842 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003843 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3844 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3845 if (cmdp->cmdtype == CMDNORMAL)
3846 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003847 }
3848 }
3849 return 0;
3850 }
3851 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003852 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003853 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003854 && (cmdp->cmdtype == CMDNORMAL
3855 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003856 delete_cmd_entry();
3857 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003858 if (entry.cmdtype == CMDUNKNOWN)
3859 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003860 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003861 }
3862 return c;
3863}
3864
Eric Andersenc470f442003-07-28 09:56:35 +00003865
Eric Andersencb57d552001-06-28 07:25:16 +00003866/*
3867 * Resolve a command name. If you change this routine, you may have to
3868 * change the shellexec routine as well.
3869 */
3870
3871static void
Eric Andersenc470f442003-07-28 09:56:35 +00003872find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003873{
3874 struct tblentry *cmdp;
3875 int idx;
3876 int prev;
3877 char *fullname;
3878 struct stat statb;
3879 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003880 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003881 struct builtincmd *bcmd;
3882
Eric Andersenc470f442003-07-28 09:56:35 +00003883 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003884 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003885 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003886 if (act & DO_ABS) {
3887 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003888#ifdef SYSV
3889 if (errno == EINTR)
3890 continue;
3891#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003892 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003893 return;
3894 }
Eric Andersencb57d552001-06-28 07:25:16 +00003895 }
3896 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003897 return;
3898 }
3899
Eric Andersenbf8bf102002-09-17 08:41:08 +00003900#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3901 if (find_applet_by_name(name)) {
3902 entry->cmdtype = CMDNORMAL;
3903 entry->u.index = -1;
3904 return;
3905 }
3906#endif
3907
Eric Andersenc470f442003-07-28 09:56:35 +00003908 updatetbl = (path == pathval());
3909 if (!updatetbl) {
3910 act |= DO_ALTPATH;
3911 if (strstr(path, "%builtin") != NULL)
3912 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003913 }
3914
Eric Andersenc470f442003-07-28 09:56:35 +00003915 /* If name is in the table, check answer will be ok */
3916 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3917 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003918
Eric Andersenc470f442003-07-28 09:56:35 +00003919 switch (cmdp->cmdtype) {
3920 default:
3921#if DEBUG
3922 abort();
3923#endif
3924 case CMDNORMAL:
3925 bit = DO_ALTPATH;
3926 break;
3927 case CMDFUNCTION:
3928 bit = DO_NOFUNC;
3929 break;
3930 case CMDBUILTIN:
3931 bit = DO_ALTBLTIN;
3932 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003933 }
Eric Andersenc470f442003-07-28 09:56:35 +00003934 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003935 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003936 cmdp = NULL;
3937 } else if (cmdp->rehash == 0)
3938 /* if not invalidated by cd, we're done */
3939 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003940 }
3941
3942 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003943 bcmd = find_builtin(name);
3944 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3945 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3946 )))
3947 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003948
3949 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003950 prev = -1; /* where to start */
3951 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003952 if (cmdp->cmdtype == CMDBUILTIN)
3953 prev = builtinloc;
3954 else
3955 prev = cmdp->param.index;
3956 }
3957
3958 e = ENOENT;
3959 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003960loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003961 while ((fullname = padvance(&path, name)) != NULL) {
3962 stunalloc(fullname);
3963 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003964 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003965 if (prefix(pathopt, "builtin")) {
3966 if (bcmd)
3967 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003968 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003969 } else if (!(act & DO_NOFUNC) &&
3970 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003971 /* handled below */
3972 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003973 /* ignore unimplemented options */
3974 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003975 }
3976 }
3977 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003978 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003979 if (idx < prev)
3980 continue;
3981 TRACE(("searchexec \"%s\": no change\n", name));
3982 goto success;
3983 }
3984 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003985#ifdef SYSV
3986 if (errno == EINTR)
3987 continue;
3988#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003989 if (errno != ENOENT && errno != ENOTDIR)
3990 e = errno;
3991 goto loop;
3992 }
Eric Andersenc470f442003-07-28 09:56:35 +00003993 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003994 if (!S_ISREG(statb.st_mode))
3995 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003996 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003997 stalloc(strlen(fullname) + 1);
3998 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00003999 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4000 cmdp->cmdtype != CMDFUNCTION)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004001 sh_error("%s not defined in %s", name, fullname);
Eric Andersencb57d552001-06-28 07:25:16 +00004002 stunalloc(fullname);
4003 goto success;
4004 }
Eric Andersencb57d552001-06-28 07:25:16 +00004005 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004006 if (!updatetbl) {
4007 entry->cmdtype = CMDNORMAL;
4008 entry->u.index = idx;
4009 return;
4010 }
4011 INTOFF;
4012 cmdp = cmdlookup(name, 1);
4013 cmdp->cmdtype = CMDNORMAL;
4014 cmdp->param.index = idx;
4015 INTON;
4016 goto success;
4017 }
4018
4019 /* We failed. If there was an entry for this command, delete it */
4020 if (cmdp && updatetbl)
4021 delete_cmd_entry();
4022 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004023 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004024 entry->cmdtype = CMDUNKNOWN;
4025 return;
4026
Eric Andersenc470f442003-07-28 09:56:35 +00004027builtin_success:
4028 if (!updatetbl) {
4029 entry->cmdtype = CMDBUILTIN;
4030 entry->u.cmd = bcmd;
4031 return;
4032 }
4033 INTOFF;
4034 cmdp = cmdlookup(name, 1);
4035 cmdp->cmdtype = CMDBUILTIN;
4036 cmdp->param.cmd = bcmd;
4037 INTON;
4038success:
Eric Andersencb57d552001-06-28 07:25:16 +00004039 cmdp->rehash = 0;
4040 entry->cmdtype = cmdp->cmdtype;
4041 entry->u = cmdp->param;
4042}
4043
4044
Eric Andersenc470f442003-07-28 09:56:35 +00004045/*
4046 * Wrapper around strcmp for qsort/bsearch/...
4047 */
4048static int pstrcmp(const void *a, const void *b)
4049{
4050 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4051}
Eric Andersencb57d552001-06-28 07:25:16 +00004052
4053/*
4054 * Search the table of builtin commands.
4055 */
4056
Eric Andersenc470f442003-07-28 09:56:35 +00004057static struct builtincmd *
4058find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004059{
4060 struct builtincmd *bp;
4061
Eric Andersenc470f442003-07-28 09:56:35 +00004062 bp = bsearch(
4063 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4064 pstrcmp
4065 );
Eric Andersencb57d552001-06-28 07:25:16 +00004066 return bp;
4067}
4068
4069
Eric Andersenc470f442003-07-28 09:56:35 +00004070
Eric Andersencb57d552001-06-28 07:25:16 +00004071/*
4072 * Called when a cd is done. Marks all commands so the next time they
4073 * are executed they will be rehashed.
4074 */
4075
Eric Andersenc470f442003-07-28 09:56:35 +00004076static void
4077hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004078{
Eric Andersencb57d552001-06-28 07:25:16 +00004079 struct tblentry **pp;
4080 struct tblentry *cmdp;
4081
Eric Andersenc470f442003-07-28 09:56:35 +00004082 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4083 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4084 if (cmdp->cmdtype == CMDNORMAL || (
4085 cmdp->cmdtype == CMDBUILTIN &&
4086 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4087 builtinloc > 0
4088 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004089 cmdp->rehash = 1;
4090 }
4091 }
4092}
4093
4094
4095
4096/*
Eric Andersenc470f442003-07-28 09:56:35 +00004097 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004098 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004099 * pathval() still returns the old value at this point.
4100 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004101 */
4102
Eric Andersenc470f442003-07-28 09:56:35 +00004103static void
4104changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004105{
Eric Andersenc470f442003-07-28 09:56:35 +00004106 const char *old, *new;
4107 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004108 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004109 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004110
Eric Andersenc470f442003-07-28 09:56:35 +00004111 old = pathval();
4112 new = newval;
4113 firstchange = 9999; /* assume no change */
4114 idx = 0;
4115 idx_bltin = -1;
4116 for (;;) {
4117 if (*old != *new) {
4118 firstchange = idx;
4119 if ((*old == '\0' && *new == ':')
4120 || (*old == ':' && *new == '\0'))
4121 firstchange++;
4122 old = new; /* ignore subsequent differences */
4123 }
4124 if (*new == '\0')
4125 break;
4126 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4127 idx_bltin = idx;
4128 if (*new == ':') {
4129 idx++;
4130 }
4131 new++, old++;
4132 }
4133 if (builtinloc < 0 && idx_bltin >= 0)
4134 builtinloc = idx_bltin; /* zap builtins */
4135 if (builtinloc >= 0 && idx_bltin < 0)
4136 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004137 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004138 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004139}
4140
4141
4142/*
4143 * Clear out command entries. The argument specifies the first entry in
4144 * PATH which has changed.
4145 */
4146
Eric Andersenc470f442003-07-28 09:56:35 +00004147static void
4148clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004149{
4150 struct tblentry **tblp;
4151 struct tblentry **pp;
4152 struct tblentry *cmdp;
4153
4154 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004155 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004156 pp = tblp;
4157 while ((cmdp = *pp) != NULL) {
4158 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004159 cmdp->param.index >= firstchange)
4160 || (cmdp->cmdtype == CMDBUILTIN &&
4161 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004162 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004163 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004164 } else {
4165 pp = &cmdp->next;
4166 }
4167 }
4168 }
4169 INTON;
4170}
4171
4172
Eric Andersenc470f442003-07-28 09:56:35 +00004173
Eric Andersencb57d552001-06-28 07:25:16 +00004174/*
Eric Andersencb57d552001-06-28 07:25:16 +00004175 * Locate a command in the command hash table. If "add" is nonzero,
4176 * add the command to the table if it is not already present. The
4177 * variable "lastcmdentry" is set to point to the address of the link
4178 * pointing to the entry, so that delete_cmd_entry can delete the
4179 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004180 *
4181 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004182 */
4183
Eric Andersen2870d962001-07-02 17:27:21 +00004184static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004185
Eric Andersenc470f442003-07-28 09:56:35 +00004186
4187static struct tblentry *
4188cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004189{
Eric Andersenc470f442003-07-28 09:56:35 +00004190 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004191 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004192 struct tblentry *cmdp;
4193 struct tblentry **pp;
4194
4195 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004196 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004197 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004198 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004199 hashval &= 0x7FFF;
4200 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004201 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004202 if (equal(cmdp->cmdname, name))
4203 break;
4204 pp = &cmdp->next;
4205 }
4206 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004207 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4208 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004209 cmdp->next = NULL;
4210 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004211 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004212 }
4213 lastcmdentry = pp;
4214 return cmdp;
4215}
4216
4217/*
4218 * Delete the command entry returned on the last lookup.
4219 */
4220
Eric Andersenc470f442003-07-28 09:56:35 +00004221static void
4222delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004223{
Eric Andersencb57d552001-06-28 07:25:16 +00004224 struct tblentry *cmdp;
4225
4226 INTOFF;
4227 cmdp = *lastcmdentry;
4228 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004229 if (cmdp->cmdtype == CMDFUNCTION)
4230 freefunc(cmdp->param.func);
4231 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004232 INTON;
4233}
4234
4235
Eric Andersenc470f442003-07-28 09:56:35 +00004236/*
4237 * Add a new command entry, replacing any existing command entry for
4238 * the same name - except special builtins.
4239 */
Eric Andersencb57d552001-06-28 07:25:16 +00004240
Rob Landley88621d72006-08-29 19:41:06 +00004241static void addcmdentry(char *name, struct cmdentry *entry)
Eric Andersenc470f442003-07-28 09:56:35 +00004242{
4243 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004244
Eric Andersenc470f442003-07-28 09:56:35 +00004245 cmdp = cmdlookup(name, 1);
4246 if (cmdp->cmdtype == CMDFUNCTION) {
4247 freefunc(cmdp->param.func);
4248 }
4249 cmdp->cmdtype = entry->cmdtype;
4250 cmdp->param = entry->u;
4251 cmdp->rehash = 0;
4252}
Eric Andersencb57d552001-06-28 07:25:16 +00004253
Eric Andersenc470f442003-07-28 09:56:35 +00004254/*
4255 * Make a copy of a parse tree.
4256 */
Eric Andersencb57d552001-06-28 07:25:16 +00004257
Rob Landley88621d72006-08-29 19:41:06 +00004258static struct funcnode * copyfunc(union node *n)
Eric Andersenc470f442003-07-28 09:56:35 +00004259{
4260 struct funcnode *f;
4261 size_t blocksize;
4262
4263 funcblocksize = offsetof(struct funcnode, n);
4264 funcstringsize = 0;
4265 calcsize(n);
4266 blocksize = funcblocksize;
4267 f = ckmalloc(blocksize + funcstringsize);
4268 funcblock = (char *) f + offsetof(struct funcnode, n);
4269 funcstring = (char *) f + blocksize;
4270 copynode(n);
4271 f->count = 0;
4272 return f;
4273}
4274
4275/*
4276 * Define a shell function.
4277 */
4278
4279static void
4280defun(char *name, union node *func)
4281{
4282 struct cmdentry entry;
4283
4284 INTOFF;
4285 entry.cmdtype = CMDFUNCTION;
4286 entry.u.func = copyfunc(func);
4287 addcmdentry(name, &entry);
4288 INTON;
4289}
Eric Andersencb57d552001-06-28 07:25:16 +00004290
4291
4292/*
4293 * Delete a function if it exists.
4294 */
4295
Eric Andersenc470f442003-07-28 09:56:35 +00004296static void
4297unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004298{
Eric Andersencb57d552001-06-28 07:25:16 +00004299 struct tblentry *cmdp;
4300
Eric Andersenc470f442003-07-28 09:56:35 +00004301 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4302 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004303 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004304}
4305
Eric Andersen2870d962001-07-02 17:27:21 +00004306/*
Eric Andersencb57d552001-06-28 07:25:16 +00004307 * Locate and print what a word is...
4308 */
4309
Eric Andersenc470f442003-07-28 09:56:35 +00004310
4311#ifdef CONFIG_ASH_CMDCMD
4312static int
4313describe_command(char *command, int describe_command_verbose)
4314#else
4315#define describe_command_verbose 1
4316static int
4317describe_command(char *command)
4318#endif
4319{
4320 struct cmdentry entry;
4321 struct tblentry *cmdp;
4322#ifdef CONFIG_ASH_ALIAS
4323 const struct alias *ap;
4324#endif
4325 const char *path = pathval();
4326
4327 if (describe_command_verbose) {
4328 out1str(command);
4329 }
4330
4331 /* First look at the keywords */
4332 if (findkwd(command)) {
4333 out1str(describe_command_verbose ? " is a shell keyword" : command);
4334 goto out;
4335 }
4336
4337#ifdef CONFIG_ASH_ALIAS
4338 /* Then look at the aliases */
4339 if ((ap = lookupalias(command, 0)) != NULL) {
4340 if (describe_command_verbose) {
4341 out1fmt(" is an alias for %s", ap->val);
4342 } else {
4343 out1str("alias ");
4344 printalias(ap);
4345 return 0;
4346 }
4347 goto out;
4348 }
4349#endif
4350 /* Then check if it is a tracked alias */
4351 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4352 entry.cmdtype = cmdp->cmdtype;
4353 entry.u = cmdp->param;
4354 } else {
4355 /* Finally use brute force */
4356 find_command(command, &entry, DO_ABS, path);
4357 }
4358
4359 switch (entry.cmdtype) {
4360 case CMDNORMAL: {
4361 int j = entry.u.index;
4362 char *p;
4363 if (j == -1) {
4364 p = command;
4365 } else {
4366 do {
4367 p = padvance(&path, command);
4368 stunalloc(p);
4369 } while (--j >= 0);
4370 }
4371 if (describe_command_verbose) {
4372 out1fmt(" is%s %s",
4373 (cmdp ? " a tracked alias for" : nullstr), p
4374 );
4375 } else {
4376 out1str(p);
4377 }
4378 break;
4379 }
4380
4381 case CMDFUNCTION:
4382 if (describe_command_verbose) {
4383 out1str(" is a shell function");
4384 } else {
4385 out1str(command);
4386 }
4387 break;
4388
4389 case CMDBUILTIN:
4390 if (describe_command_verbose) {
4391 out1fmt(" is a %sshell builtin",
4392 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4393 "special " : nullstr
4394 );
4395 } else {
4396 out1str(command);
4397 }
4398 break;
4399
4400 default:
4401 if (describe_command_verbose) {
4402 out1str(": not found\n");
4403 }
4404 return 127;
4405 }
4406
4407out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004408 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004409 return 0;
4410}
4411
4412static int
4413typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004414{
4415 int i;
4416 int err = 0;
4417
4418 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004419#ifdef CONFIG_ASH_CMDCMD
4420 err |= describe_command(argv[i], 1);
4421#else
4422 err |= describe_command(argv[i]);
4423#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004424 }
4425 return err;
4426}
4427
Eric Andersend35c5df2002-01-09 15:37:36 +00004428#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004429static int
4430commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004431{
4432 int c;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004433 enum {
4434 VERIFY_BRIEF = 1,
4435 VERIFY_VERBOSE = 2,
4436 } verify = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004437
4438 while ((c = nextopt("pvV")) != '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004439 if (c == 'V')
4440 verify |= VERIFY_VERBOSE;
4441 else if (c == 'v')
4442 verify |= VERIFY_BRIEF;
Eric Andersenc470f442003-07-28 09:56:35 +00004443#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004444 else if (c != 'p')
4445 abort();
Eric Andersenc470f442003-07-28 09:56:35 +00004446#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004447 if (verify)
4448 return describe_command(*argptr, verify - VERIFY_BRIEF);
Eric Andersencb57d552001-06-28 07:25:16 +00004449
4450 return 0;
4451}
Eric Andersen2870d962001-07-02 17:27:21 +00004452#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004453
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004454/* expand.c */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004455
Eric Andersencb57d552001-06-28 07:25:16 +00004456/*
4457 * Routines to expand arguments to commands. We have to deal with
4458 * backquotes, shell variables, and file metacharacters.
4459 */
Eric Andersenc470f442003-07-28 09:56:35 +00004460
Eric Andersencb57d552001-06-28 07:25:16 +00004461/*
4462 * _rmescape() flags
4463 */
Eric Andersenc470f442003-07-28 09:56:35 +00004464#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4465#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4466#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4467#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4468#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004469
4470/*
4471 * Structure specifying which parts of the string should be searched
4472 * for IFS characters.
4473 */
4474
4475struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004476 struct ifsregion *next; /* next region in list */
4477 int begoff; /* offset of start of region */
4478 int endoff; /* offset of end of region */
4479 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004480};
4481
Eric Andersenc470f442003-07-28 09:56:35 +00004482/* output of current string */
4483static char *expdest;
4484/* list of back quote expressions */
4485static struct nodelist *argbackq;
4486/* first struct in list of ifs regions */
4487static struct ifsregion ifsfirst;
4488/* last struct in list */
4489static struct ifsregion *ifslastp;
4490/* holds expanded arg list */
4491static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004492
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004493static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004494static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004495static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004496static const char *subevalvar(char *, char *, int, int, int, int, int);
4497static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004498static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004499static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004500static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004501static void recordregion(int, int, int);
4502static void removerecordregions(int);
4503static void ifsbreakup(char *, struct arglist *);
4504static void ifsfree(void);
4505static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004506static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004507
Eric Andersened9ecf72004-06-22 08:29:45 +00004508static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004509static size_t esclen(const char *, const char *);
4510static char *scanleft(char *, char *, char *, char *, int, int);
4511static char *scanright(char *, char *, char *, char *, int, int);
4512static void varunset(const char *, const char *, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00004513 ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004514
Eric Andersenc470f442003-07-28 09:56:35 +00004515
4516#define pmatch(a, b) !fnmatch((a), (b), 0)
4517/*
Eric Andersen90898442003-08-06 11:20:52 +00004518 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004519 *
4520 * Returns an stalloced string.
4521 */
4522
Rob Landley88621d72006-08-29 19:41:06 +00004523static char * preglob(const char *pattern, int quoted, int flag) {
Eric Andersenc470f442003-07-28 09:56:35 +00004524 flag |= RMESCAPE_GLOB;
4525 if (quoted) {
4526 flag |= RMESCAPE_QUOTED;
4527 }
4528 return _rmescapes((char *)pattern, flag);
4529}
4530
4531
4532static size_t
4533esclen(const char *start, const char *p) {
4534 size_t esc = 0;
4535
4536 while (p > start && *--p == CTLESC) {
4537 esc++;
4538 }
4539 return esc;
4540}
4541
Eric Andersencb57d552001-06-28 07:25:16 +00004542
4543/*
4544 * Expand shell variables and backquotes inside a here document.
4545 */
4546
Rob Landley88621d72006-08-29 19:41:06 +00004547static void expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004548{
Eric Andersencb57d552001-06-28 07:25:16 +00004549 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004550 expandarg(arg, (struct arglist *)NULL, 0);
Rob Landley53437472006-07-16 08:14:35 +00004551 full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004552}
4553
4554
4555/*
4556 * Perform variable substitution and command substitution on an argument,
4557 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4558 * perform splitting and file name expansion. When arglist is NULL, perform
4559 * here document expansion.
4560 */
4561
Eric Andersenc470f442003-07-28 09:56:35 +00004562void
4563expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004564{
4565 struct strlist *sp;
4566 char *p;
4567
4568 argbackq = arg->narg.backquote;
4569 STARTSTACKSTR(expdest);
4570 ifsfirst.next = NULL;
4571 ifslastp = NULL;
4572 argstr(arg->narg.text, flag);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004573 p = _STPUTC('\0', expdest);
4574 expdest = p - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004575 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004576 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004577 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004578 p = grabstackstr(p);
Eric Andersencb57d552001-06-28 07:25:16 +00004579 exparg.lastp = &exparg.list;
4580 /*
4581 * TODO - EXP_REDIR
4582 */
4583 if (flag & EXP_FULL) {
4584 ifsbreakup(p, &exparg);
4585 *exparg.lastp = NULL;
4586 exparg.lastp = &exparg.list;
4587 expandmeta(exparg.list, flag);
4588 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004589 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004590 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004591 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004592 sp->text = p;
4593 *exparg.lastp = sp;
4594 exparg.lastp = &sp->next;
4595 }
Eric Andersenc470f442003-07-28 09:56:35 +00004596 if (ifsfirst.next)
4597 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004598 *exparg.lastp = NULL;
4599 if (exparg.list) {
4600 *arglist->lastp = exparg.list;
4601 arglist->lastp = exparg.lastp;
4602 }
4603}
4604
4605
Eric Andersenc470f442003-07-28 09:56:35 +00004606/*
4607 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4608 * characters to allow for further processing. Otherwise treat
4609 * $@ like $* since no splitting will be performed.
4610 */
4611
4612static void
4613argstr(char *p, int flag)
4614{
4615 static const char spclchars[] = {
4616 '=',
4617 ':',
4618 CTLQUOTEMARK,
4619 CTLENDVAR,
4620 CTLESC,
4621 CTLVAR,
4622 CTLBACKQ,
4623 CTLBACKQ | CTLQUOTE,
4624#ifdef CONFIG_ASH_MATH_SUPPORT
4625 CTLENDARI,
4626#endif
4627 0
4628 };
4629 const char *reject = spclchars;
4630 int c;
4631 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4632 int breakall = flag & EXP_WORD;
4633 int inquotes;
4634 size_t length;
4635 int startloc;
4636
4637 if (!(flag & EXP_VARTILDE)) {
4638 reject += 2;
4639 } else if (flag & EXP_VARTILDE2) {
4640 reject++;
4641 }
4642 inquotes = 0;
4643 length = 0;
4644 if (flag & EXP_TILDE) {
4645 char *q;
4646
4647 flag &= ~EXP_TILDE;
4648tilde:
4649 q = p;
4650 if (*q == CTLESC && (flag & EXP_QWORD))
4651 q++;
4652 if (*q == '~')
4653 p = exptilde(p, q, flag);
4654 }
4655start:
4656 startloc = expdest - (char *)stackblock();
4657 for (;;) {
4658 length += strcspn(p + length, reject);
4659 c = p[length];
4660 if (c && (!(c & 0x80)
4661#ifdef CONFIG_ASH_MATH_SUPPORT
4662 || c == CTLENDARI
4663#endif
4664 )) {
4665 /* c == '=' || c == ':' || c == CTLENDARI */
4666 length++;
4667 }
4668 if (length > 0) {
4669 int newloc;
4670 expdest = stnputs(p, length, expdest);
4671 newloc = expdest - (char *)stackblock();
4672 if (breakall && !inquotes && newloc > startloc) {
4673 recordregion(startloc, newloc, 0);
4674 }
4675 startloc = newloc;
4676 }
4677 p += length + 1;
4678 length = 0;
4679
4680 switch (c) {
4681 case '\0':
4682 goto breakloop;
4683 case '=':
4684 if (flag & EXP_VARTILDE2) {
4685 p--;
4686 continue;
4687 }
4688 flag |= EXP_VARTILDE2;
4689 reject++;
4690 /* fall through */
4691 case ':':
4692 /*
4693 * sort of a hack - expand tildes in variable
4694 * assignments (after the first '=' and after ':'s).
4695 */
4696 if (*--p == '~') {
4697 goto tilde;
4698 }
4699 continue;
4700 }
4701
4702 switch (c) {
4703 case CTLENDVAR: /* ??? */
4704 goto breakloop;
4705 case CTLQUOTEMARK:
4706 /* "$@" syntax adherence hack */
4707 if (
4708 !inquotes &&
4709 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4710 (p[4] == CTLQUOTEMARK || (
4711 p[4] == CTLENDVAR &&
4712 p[5] == CTLQUOTEMARK
4713 ))
4714 ) {
4715 p = evalvar(p + 1, flag) + 1;
4716 goto start;
4717 }
4718 inquotes = !inquotes;
4719addquote:
4720 if (quotes) {
4721 p--;
4722 length++;
4723 startloc++;
4724 }
4725 break;
4726 case CTLESC:
4727 startloc++;
4728 length++;
4729 goto addquote;
4730 case CTLVAR:
4731 p = evalvar(p, flag);
4732 goto start;
4733 case CTLBACKQ:
4734 c = 0;
4735 case CTLBACKQ|CTLQUOTE:
4736 expbackq(argbackq->n, c, quotes);
4737 argbackq = argbackq->next;
4738 goto start;
4739#ifdef CONFIG_ASH_MATH_SUPPORT
4740 case CTLENDARI:
4741 p--;
4742 expari(quotes);
4743 goto start;
4744#endif
4745 }
4746 }
4747breakloop:
4748 ;
4749}
4750
4751static char *
4752exptilde(char *startp, char *p, int flag)
4753{
4754 char c;
4755 char *name;
4756 struct passwd *pw;
4757 const char *home;
4758 int quotes = flag & (EXP_FULL | EXP_CASE);
4759 int startloc;
4760
4761 name = p + 1;
4762
4763 while ((c = *++p) != '\0') {
4764 switch(c) {
4765 case CTLESC:
4766 return (startp);
4767 case CTLQUOTEMARK:
4768 return (startp);
4769 case ':':
4770 if (flag & EXP_VARTILDE)
4771 goto done;
4772 break;
4773 case '/':
4774 case CTLENDVAR:
4775 goto done;
4776 }
4777 }
4778done:
4779 *p = '\0';
4780 if (*name == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004781 home = lookupvar(homestr);
Eric Andersenc470f442003-07-28 09:56:35 +00004782 } else {
4783 if ((pw = getpwnam(name)) == NULL)
4784 goto lose;
4785 home = pw->pw_dir;
4786 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004787 if (!home || !*home)
Eric Andersenc470f442003-07-28 09:56:35 +00004788 goto lose;
4789 *p = c;
4790 startloc = expdest - (char *)stackblock();
4791 strtodest(home, SQSYNTAX, quotes);
4792 recordregion(startloc, expdest - (char *)stackblock(), 0);
4793 return (p);
4794lose:
4795 *p = c;
4796 return (startp);
4797}
4798
4799
4800static void
4801removerecordregions(int endoff)
4802{
4803 if (ifslastp == NULL)
4804 return;
4805
4806 if (ifsfirst.endoff > endoff) {
4807 while (ifsfirst.next != NULL) {
4808 struct ifsregion *ifsp;
4809 INTOFF;
4810 ifsp = ifsfirst.next->next;
4811 ckfree(ifsfirst.next);
4812 ifsfirst.next = ifsp;
4813 INTON;
4814 }
4815 if (ifsfirst.begoff > endoff)
4816 ifslastp = NULL;
4817 else {
4818 ifslastp = &ifsfirst;
4819 ifsfirst.endoff = endoff;
4820 }
4821 return;
4822 }
4823
4824 ifslastp = &ifsfirst;
4825 while (ifslastp->next && ifslastp->next->begoff < endoff)
4826 ifslastp=ifslastp->next;
4827 while (ifslastp->next != NULL) {
4828 struct ifsregion *ifsp;
4829 INTOFF;
4830 ifsp = ifslastp->next->next;
4831 ckfree(ifslastp->next);
4832 ifslastp->next = ifsp;
4833 INTON;
4834 }
4835 if (ifslastp->endoff > endoff)
4836 ifslastp->endoff = endoff;
4837}
4838
4839
4840#ifdef CONFIG_ASH_MATH_SUPPORT
4841/*
4842 * Expand arithmetic expression. Backup to start of expression,
4843 * evaluate, place result in (backed up) result, adjust string position.
4844 */
4845void
4846expari(int quotes)
4847{
4848 char *p, *start;
4849 int begoff;
4850 int flag;
4851 int len;
4852
4853 /* ifsfree(); */
4854
4855 /*
4856 * This routine is slightly over-complicated for
4857 * efficiency. Next we scan backwards looking for the
4858 * start of arithmetic.
4859 */
4860 start = stackblock();
4861 p = expdest - 1;
4862 *p = '\0';
4863 p--;
4864 do {
4865 int esc;
4866
4867 while (*p != CTLARI) {
4868 p--;
4869#ifdef DEBUG
4870 if (p < start) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004871 sh_error("missing CTLARI (shouldn't happen)");
Eric Andersenc470f442003-07-28 09:56:35 +00004872 }
4873#endif
4874 }
4875
4876 esc = esclen(start, p);
4877 if (!(esc % 2)) {
4878 break;
4879 }
4880
4881 p -= esc + 1;
4882 } while (1);
4883
4884 begoff = p - start;
4885
4886 removerecordregions(begoff);
4887
4888 flag = p[1];
4889
4890 expdest = p;
4891
4892 if (quotes)
4893 rmescapes(p + 2);
4894
4895 len = cvtnum(dash_arith(p + 2));
4896
4897 if (flag != '"')
4898 recordregion(begoff, begoff + len, 0);
4899}
4900#endif
4901
4902/*
4903 * Expand stuff in backwards quotes.
4904 */
4905
4906static void
4907expbackq(union node *cmd, int quoted, int quotes)
4908{
4909 struct backcmd in;
4910 int i;
4911 char buf[128];
4912 char *p;
4913 char *dest;
4914 int startloc;
4915 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4916 struct stackmark smark;
4917
4918 INTOFF;
4919 setstackmark(&smark);
4920 dest = expdest;
4921 startloc = dest - (char *)stackblock();
4922 grabstackstr(dest);
4923 evalbackcmd(cmd, (struct backcmd *) &in);
4924 popstackmark(&smark);
4925
4926 p = in.buf;
4927 i = in.nleft;
4928 if (i == 0)
4929 goto read;
4930 for (;;) {
4931 memtodest(p, i, syntax, quotes);
4932read:
4933 if (in.fd < 0)
4934 break;
4935 i = safe_read(in.fd, buf, sizeof buf);
4936 TRACE(("expbackq: read returns %d\n", i));
4937 if (i <= 0)
4938 break;
4939 p = buf;
4940 }
4941
4942 if (in.buf)
4943 ckfree(in.buf);
4944 if (in.fd >= 0) {
4945 close(in.fd);
4946 back_exitstatus = waitforjob(in.jp);
4947 }
4948 INTON;
4949
4950 /* Eat all trailing newlines */
4951 dest = expdest;
4952 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4953 STUNPUTC(dest);
4954 expdest = dest;
4955
4956 if (quoted == 0)
4957 recordregion(startloc, dest - (char *)stackblock(), 0);
4958 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4959 (dest - (char *)stackblock()) - startloc,
4960 (dest - (char *)stackblock()) - startloc,
4961 stackblock() + startloc));
4962}
4963
4964
4965static char *
Eric Andersen90898442003-08-06 11:20:52 +00004966scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4967 int zero)
4968{
Eric Andersenc470f442003-07-28 09:56:35 +00004969 char *loc;
4970 char *loc2;
4971 char c;
4972
4973 loc = startp;
4974 loc2 = rmesc;
4975 do {
4976 int match;
4977 const char *s = loc2;
4978 c = *loc2;
4979 if (zero) {
4980 *loc2 = '\0';
4981 s = rmesc;
4982 }
4983 match = pmatch(str, s);
4984 *loc2 = c;
4985 if (match)
4986 return loc;
4987 if (quotes && *loc == CTLESC)
4988 loc++;
4989 loc++;
4990 loc2++;
4991 } while (c);
4992 return 0;
4993}
4994
4995
4996static char *
Eric Andersen90898442003-08-06 11:20:52 +00004997scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4998 int zero)
4999{
Eric Andersenc470f442003-07-28 09:56:35 +00005000 int esc = 0;
5001 char *loc;
5002 char *loc2;
5003
5004 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5005 int match;
5006 char c = *loc2;
5007 const char *s = loc2;
5008 if (zero) {
5009 *loc2 = '\0';
5010 s = rmesc;
5011 }
5012 match = pmatch(str, s);
5013 *loc2 = c;
5014 if (match)
5015 return loc;
5016 loc--;
5017 if (quotes) {
5018 if (--esc < 0) {
5019 esc = esclen(startp, loc);
5020 }
5021 if (esc % 2) {
5022 esc--;
5023 loc--;
5024 }
5025 }
5026 }
5027 return 0;
5028}
5029
5030static const char *
5031subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5032{
5033 char *startp;
5034 char *loc;
5035 int saveherefd = herefd;
5036 struct nodelist *saveargbackq = argbackq;
5037 int amount;
5038 char *rmesc, *rmescend;
5039 int zero;
5040 char *(*scan)(char *, char *, char *, char *, int , int);
5041
5042 herefd = -1;
5043 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5044 STPUTC('\0', expdest);
5045 herefd = saveherefd;
5046 argbackq = saveargbackq;
5047 startp = stackblock() + startloc;
5048
5049 switch (subtype) {
5050 case VSASSIGN:
5051 setvar(str, startp, 0);
5052 amount = startp - expdest;
5053 STADJUST(amount, expdest);
5054 return startp;
5055
5056 case VSQUESTION:
5057 varunset(p, str, startp, varflags);
5058 /* NOTREACHED */
5059 }
5060
5061 subtype -= VSTRIMRIGHT;
5062#ifdef DEBUG
5063 if (subtype < 0 || subtype > 3)
5064 abort();
5065#endif
5066
5067 rmesc = startp;
5068 rmescend = stackblock() + strloc;
5069 if (quotes) {
5070 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5071 if (rmesc != startp) {
5072 rmescend = expdest;
5073 startp = stackblock() + startloc;
5074 }
5075 }
5076 rmescend--;
5077 str = stackblock() + strloc;
5078 preglob(str, varflags & VSQUOTE, 0);
5079
5080 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5081 zero = subtype >> 1;
5082 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5083 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5084
5085 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5086 if (loc) {
5087 if (zero) {
5088 memmove(startp, loc, str - loc);
5089 loc = startp + (str - loc) - 1;
5090 }
5091 *loc = '\0';
5092 amount = loc - expdest;
5093 STADJUST(amount, expdest);
5094 }
5095 return loc;
5096}
5097
5098
Eric Andersen62483552001-07-10 06:09:16 +00005099/*
5100 * Expand a variable, and return a pointer to the next character in the
5101 * input string.
5102 */
Eric Andersenc470f442003-07-28 09:56:35 +00005103static char *
5104evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005105{
5106 int subtype;
5107 int varflags;
5108 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005109 int patloc;
5110 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005111 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005112 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005113 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005114 int quotes;
5115 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005116
Eric Andersenc470f442003-07-28 09:56:35 +00005117 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005118 varflags = *p++;
5119 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005120 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005121 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005122 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005123 startloc = expdest - (char *)stackblock();
5124 p = strchr(p, '=') + 1;
5125
Eric Andersenc470f442003-07-28 09:56:35 +00005126again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005127 varlen = varvalue(var, varflags, flag);
5128 if (varflags & VSNUL)
5129 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005130
Glenn L McGrath76620622004-01-13 10:19:37 +00005131 if (subtype == VSPLUS) {
5132 varlen = -1 - varlen;
5133 goto vsplus;
5134 }
Eric Andersen62483552001-07-10 06:09:16 +00005135
Eric Andersenc470f442003-07-28 09:56:35 +00005136 if (subtype == VSMINUS) {
5137vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005138 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005139 argstr(
5140 p, flag | EXP_TILDE |
5141 (quoted ? EXP_QWORD : EXP_WORD)
5142 );
5143 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005144 }
5145 if (easy)
5146 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005147 goto end;
5148 }
Eric Andersen62483552001-07-10 06:09:16 +00005149
Eric Andersenc470f442003-07-28 09:56:35 +00005150 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005151 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005152 if (subevalvar(p, var, 0, subtype, startloc,
5153 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005154 varflags &= ~VSNUL;
5155 /*
5156 * Remove any recorded regions beyond
5157 * start of variable
5158 */
5159 removerecordregions(startloc);
5160 goto again;
5161 }
Eric Andersenc470f442003-07-28 09:56:35 +00005162 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005163 }
5164 if (easy)
5165 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005166 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005167 }
5168
Glenn L McGrath76620622004-01-13 10:19:37 +00005169 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005170 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005171
Eric Andersenc470f442003-07-28 09:56:35 +00005172 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005173 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005174 goto record;
5175 }
5176
5177 if (subtype == VSNORMAL) {
5178 if (!easy)
5179 goto end;
5180record:
5181 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5182 goto end;
5183 }
5184
5185#ifdef DEBUG
5186 switch (subtype) {
5187 case VSTRIMLEFT:
5188 case VSTRIMLEFTMAX:
5189 case VSTRIMRIGHT:
5190 case VSTRIMRIGHTMAX:
5191 break;
5192 default:
5193 abort();
5194 }
5195#endif
5196
Glenn L McGrath76620622004-01-13 10:19:37 +00005197 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005198 /*
5199 * Terminate the string and start recording the pattern
5200 * right after it
5201 */
5202 STPUTC('\0', expdest);
5203 patloc = expdest - (char *)stackblock();
5204 if (subevalvar(p, NULL, patloc, subtype,
5205 startloc, varflags, quotes) == 0) {
5206 int amount = expdest - (
5207 (char *)stackblock() + patloc - 1
5208 );
5209 STADJUST(-amount, expdest);
5210 }
5211 /* Remove any recorded regions beyond start of variable */
5212 removerecordregions(startloc);
5213 goto record;
5214 }
5215
5216end:
5217 if (subtype != VSNORMAL) { /* skip to end of alternative */
5218 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005219 for (;;) {
5220 if ((c = *p++) == CTLESC)
5221 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005222 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005223 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005224 argbackq = argbackq->next;
5225 } else if (c == CTLVAR) {
5226 if ((*p++ & VSTYPE) != VSNORMAL)
5227 nesting++;
5228 } else if (c == CTLENDVAR) {
5229 if (--nesting == 0)
5230 break;
5231 }
5232 }
5233 }
5234 return p;
5235}
5236
Eric Andersencb57d552001-06-28 07:25:16 +00005237
Eric Andersencb57d552001-06-28 07:25:16 +00005238/*
5239 * Put a string on the stack.
5240 */
5241
Eric Andersenc470f442003-07-28 09:56:35 +00005242static void
5243memtodest(const char *p, size_t len, int syntax, int quotes) {
5244 char *q = expdest;
5245
5246 q = makestrspace(len * 2, q);
5247
5248 while (len--) {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005249 int c = SC2INT(*p++);
Eric Andersenc470f442003-07-28 09:56:35 +00005250 if (!c)
5251 continue;
5252 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5253 USTPUTC(CTLESC, q);
5254 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005255 }
Eric Andersenc470f442003-07-28 09:56:35 +00005256
5257 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005258}
5259
Eric Andersenc470f442003-07-28 09:56:35 +00005260
5261static void
5262strtodest(const char *p, int syntax, int quotes)
5263{
5264 memtodest(p, strlen(p), syntax, quotes);
5265}
5266
5267
Eric Andersencb57d552001-06-28 07:25:16 +00005268/*
5269 * Add the value of a specialized variable to the stack string.
5270 */
5271
Glenn L McGrath76620622004-01-13 10:19:37 +00005272static ssize_t
5273varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005274{
5275 int num;
5276 char *p;
5277 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005278 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005279 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005280 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005281 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005282 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005283 int quoted = varflags & VSQUOTE;
5284 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005285 int quotes = flags & (EXP_FULL | EXP_CASE);
5286
Glenn L McGrath76620622004-01-13 10:19:37 +00005287 if (quoted && (flags & EXP_FULL))
5288 sep = 1 << CHAR_BIT;
5289
Eric Andersencb57d552001-06-28 07:25:16 +00005290 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5291 switch (*name) {
5292 case '$':
5293 num = rootpid;
5294 goto numvar;
5295 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005296 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005297 goto numvar;
5298 case '#':
5299 num = shellparam.nparam;
5300 goto numvar;
5301 case '!':
5302 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005303 if (num == 0)
5304 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005305numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005306 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005307 break;
5308 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005309 p = makestrspace(NOPTS, expdest);
5310 for (i = NOPTS - 1; i >= 0; i--) {
5311 if (optlist[i]) {
5312 USTPUTC(optletters(i), p);
5313 len++;
5314 }
Eric Andersencb57d552001-06-28 07:25:16 +00005315 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005316 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005317 break;
5318 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005319 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005320 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005321 /* fall through */
5322 case '*':
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005323 sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005324 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5325 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005326param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005327 if (!(ap = shellparam.p))
5328 return -1;
5329 while ((p = *ap++)) {
5330 size_t partlen;
5331
5332 partlen = strlen(p);
Glenn L McGrath76620622004-01-13 10:19:37 +00005333 len += partlen;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00005334
5335 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5336 memtodest(p, partlen, syntax, quotes);
5337
5338 if (*ap && sep) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005339 char *q;
5340
5341 len++;
5342 if (subtype == VSPLUS || subtype == VSLENGTH) {
5343 continue;
5344 }
5345 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005346 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005347 STPUTC(CTLESC, q);
5348 STPUTC(sep, q);
5349 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005350 }
5351 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005352 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005353 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005354 case '1':
5355 case '2':
5356 case '3':
5357 case '4':
5358 case '5':
5359 case '6':
5360 case '7':
5361 case '8':
5362 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005363 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005364 if (num < 0 || num > shellparam.nparam)
5365 return -1;
5366 p = num ? shellparam.p[num - 1] : arg0;
5367 goto value;
5368 default:
5369 p = lookupvar(name);
5370value:
5371 if (!p)
5372 return -1;
5373
5374 len = strlen(p);
5375 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5376 memtodest(p, len, syntax, quotes);
5377 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005378 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005379
5380 if (subtype == VSPLUS || subtype == VSLENGTH)
5381 STADJUST(-len, expdest);
5382 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005383}
5384
5385
Eric Andersencb57d552001-06-28 07:25:16 +00005386/*
5387 * Record the fact that we have to scan this region of the
5388 * string for IFS characters.
5389 */
5390
Eric Andersenc470f442003-07-28 09:56:35 +00005391static void
5392recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005393{
5394 struct ifsregion *ifsp;
5395
5396 if (ifslastp == NULL) {
5397 ifsp = &ifsfirst;
5398 } else {
5399 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005400 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005401 ifsp->next = NULL;
5402 ifslastp->next = ifsp;
5403 INTON;
5404 }
5405 ifslastp = ifsp;
5406 ifslastp->begoff = start;
5407 ifslastp->endoff = end;
5408 ifslastp->nulonly = nulonly;
5409}
5410
5411
Eric Andersencb57d552001-06-28 07:25:16 +00005412/*
5413 * Break the argument string into pieces based upon IFS and add the
5414 * strings to the argument list. The regions of the string to be
5415 * searched for IFS characters have been stored by recordregion.
5416 */
Eric Andersenc470f442003-07-28 09:56:35 +00005417static void
5418ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005419{
Eric Andersencb57d552001-06-28 07:25:16 +00005420 struct ifsregion *ifsp;
5421 struct strlist *sp;
5422 char *start;
5423 char *p;
5424 char *q;
5425 const char *ifs, *realifs;
5426 int ifsspc;
5427 int nulonly;
5428
5429
5430 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005431 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005432 ifsspc = 0;
5433 nulonly = 0;
5434 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005435 ifsp = &ifsfirst;
5436 do {
5437 p = string + ifsp->begoff;
5438 nulonly = ifsp->nulonly;
5439 ifs = nulonly ? nullstr : realifs;
5440 ifsspc = 0;
5441 while (p < string + ifsp->endoff) {
5442 q = p;
5443 if (*p == CTLESC)
5444 p++;
5445 if (strchr(ifs, *p)) {
5446 if (!nulonly)
5447 ifsspc = (strchr(defifs, *p) != NULL);
5448 /* Ignore IFS whitespace at start */
5449 if (q == start && ifsspc) {
5450 p++;
5451 start = p;
5452 continue;
5453 }
5454 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005455 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005456 sp->text = start;
5457 *arglist->lastp = sp;
5458 arglist->lastp = &sp->next;
5459 p++;
5460 if (!nulonly) {
5461 for (;;) {
5462 if (p >= string + ifsp->endoff) {
5463 break;
5464 }
5465 q = p;
5466 if (*p == CTLESC)
5467 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005468 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005469 p = q;
5470 break;
5471 } else if (strchr(defifs, *p) == NULL) {
5472 if (ifsspc) {
5473 p++;
5474 ifsspc = 0;
5475 } else {
5476 p = q;
5477 break;
5478 }
5479 } else
5480 p++;
5481 }
5482 }
5483 start = p;
5484 } else
5485 p++;
5486 }
5487 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005488 if (nulonly)
5489 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005490 }
5491
Eric Andersenc470f442003-07-28 09:56:35 +00005492 if (!*start)
5493 return;
5494
5495add:
5496 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005497 sp->text = start;
5498 *arglist->lastp = sp;
5499 arglist->lastp = &sp->next;
5500}
5501
Eric Andersenc470f442003-07-28 09:56:35 +00005502static void
5503ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005504{
Eric Andersenc470f442003-07-28 09:56:35 +00005505 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005506
Eric Andersenc470f442003-07-28 09:56:35 +00005507 INTOFF;
5508 p = ifsfirst.next;
5509 do {
5510 struct ifsregion *ifsp;
5511 ifsp = p->next;
5512 ckfree(p);
5513 p = ifsp;
5514 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005515 ifslastp = NULL;
5516 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005517 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005518}
5519
Eric Andersen90898442003-08-06 11:20:52 +00005520static void expmeta(char *, char *);
5521static struct strlist *expsort(struct strlist *);
5522static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005523
Eric Andersen90898442003-08-06 11:20:52 +00005524static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005525
Eric Andersencb57d552001-06-28 07:25:16 +00005526
Eric Andersenc470f442003-07-28 09:56:35 +00005527static void
Eric Andersen90898442003-08-06 11:20:52 +00005528expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005529{
Eric Andersen90898442003-08-06 11:20:52 +00005530 static const char metachars[] = {
5531 '*', '?', '[', 0
5532 };
Eric Andersencb57d552001-06-28 07:25:16 +00005533 /* TODO - EXP_REDIR */
5534
5535 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005536 struct strlist **savelastp;
5537 struct strlist *sp;
5538 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005539
Eric Andersencb57d552001-06-28 07:25:16 +00005540 if (fflag)
5541 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005542 if (!strpbrk(str->text, metachars))
5543 goto nometa;
5544 savelastp = exparg.lastp;
5545
Eric Andersencb57d552001-06-28 07:25:16 +00005546 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005547 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005548 {
5549 int i = strlen(str->text);
5550 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5551 }
5552
5553 expmeta(expdir, p);
5554 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005555 if (p != str->text)
5556 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005557 INTON;
5558 if (exparg.lastp == savelastp) {
5559 /*
5560 * no matches
5561 */
Eric Andersenc470f442003-07-28 09:56:35 +00005562nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005563 *exparg.lastp = str;
5564 rmescapes(str->text);
5565 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005566 } else {
5567 *exparg.lastp = NULL;
5568 *savelastp = sp = expsort(*savelastp);
5569 while (sp->next != NULL)
5570 sp = sp->next;
5571 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005572 }
5573 str = str->next;
5574 }
5575}
5576
Eric Andersencb57d552001-06-28 07:25:16 +00005577/*
Eric Andersenc470f442003-07-28 09:56:35 +00005578 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005579 */
5580
Eric Andersenc470f442003-07-28 09:56:35 +00005581static void
Eric Andersen90898442003-08-06 11:20:52 +00005582addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005583{
Eric Andersencb57d552001-06-28 07:25:16 +00005584 struct strlist *sp;
5585
Eric Andersenc470f442003-07-28 09:56:35 +00005586 sp = (struct strlist *)stalloc(sizeof *sp);
5587 sp->text = sstrdup(name);
5588 *exparg.lastp = sp;
5589 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005590}
5591
5592
Eric Andersencb57d552001-06-28 07:25:16 +00005593/*
Eric Andersen90898442003-08-06 11:20:52 +00005594 * Do metacharacter (i.e. *, ?, [...]) expansion.
5595 */
5596
5597static void
5598expmeta(char *enddir, char *name)
5599{
5600 char *p;
5601 const char *cp;
5602 char *start;
5603 char *endname;
5604 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005605 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005606 DIR *dirp;
5607 struct dirent *dp;
5608 int atend;
5609 int matchdot;
5610
5611 metaflag = 0;
5612 start = name;
5613 for (p = name; *p; p++) {
5614 if (*p == '*' || *p == '?')
5615 metaflag = 1;
5616 else if (*p == '[') {
5617 char *q = p + 1;
5618 if (*q == '!')
5619 q++;
5620 for (;;) {
5621 if (*q == '\\')
5622 q++;
5623 if (*q == '/' || *q == '\0')
5624 break;
5625 if (*++q == ']') {
5626 metaflag = 1;
5627 break;
5628 }
5629 }
5630 } else if (*p == '\\')
5631 p++;
5632 else if (*p == '/') {
5633 if (metaflag)
5634 goto out;
5635 start = p + 1;
5636 }
5637 }
5638out:
5639 if (metaflag == 0) { /* we've reached the end of the file name */
5640 if (enddir != expdir)
5641 metaflag++;
5642 p = name;
5643 do {
5644 if (*p == '\\')
5645 p++;
5646 *enddir++ = *p;
5647 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005648 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005649 addfname(expdir);
5650 return;
5651 }
5652 endname = p;
5653 if (name < start) {
5654 p = name;
5655 do {
5656 if (*p == '\\')
5657 p++;
5658 *enddir++ = *p++;
5659 } while (p < start);
5660 }
5661 if (enddir == expdir) {
5662 cp = ".";
5663 } else if (enddir == expdir + 1 && *expdir == '/') {
5664 cp = "/";
5665 } else {
5666 cp = expdir;
5667 enddir[-1] = '\0';
5668 }
5669 if ((dirp = opendir(cp)) == NULL)
5670 return;
5671 if (enddir != expdir)
5672 enddir[-1] = '/';
5673 if (*endname == 0) {
5674 atend = 1;
5675 } else {
5676 atend = 0;
5677 *endname++ = '\0';
5678 }
5679 matchdot = 0;
5680 p = start;
5681 if (*p == '\\')
5682 p++;
5683 if (*p == '.')
5684 matchdot++;
5685 while (! intpending && (dp = readdir(dirp)) != NULL) {
5686 if (dp->d_name[0] == '.' && ! matchdot)
5687 continue;
5688 if (pmatch(start, dp->d_name)) {
5689 if (atend) {
5690 scopy(dp->d_name, enddir);
5691 addfname(expdir);
5692 } else {
5693 for (p = enddir, cp = dp->d_name;
5694 (*p++ = *cp++) != '\0';)
5695 continue;
5696 p[-1] = '/';
5697 expmeta(p, endname);
5698 }
5699 }
5700 }
5701 closedir(dirp);
5702 if (! atend)
5703 endname[-1] = '/';
5704}
5705
5706/*
5707 * Sort the results of file name expansion. It calculates the number of
5708 * strings to sort and then calls msort (short for merge sort) to do the
5709 * work.
5710 */
5711
5712static struct strlist *
5713expsort(struct strlist *str)
5714{
5715 int len;
5716 struct strlist *sp;
5717
5718 len = 0;
5719 for (sp = str ; sp ; sp = sp->next)
5720 len++;
5721 return msort(str, len);
5722}
5723
5724
5725static struct strlist *
5726msort(struct strlist *list, int len)
5727{
5728 struct strlist *p, *q = NULL;
5729 struct strlist **lpp;
5730 int half;
5731 int n;
5732
5733 if (len <= 1)
5734 return list;
5735 half = len >> 1;
5736 p = list;
5737 for (n = half ; --n >= 0 ; ) {
5738 q = p;
5739 p = p->next;
5740 }
5741 q->next = NULL; /* terminate first half of list */
5742 q = msort(list, half); /* sort first half of list */
5743 p = msort(p, len - half); /* sort second half */
5744 lpp = &list;
5745 for (;;) {
5746#ifdef CONFIG_LOCALE_SUPPORT
5747 if (strcoll(p->text, q->text) < 0)
5748#else
5749 if (strcmp(p->text, q->text) < 0)
5750#endif
5751 {
5752 *lpp = p;
5753 lpp = &p->next;
5754 if ((p = *lpp) == NULL) {
5755 *lpp = q;
5756 break;
5757 }
5758 } else {
5759 *lpp = q;
5760 lpp = &q->next;
5761 if ((q = *lpp) == NULL) {
5762 *lpp = p;
5763 break;
5764 }
5765 }
5766 }
5767 return list;
5768}
5769
5770
5771/*
Eric Andersencb57d552001-06-28 07:25:16 +00005772 * Returns true if the pattern matches the string.
5773 */
5774
Rob Landley88621d72006-08-29 19:41:06 +00005775static int patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005776{
Eric Andersenc470f442003-07-28 09:56:35 +00005777 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005778}
5779
5780
Eric Andersencb57d552001-06-28 07:25:16 +00005781/*
5782 * Remove any CTLESC characters from a string.
5783 */
5784
Eric Andersenc470f442003-07-28 09:56:35 +00005785static char *
5786_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005787{
5788 char *p, *q, *r;
5789 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005790 unsigned inquotes;
5791 int notescaped;
5792 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005793
5794 p = strpbrk(str, qchars);
5795 if (!p) {
5796 return str;
5797 }
5798 q = p;
5799 r = str;
5800 if (flag & RMESCAPE_ALLOC) {
5801 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005802 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005803
Eric Andersenc470f442003-07-28 09:56:35 +00005804 if (flag & RMESCAPE_GROW) {
5805 r = makestrspace(fulllen, expdest);
5806 } else if (flag & RMESCAPE_HEAP) {
5807 r = ckmalloc(fulllen);
5808 } else {
5809 r = stalloc(fulllen);
5810 }
5811 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005812 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005813 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005814 }
5815 }
Eric Andersenc470f442003-07-28 09:56:35 +00005816 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5817 globbing = flag & RMESCAPE_GLOB;
5818 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005819 while (*p) {
5820 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005821 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005822 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005823 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005824 continue;
5825 }
Eric Andersenc470f442003-07-28 09:56:35 +00005826 if (*p == '\\') {
5827 /* naked back slash */
5828 notescaped = 0;
5829 goto copy;
5830 }
Eric Andersencb57d552001-06-28 07:25:16 +00005831 if (*p == CTLESC) {
5832 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005833 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005834 *q++ = '\\';
5835 }
5836 }
Eric Andersenc470f442003-07-28 09:56:35 +00005837 notescaped = globbing;
5838copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005839 *q++ = *p++;
5840 }
5841 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005842 if (flag & RMESCAPE_GROW) {
5843 expdest = r;
5844 STADJUST(q - r + 1, expdest);
5845 }
Eric Andersencb57d552001-06-28 07:25:16 +00005846 return r;
5847}
Eric Andersencb57d552001-06-28 07:25:16 +00005848
5849
Eric Andersencb57d552001-06-28 07:25:16 +00005850/*
5851 * See if a pattern matches in a case statement.
5852 */
5853
Eric Andersenc470f442003-07-28 09:56:35 +00005854int
5855casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005856{
Eric Andersencb57d552001-06-28 07:25:16 +00005857 struct stackmark smark;
5858 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005859
5860 setstackmark(&smark);
5861 argbackq = pattern->narg.backquote;
5862 STARTSTACKSTR(expdest);
5863 ifslastp = NULL;
5864 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005865 STACKSTRNUL(expdest);
5866 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005867 popstackmark(&smark);
5868 return result;
5869}
5870
5871/*
5872 * Our own itoa().
5873 */
5874
Eric Andersenc470f442003-07-28 09:56:35 +00005875static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005876cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005877{
Eric Andersencb57d552001-06-28 07:25:16 +00005878 int len;
5879
Eric Andersenc470f442003-07-28 09:56:35 +00005880 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005881#ifdef CONFIG_ASH_MATH_SUPPORT_64
5882 len = fmtstr(expdest, 32, "%lld", (long long) num);
5883#else
Eric Andersenc470f442003-07-28 09:56:35 +00005884 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005885#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005886 STADJUST(len, expdest);
5887 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005888}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005889
Eric Andersenc470f442003-07-28 09:56:35 +00005890static void
5891varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005892{
Eric Andersenc470f442003-07-28 09:56:35 +00005893 const char *msg;
5894 const char *tail;
5895
5896 tail = nullstr;
5897 msg = "parameter not set";
5898 if (umsg) {
5899 if (*end == CTLENDVAR) {
5900 if (varflags & VSNUL)
5901 tail = " or null";
5902 } else
5903 msg = umsg;
5904 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005905 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005906}
Eric Andersen90898442003-08-06 11:20:52 +00005907
5908
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005909/* input.c */
Eric Andersencb57d552001-06-28 07:25:16 +00005910
Eric Andersencb57d552001-06-28 07:25:16 +00005911/*
Eric Andersen90898442003-08-06 11:20:52 +00005912 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005913 */
5914
Eric Andersenc470f442003-07-28 09:56:35 +00005915#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005916
Eric Andersenc470f442003-07-28 09:56:35 +00005917static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005918
Eric Andersencb57d552001-06-28 07:25:16 +00005919/*
Eric Andersenc470f442003-07-28 09:56:35 +00005920 * Read a character from the script, returning PEOF on end of file.
5921 * Nul characters in the input are silently discarded.
5922 */
5923
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005924
5925#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
Eric Andersenc470f442003-07-28 09:56:35 +00005926
5927#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5928#define pgetc_macro() pgetc()
5929static int
5930pgetc(void)
5931{
5932 return pgetc_as_macro();
5933}
5934#else
5935#define pgetc_macro() pgetc_as_macro()
5936static int
5937pgetc(void)
5938{
5939 return pgetc_macro();
5940}
5941#endif
5942
5943
5944/*
5945 * Same as pgetc(), but ignores PEOA.
5946 */
5947#ifdef CONFIG_ASH_ALIAS
5948static int pgetc2(void)
5949{
5950 int c;
5951
5952 do {
5953 c = pgetc_macro();
5954 } while (c == PEOA);
5955 return c;
5956}
5957#else
Rob Landley88621d72006-08-29 19:41:06 +00005958static int pgetc2(void)
Eric Andersenc470f442003-07-28 09:56:35 +00005959{
5960 return pgetc_macro();
5961}
5962#endif
5963
Glenn L McGrath28939ad2004-07-21 10:20:19 +00005964/*
5965 * Read a line from the script.
5966 */
5967
Rob Landley88621d72006-08-29 19:41:06 +00005968static char * pfgets(char *line, int len)
Glenn L McGrath28939ad2004-07-21 10:20:19 +00005969{
5970 char *p = line;
5971 int nleft = len;
5972 int c;
5973
5974 while (--nleft > 0) {
5975 c = pgetc2();
5976 if (c == PEOF) {
5977 if (p == line)
5978 return NULL;
5979 break;
5980 }
5981 *p++ = c;
5982 if (c == '\n')
5983 break;
5984 }
5985 *p = '\0';
5986 return line;
5987}
5988
5989
Eric Andersenc470f442003-07-28 09:56:35 +00005990
5991#ifdef CONFIG_FEATURE_COMMAND_EDITING
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00005992#ifdef CONFIG_ASH_EXPAND_PRMT
5993static char *cmdedit_prompt;
5994#else
Eric Andersenc470f442003-07-28 09:56:35 +00005995static const char *cmdedit_prompt;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00005996#endif
Rob Landley88621d72006-08-29 19:41:06 +00005997static void putprompt(const char *s)
Eric Andersenc470f442003-07-28 09:56:35 +00005998{
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00005999#ifdef CONFIG_ASH_EXPAND_PRMT
6000 free(cmdedit_prompt);
Rob Landleyd921b2e2006-08-03 15:41:12 +00006001 cmdedit_prompt = xstrdup(s);
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006002#else
Eric Andersenc470f442003-07-28 09:56:35 +00006003 cmdedit_prompt = s;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006004#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006005}
6006#else
Rob Landley88621d72006-08-29 19:41:06 +00006007static void putprompt(const char *s)
Eric Andersenc470f442003-07-28 09:56:35 +00006008{
6009 out2str(s);
6010}
6011#endif
6012
Rob Landley88621d72006-08-29 19:41:06 +00006013static int preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006014{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006015 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006016 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006017 parsenextc = buf;
6018
Eric Andersenc470f442003-07-28 09:56:35 +00006019retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006020#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006021 if (!iflag || parsefile->fd)
6022 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6023 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006024#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006025 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006026#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006027 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6028 if(nr == 0) {
6029 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006030 if(trap[SIGINT]) {
6031 buf[0] = '\n';
6032 buf[1] = 0;
6033 raise(SIGINT);
6034 return 1;
6035 }
Eric Andersenc470f442003-07-28 09:56:35 +00006036 goto retry;
6037 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006038 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006039 /* Ctrl+D presend */
6040 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006041 }
Eric Andersencb57d552001-06-28 07:25:16 +00006042 }
6043#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006044 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006045#endif
6046
6047 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006048 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6049 int flags = fcntl(0, F_GETFL, 0);
6050 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006051 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006052 if (fcntl(0, F_SETFL, flags) >= 0) {
6053 out2str("sh: turning off NDELAY mode\n");
6054 goto retry;
6055 }
6056 }
6057 }
6058 }
6059 return nr;
6060}
6061
6062/*
6063 * Refill the input buffer and return the next input character:
6064 *
6065 * 1) If a string was pushed back on the input, pop it;
6066 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6067 * from a string so we can't refill the buffer, return EOF.
6068 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6069 * 4) Process input up to the next newline, deleting nul characters.
6070 */
6071
Eric Andersenc470f442003-07-28 09:56:35 +00006072int
6073preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006074{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006075 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00006076 int more;
6077 char savec;
6078
6079 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006080#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006081 if (parsenleft == -1 && parsefile->strpush->ap &&
6082 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006083 return PEOA;
6084 }
Eric Andersen2870d962001-07-02 17:27:21 +00006085#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006086 popstring();
6087 if (--parsenleft >= 0)
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006088 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006089 }
6090 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6091 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006092 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006093
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006094 more = parselleft;
6095 if (more <= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006096again:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006097 if ((more = preadfd()) <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006098 parselleft = parsenleft = EOF_NLEFT;
6099 return PEOF;
6100 }
6101 }
6102
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006103 q = parsenextc;
Eric Andersencb57d552001-06-28 07:25:16 +00006104
6105 /* delete nul characters */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006106 for (;;) {
6107 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00006108
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006109 more--;
6110 c = *q;
Eric Andersenc470f442003-07-28 09:56:35 +00006111
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006112 if (!c)
6113 memmove(q, q + 1, more);
6114 else {
6115 q++;
6116 if (c == '\n') {
6117 parsenleft = q - parsenextc - 1;
6118 break;
6119 }
Eric Andersencb57d552001-06-28 07:25:16 +00006120 }
6121
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006122 if (more <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006123 parsenleft = q - parsenextc - 1;
6124 if (parsenleft < 0)
6125 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006126 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006127 }
6128 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006129 parselleft = more;
Eric Andersencb57d552001-06-28 07:25:16 +00006130
6131 savec = *q;
6132 *q = '\0';
6133
6134 if (vflag) {
6135 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006136 }
6137
6138 *q = savec;
6139
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006140 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006141}
6142
Eric Andersenc470f442003-07-28 09:56:35 +00006143/*
6144 * Undo the last call to pgetc. Only one character may be pushed back.
6145 * PEOF may be pushed back.
6146 */
6147
6148void
6149pungetc(void)
6150{
6151 parsenleft++;
6152 parsenextc--;
6153}
Eric Andersencb57d552001-06-28 07:25:16 +00006154
6155/*
6156 * Push a string back onto the input at this current parsefile level.
6157 * We handle aliases this way.
6158 */
Eric Andersenc470f442003-07-28 09:56:35 +00006159void
6160pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006161{
Eric Andersencb57d552001-06-28 07:25:16 +00006162 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006163 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006164
Eric Andersenc470f442003-07-28 09:56:35 +00006165 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006166 INTOFF;
6167/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6168 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006169 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006170 sp->prev = parsefile->strpush;
6171 parsefile->strpush = sp;
6172 } else
6173 sp = parsefile->strpush = &(parsefile->basestrpush);
6174 sp->prevstring = parsenextc;
6175 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006176#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006177 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006178 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006179 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006180 sp->string = s;
6181 }
Eric Andersen2870d962001-07-02 17:27:21 +00006182#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006183 parsenextc = s;
6184 parsenleft = len;
6185 INTON;
6186}
6187
Eric Andersenc470f442003-07-28 09:56:35 +00006188void
6189popstring(void)
6190{
6191 struct strpush *sp = parsefile->strpush;
6192
6193 INTOFF;
6194#ifdef CONFIG_ASH_ALIAS
6195 if (sp->ap) {
6196 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6197 checkkwd |= CHKALIAS;
6198 }
6199 if (sp->string != sp->ap->val) {
6200 ckfree(sp->string);
6201 }
6202 sp->ap->flag &= ~ALIASINUSE;
6203 if (sp->ap->flag & ALIASDEAD) {
6204 unalias(sp->ap->name);
6205 }
6206 }
6207#endif
6208 parsenextc = sp->prevstring;
6209 parsenleft = sp->prevnleft;
6210/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6211 parsefile->strpush = sp->prev;
6212 if (sp != &(parsefile->basestrpush))
6213 ckfree(sp);
6214 INTON;
6215}
6216
6217/*
6218 * Set the input to take input from a file. If push is set, push the
6219 * old input onto the stack first.
6220 */
6221
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006222static int
6223setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00006224{
6225 int fd;
6226 int fd2;
6227
6228 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006229 if ((fd = open(fname, O_RDONLY)) < 0) {
6230 if (flags & INPUT_NOFILE_OK)
6231 goto out;
6232 sh_error("Can't open %s", fname);
6233 }
Eric Andersenc470f442003-07-28 09:56:35 +00006234 if (fd < 10) {
6235 fd2 = copyfd(fd, 10);
6236 close(fd);
6237 if (fd2 < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006238 sh_error("Out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +00006239 fd = fd2;
6240 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006241 setinputfd(fd, flags & INPUT_PUSH_FILE);
6242out:
Eric Andersenc470f442003-07-28 09:56:35 +00006243 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006244 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +00006245}
6246
6247
6248/*
6249 * Like setinputfile, but takes an open file descriptor. Call this with
6250 * interrupts off.
6251 */
6252
6253static void
6254setinputfd(int fd, int push)
6255{
6256 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6257 if (push) {
6258 pushfile();
6259 parsefile->buf = 0;
6260 }
6261 parsefile->fd = fd;
6262 if (parsefile->buf == NULL)
6263 parsefile->buf = ckmalloc(IBUFSIZ);
6264 parselleft = parsenleft = 0;
6265 plinno = 1;
6266}
6267
Eric Andersencb57d552001-06-28 07:25:16 +00006268
Eric Andersencb57d552001-06-28 07:25:16 +00006269/*
6270 * Like setinputfile, but takes input from a string.
6271 */
6272
Eric Andersenc470f442003-07-28 09:56:35 +00006273static void
6274setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006275{
Eric Andersencb57d552001-06-28 07:25:16 +00006276 INTOFF;
6277 pushfile();
6278 parsenextc = string;
6279 parsenleft = strlen(string);
6280 parsefile->buf = NULL;
6281 plinno = 1;
6282 INTON;
6283}
6284
6285
Eric Andersencb57d552001-06-28 07:25:16 +00006286/*
6287 * To handle the "." command, a stack of input files is used. Pushfile
6288 * adds a new entry to the stack and popfile restores the previous level.
6289 */
6290
Eric Andersenc470f442003-07-28 09:56:35 +00006291static void
6292pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006293{
Eric Andersencb57d552001-06-28 07:25:16 +00006294 struct parsefile *pf;
6295
6296 parsefile->nleft = parsenleft;
6297 parsefile->lleft = parselleft;
6298 parsefile->nextc = parsenextc;
6299 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006300 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006301 pf->prev = parsefile;
6302 pf->fd = -1;
6303 pf->strpush = NULL;
6304 pf->basestrpush.prev = NULL;
6305 parsefile = pf;
6306}
6307
Eric Andersenc470f442003-07-28 09:56:35 +00006308
6309static void
6310popfile(void)
6311{
6312 struct parsefile *pf = parsefile;
6313
6314 INTOFF;
6315 if (pf->fd >= 0)
6316 close(pf->fd);
6317 if (pf->buf)
6318 ckfree(pf->buf);
6319 while (pf->strpush)
6320 popstring();
6321 parsefile = pf->prev;
6322 ckfree(pf);
6323 parsenleft = parsefile->nleft;
6324 parselleft = parsefile->lleft;
6325 parsenextc = parsefile->nextc;
6326 plinno = parsefile->linno;
6327 INTON;
6328}
Eric Andersencb57d552001-06-28 07:25:16 +00006329
6330
Eric Andersen2870d962001-07-02 17:27:21 +00006331/*
Eric Andersenc470f442003-07-28 09:56:35 +00006332 * Return to top level.
6333 */
Eric Andersen2870d962001-07-02 17:27:21 +00006334
Eric Andersenc470f442003-07-28 09:56:35 +00006335static void
6336popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006337{
Eric Andersenc470f442003-07-28 09:56:35 +00006338 while (parsefile != &basepf)
6339 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006340}
6341
Eric Andersen2870d962001-07-02 17:27:21 +00006342
Eric Andersenc470f442003-07-28 09:56:35 +00006343/*
6344 * Close the file(s) that the shell is reading commands from. Called
6345 * after a fork is done.
6346 */
6347
6348static void
6349closescript(void)
6350{
6351 popallfiles();
6352 if (parsefile->fd > 0) {
6353 close(parsefile->fd);
6354 parsefile->fd = 0;
6355 }
6356}
Eric Andersenc470f442003-07-28 09:56:35 +00006357
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006358/* jobs.c */
Eric Andersenc470f442003-07-28 09:56:35 +00006359
6360/* mode flags for set_curjob */
6361#define CUR_DELETE 2
6362#define CUR_RUNNING 1
6363#define CUR_STOPPED 0
6364
6365/* mode flags for dowait */
6366#define DOWAIT_NORMAL 0
6367#define DOWAIT_BLOCK 1
6368
6369/* array of jobs */
6370static struct job *jobtab;
6371/* size of array */
6372static unsigned njobs;
6373#if JOBS
6374/* pgrp of shell on invocation */
6375static int initialpgrp;
6376static int ttyfd = -1;
6377#endif
6378/* current job */
6379static struct job *curjob;
6380/* number of presumed living untracked jobs */
6381static int jobless;
6382
6383static void set_curjob(struct job *, unsigned);
6384#if JOBS
6385static int restartjob(struct job *, int);
6386static void xtcsetpgrp(int, pid_t);
6387static char *commandtext(union node *);
6388static void cmdlist(union node *, int);
6389static void cmdtxt(union node *);
6390static void cmdputs(const char *);
6391static void showpipe(struct job *, FILE *);
6392#endif
6393static int sprint_status(char *, int, int);
6394static void freejob(struct job *);
6395static struct job *getjob(const char *, int);
6396static struct job *growjobtab(void);
6397static void forkchild(struct job *, union node *, int);
6398static void forkparent(struct job *, union node *, int, pid_t);
6399static int dowait(int, struct job *);
6400static int getstatus(struct job *);
6401
6402static void
6403set_curjob(struct job *jp, unsigned mode)
6404{
6405 struct job *jp1;
6406 struct job **jpp, **curp;
6407
6408 /* first remove from list */
6409 jpp = curp = &curjob;
6410 do {
6411 jp1 = *jpp;
6412 if (jp1 == jp)
6413 break;
6414 jpp = &jp1->prev_job;
6415 } while (1);
6416 *jpp = jp1->prev_job;
6417
6418 /* Then re-insert in correct position */
6419 jpp = curp;
6420 switch (mode) {
6421 default:
6422#ifdef DEBUG
6423 abort();
6424#endif
6425 case CUR_DELETE:
6426 /* job being deleted */
6427 break;
6428 case CUR_RUNNING:
6429 /* newly created job or backgrounded job,
6430 put after all stopped jobs. */
6431 do {
6432 jp1 = *jpp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006433#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006434 if (!jp1 || jp1->state != JOBSTOPPED)
6435#endif
6436 break;
6437 jpp = &jp1->prev_job;
6438 } while (1);
6439 /* FALLTHROUGH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006440#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006441 case CUR_STOPPED:
6442#endif
6443 /* newly stopped job - becomes curjob */
6444 jp->prev_job = *jpp;
6445 *jpp = jp;
6446 break;
6447 }
6448}
6449
6450#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006451/*
6452 * Turn job control on and off.
6453 *
6454 * Note: This code assumes that the third arg to ioctl is a character
6455 * pointer, which is true on Berkeley systems but not System V. Since
6456 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006457 *
6458 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006459 */
6460
Eric Andersenc470f442003-07-28 09:56:35 +00006461void
6462setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006463{
Eric Andersenc470f442003-07-28 09:56:35 +00006464 int fd;
6465 int pgrp;
6466
6467 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006468 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006469 if (on) {
6470 int ofd;
6471 ofd = fd = open(_PATH_TTY, O_RDWR);
6472 if (fd < 0) {
6473 fd += 3;
6474 while (!isatty(fd) && --fd >= 0)
6475 ;
6476 }
6477 fd = fcntl(fd, F_DUPFD, 10);
6478 close(ofd);
6479 if (fd < 0)
6480 goto out;
6481 fcntl(fd, F_SETFD, FD_CLOEXEC);
6482 do { /* while we are in the background */
6483 if ((pgrp = tcgetpgrp(fd)) < 0) {
6484out:
6485 sh_warnx("can't access tty; job control turned off");
6486 mflag = on = 0;
6487 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006488 }
Eric Andersenc470f442003-07-28 09:56:35 +00006489 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006490 break;
6491 killpg(0, SIGTTIN);
6492 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006493 initialpgrp = pgrp;
6494
Eric Andersencb57d552001-06-28 07:25:16 +00006495 setsignal(SIGTSTP);
6496 setsignal(SIGTTOU);
6497 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006498 pgrp = rootpid;
6499 setpgid(0, pgrp);
6500 xtcsetpgrp(fd, pgrp);
6501 } else {
6502 /* turning job control off */
6503 fd = ttyfd;
6504 pgrp = initialpgrp;
6505 xtcsetpgrp(fd, pgrp);
6506 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006507 setsignal(SIGTSTP);
6508 setsignal(SIGTTOU);
6509 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006510close:
6511 close(fd);
6512 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006513 }
Eric Andersenc470f442003-07-28 09:56:35 +00006514 ttyfd = fd;
6515 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006516}
Eric Andersencb57d552001-06-28 07:25:16 +00006517
Eric Andersenc470f442003-07-28 09:56:35 +00006518static int
Eric Andersen90898442003-08-06 11:20:52 +00006519killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006520{
6521 int signo = -1;
6522 int list = 0;
6523 int i;
6524 pid_t pid;
6525 struct job *jp;
6526
6527 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006528usage:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006529 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006530"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6531"kill -l [exitstatus]"
6532 );
Eric Andersencb57d552001-06-28 07:25:16 +00006533 }
6534
Eric Andersenc470f442003-07-28 09:56:35 +00006535 if (**++argv == '-') {
Rob Landleyc9c1a412006-07-12 19:17:55 +00006536 signo = get_signum(*argv + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006537 if (signo < 0) {
6538 int c;
6539
6540 while ((c = nextopt("ls:")) != '\0')
6541 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006542 default:
6543#ifdef DEBUG
6544 abort();
6545#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006546 case 'l':
6547 list = 1;
6548 break;
6549 case 's':
Rob Landleyc9c1a412006-07-12 19:17:55 +00006550 signo = get_signum(optionarg);
Eric Andersencb57d552001-06-28 07:25:16 +00006551 if (signo < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006552 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006553 "invalid signal number or name: %s",
6554 optionarg
6555 );
Eric Andersencb57d552001-06-28 07:25:16 +00006556 }
Eric Andersen2870d962001-07-02 17:27:21 +00006557 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006558 }
Eric Andersenc470f442003-07-28 09:56:35 +00006559 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006560 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006561 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006562 }
6563
6564 if (!list && signo < 0)
6565 signo = SIGTERM;
6566
Eric Andersenc470f442003-07-28 09:56:35 +00006567 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006568 goto usage;
6569 }
6570
6571 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006572 const char *name;
6573
Eric Andersenc470f442003-07-28 09:56:35 +00006574 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006575 for (i = 1; i < NSIG; i++) {
Rob Landleyc9c1a412006-07-12 19:17:55 +00006576 name = get_signame(i);
6577 if (isdigit(*name))
Eric Andersenc470f442003-07-28 09:56:35 +00006578 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006579 }
6580 return 0;
6581 }
Rob Landleyc9c1a412006-07-12 19:17:55 +00006582 name = get_signame(signo);
6583 if (isdigit(*name))
Eric Andersenc470f442003-07-28 09:56:35 +00006584 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006585 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006586 sh_error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006587 return 0;
6588 }
6589
Eric Andersenc470f442003-07-28 09:56:35 +00006590 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006591 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006592 if (**argv == '%') {
6593 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006594 pid = -jp->ps[0].pid;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006595 } else {
6596 pid = **argv == '-' ?
6597 -number(*argv + 1) : number(*argv);
6598 }
Eric Andersenc470f442003-07-28 09:56:35 +00006599 if (kill(pid, signo) != 0) {
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006600 sh_warnx("(%d) - %m", pid);
Eric Andersenc470f442003-07-28 09:56:35 +00006601 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006602 }
Eric Andersenc470f442003-07-28 09:56:35 +00006603 } while (*++argv);
6604
6605 return i;
6606}
6607#endif /* JOBS */
6608
6609#if defined(JOBS) || defined(DEBUG)
6610static int
6611jobno(const struct job *jp)
6612{
6613 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006614}
6615#endif
6616
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006617#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006618static int
6619fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006620{
Eric Andersenc470f442003-07-28 09:56:35 +00006621 struct job *jp;
6622 FILE *out;
6623 int mode;
6624 int retval;
6625
6626 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6627 nextopt(nullstr);
6628 argv = argptr;
6629 out = stdout;
6630 do {
6631 jp = getjob(*argv, 1);
6632 if (mode == FORK_BG) {
6633 set_curjob(jp, CUR_RUNNING);
6634 fprintf(out, "[%d] ", jobno(jp));
6635 }
6636 outstr(jp->ps->cmd, out);
6637 showpipe(jp, out);
6638 retval = restartjob(jp, mode);
6639 } while (*argv && *++argv);
6640 return retval;
6641}
6642
6643static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6644
6645
6646static int
6647restartjob(struct job *jp, int mode)
6648{
6649 struct procstat *ps;
6650 int i;
6651 int status;
6652 pid_t pgid;
6653
6654 INTOFF;
6655 if (jp->state == JOBDONE)
6656 goto out;
6657 jp->state = JOBRUNNING;
6658 pgid = jp->ps->pid;
6659 if (mode == FORK_FG)
6660 xtcsetpgrp(ttyfd, pgid);
6661 killpg(pgid, SIGCONT);
6662 ps = jp->ps;
6663 i = jp->nprocs;
6664 do {
6665 if (WIFSTOPPED(ps->status)) {
6666 ps->status = -1;
6667 }
6668 } while (ps++, --i);
6669out:
6670 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6671 INTON;
6672 return status;
6673}
6674#endif
6675
6676static int
6677sprint_status(char *s, int status, int sigonly)
6678{
6679 int col;
6680 int st;
6681
6682 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006683 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006684#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006685 if (WIFSTOPPED(status))
6686 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006687 else
Eric Andersenc470f442003-07-28 09:56:35 +00006688#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006689 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006690 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006691 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006692 goto out;
6693#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006694 if (WIFSTOPPED(status))
6695 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006696#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006697 }
6698 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006699 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006700 if (WCOREDUMP(status)) {
6701 col += fmtstr(s + col, 16, " (core dumped)");
6702 }
6703 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006704 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006705 if (st)
6706 col = fmtstr(s, 16, "Done(%d)", st);
6707 else
6708 col = fmtstr(s, 16, "Done");
6709 }
6710
6711out:
6712 return col;
6713}
6714
6715#if JOBS
6716static void
6717showjob(FILE *out, struct job *jp, int mode)
6718{
6719 struct procstat *ps;
6720 struct procstat *psend;
6721 int col;
6722 int indent;
6723 char s[80];
6724
6725 ps = jp->ps;
6726
6727 if (mode & SHOW_PGID) {
6728 /* just output process (group) id of pipeline */
6729 fprintf(out, "%d\n", ps->pid);
6730 return;
6731 }
6732
6733 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6734 indent = col;
6735
6736 if (jp == curjob)
6737 s[col - 2] = '+';
6738 else if (curjob && jp == curjob->prev_job)
6739 s[col - 2] = '-';
6740
6741 if (mode & SHOW_PID)
6742 col += fmtstr(s + col, 16, "%d ", ps->pid);
6743
6744 psend = ps + jp->nprocs;
6745
6746 if (jp->state == JOBRUNNING) {
6747 scopy("Running", s + col);
6748 col += strlen("Running");
6749 } else {
6750 int status = psend[-1].status;
6751#if JOBS
6752 if (jp->state == JOBSTOPPED)
6753 status = jp->stopstatus;
6754#endif
6755 col += sprint_status(s + col, status, 0);
6756 }
6757
6758 goto start;
6759
6760 do {
6761 /* for each process */
6762 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6763
6764start:
Eric Andersen90898442003-08-06 11:20:52 +00006765 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006766 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6767 );
6768 if (!(mode & SHOW_PID)) {
6769 showpipe(jp, out);
6770 break;
6771 }
6772 if (++ps == psend) {
6773 outcslow('\n', out);
6774 break;
6775 }
6776 } while (1);
6777
6778 jp->changed = 0;
6779
6780 if (jp->state == JOBDONE) {
6781 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6782 freejob(jp);
6783 }
6784}
6785
6786
6787static int
6788jobscmd(int argc, char **argv)
6789{
6790 int mode, m;
6791 FILE *out;
6792
6793 mode = 0;
6794 while ((m = nextopt("lp")))
6795 if (m == 'l')
6796 mode = SHOW_PID;
6797 else
6798 mode = SHOW_PGID;
6799
6800 out = stdout;
6801 argv = argptr;
6802 if (*argv)
6803 do
6804 showjob(out, getjob(*argv,0), mode);
6805 while (*++argv);
6806 else
6807 showjobs(out, mode);
6808
Eric Andersencb57d552001-06-28 07:25:16 +00006809 return 0;
6810}
6811
6812
6813/*
6814 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6815 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006816 */
6817
Eric Andersenc470f442003-07-28 09:56:35 +00006818static void
6819showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006820{
Eric Andersencb57d552001-06-28 07:25:16 +00006821 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006822
Eric Andersenc470f442003-07-28 09:56:35 +00006823 TRACE(("showjobs(%x) called\n", mode));
6824
6825 /* If not even one one job changed, there is nothing to do */
6826 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6827 continue;
6828
6829 for (jp = curjob; jp; jp = jp->prev_job) {
6830 if (!(mode & SHOW_CHANGED) || jp->changed)
6831 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006832 }
6833}
Eric Andersenc470f442003-07-28 09:56:35 +00006834#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006835
6836/*
6837 * Mark a job structure as unused.
6838 */
6839
Eric Andersenc470f442003-07-28 09:56:35 +00006840static void
6841freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006842{
Eric Andersenc470f442003-07-28 09:56:35 +00006843 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006844 int i;
6845
6846 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006847 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006848 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006849 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006850 }
6851 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006852 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006853 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006854 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006855 INTON;
6856}
6857
6858
Eric Andersenc470f442003-07-28 09:56:35 +00006859static int
6860waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006861{
6862 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006863 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006864 struct job *jp;
6865
Eric Andersenc470f442003-07-28 09:56:35 +00006866 EXSIGON();
6867
6868 nextopt(nullstr);
6869 retval = 0;
6870
6871 argv = argptr;
6872 if (!*argv) {
6873 /* wait for all jobs */
6874 for (;;) {
6875 jp = curjob;
6876 while (1) {
6877 if (!jp) {
6878 /* no running procs */
6879 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006880 }
Eric Andersenc470f442003-07-28 09:56:35 +00006881 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006882 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006883 jp->waited = 1;
6884 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006885 }
Eric Andersenc470f442003-07-28 09:56:35 +00006886 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006887 }
6888 }
Eric Andersenc470f442003-07-28 09:56:35 +00006889
6890 retval = 127;
6891 do {
6892 if (**argv != '%') {
6893 pid_t pid = number(*argv);
6894 job = curjob;
6895 goto start;
6896 do {
6897 if (job->ps[job->nprocs - 1].pid == pid)
6898 break;
6899 job = job->prev_job;
6900start:
6901 if (!job)
6902 goto repeat;
6903 } while (1);
6904 } else
6905 job = getjob(*argv, 0);
6906 /* loop until process terminated or stopped */
6907 while (job->state == JOBRUNNING)
6908 dowait(DOWAIT_BLOCK, 0);
6909 job->waited = 1;
6910 retval = getstatus(job);
6911repeat:
6912 ;
6913 } while (*++argv);
6914
6915out:
6916 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006917}
6918
6919
Eric Andersencb57d552001-06-28 07:25:16 +00006920/*
6921 * Convert a job name to a job structure.
6922 */
6923
Eric Andersenc470f442003-07-28 09:56:35 +00006924static struct job *
6925getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006926{
Eric Andersencb57d552001-06-28 07:25:16 +00006927 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006928 struct job *found;
6929 const char *err_msg = "No such job: %s";
6930 unsigned num;
6931 int c;
6932 const char *p;
6933 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006934
Eric Andersenc470f442003-07-28 09:56:35 +00006935 jp = curjob;
6936 p = name;
6937 if (!p)
6938 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006939
Eric Andersenc470f442003-07-28 09:56:35 +00006940 if (*p != '%')
6941 goto err;
6942
6943 c = *++p;
6944 if (!c)
6945 goto currentjob;
6946
6947 if (!p[1]) {
6948 if (c == '+' || c == '%') {
6949currentjob:
6950 err_msg = "No current job";
6951 goto check;
6952 } else if (c == '-') {
6953 if (jp)
6954 jp = jp->prev_job;
6955 err_msg = "No previous job";
6956check:
6957 if (!jp)
6958 goto err;
6959 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006960 }
6961 }
Eric Andersenc470f442003-07-28 09:56:35 +00006962
6963 if (is_number(p)) {
6964 num = atoi(p);
6965 if (num < njobs) {
6966 jp = jobtab + num - 1;
6967 if (jp->used)
6968 goto gotit;
6969 goto err;
6970 }
6971 }
6972
6973 match = prefix;
6974 if (*p == '?') {
6975 match = strstr;
6976 p++;
6977 }
6978
6979 found = 0;
6980 while (1) {
6981 if (!jp)
6982 goto err;
6983 if (match(jp->ps[0].cmd, p)) {
6984 if (found)
6985 goto err;
6986 found = jp;
6987 err_msg = "%s: ambiguous";
6988 }
6989 jp = jp->prev_job;
6990 }
6991
6992gotit:
6993#if JOBS
6994 err_msg = "job %s not created under job control";
6995 if (getctl && jp->jobctl == 0)
6996 goto err;
6997#endif
6998 return jp;
6999err:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007000 sh_error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007001}
7002
7003
Eric Andersencb57d552001-06-28 07:25:16 +00007004/*
Eric Andersenc470f442003-07-28 09:56:35 +00007005 * Return a new job structure.
7006 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007007 */
7008
Eric Andersenc470f442003-07-28 09:56:35 +00007009static struct job *
7010makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007011{
7012 int i;
7013 struct job *jp;
7014
Eric Andersenc470f442003-07-28 09:56:35 +00007015 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007016 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007017 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007018 break;
7019 }
7020 if (jp->used == 0)
7021 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007022 if (jp->state != JOBDONE || !jp->waited)
7023 continue;
7024#if JOBS
7025 if (jobctl)
7026 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007027#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007028 freejob(jp);
7029 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007030 }
Eric Andersenc470f442003-07-28 09:56:35 +00007031 memset(jp, 0, sizeof(*jp));
7032#if JOBS
7033 if (jobctl)
7034 jp->jobctl = 1;
7035#endif
7036 jp->prev_job = curjob;
7037 curjob = jp;
7038 jp->used = 1;
7039 jp->ps = &jp->ps0;
7040 if (nprocs > 1) {
7041 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7042 }
7043 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7044 jobno(jp)));
7045 return jp;
7046}
7047
7048static struct job *
7049growjobtab(void)
7050{
7051 size_t len;
7052 ptrdiff_t offset;
7053 struct job *jp, *jq;
7054
7055 len = njobs * sizeof(*jp);
7056 jq = jobtab;
7057 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7058
7059 offset = (char *)jp - (char *)jq;
7060 if (offset) {
7061 /* Relocate pointers */
7062 size_t l = len;
7063
7064 jq = (struct job *)((char *)jq + l);
7065 while (l) {
7066 l -= sizeof(*jp);
7067 jq--;
7068#define joff(p) ((struct job *)((char *)(p) + l))
7069#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007070 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007071 jmove(joff(jp)->ps);
7072 if (joff(jp)->prev_job)
7073 jmove(joff(jp)->prev_job);
7074 }
7075 if (curjob)
7076 jmove(curjob);
7077#undef joff
7078#undef jmove
7079 }
7080
7081 njobs += 4;
7082 jobtab = jp;
7083 jp = (struct job *)((char *)jp + len);
7084 jq = jp + 3;
7085 do {
7086 jq->used = 0;
7087 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007088 return jp;
7089}
7090
7091
7092/*
Eric Andersenc470f442003-07-28 09:56:35 +00007093 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007094 * own process group. Jp is a job structure that the job is to be added to.
7095 * N is the command that will be evaluated by the child. Both jp and n may
7096 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007097 * FORK_FG - Fork off a foreground process.
7098 * FORK_BG - Fork off a background process.
7099 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7100 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007101 *
7102 * When job control is turned off, background processes have their standard
7103 * input redirected to /dev/null (except for the second and later processes
7104 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007105 *
7106 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007107 */
7108
Rob Landley88621d72006-08-29 19:41:06 +00007109static void forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007110{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007111 int oldlvl;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007112
Eric Andersenc470f442003-07-28 09:56:35 +00007113 TRACE(("Child shell %d\n", getpid()));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007114 oldlvl = shlvl;
7115 shlvl++;
Eric Andersenc470f442003-07-28 09:56:35 +00007116
7117 closescript();
7118 clear_traps();
7119#if JOBS
7120 /* do job control only in root shell */
7121 jobctl = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007122 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007123 pid_t pgrp;
7124
7125 if (jp->nprocs == 0)
7126 pgrp = getpid();
7127 else
7128 pgrp = jp->ps[0].pid;
7129 /* This can fail because we are doing it in the parent also */
7130 (void)setpgid(0, pgrp);
7131 if (mode == FORK_FG)
7132 xtcsetpgrp(ttyfd, pgrp);
7133 setsignal(SIGTSTP);
7134 setsignal(SIGTTOU);
7135 } else
Eric Andersen62483552001-07-10 06:09:16 +00007136#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007137 if (mode == FORK_BG) {
7138 ignoresig(SIGINT);
7139 ignoresig(SIGQUIT);
7140 if (jp->nprocs == 0) {
7141 close(0);
Bernhard Reutner-Fischer0a8812b2006-05-19 13:12:21 +00007142 if (open(bb_dev_null, O_RDONLY) != 0)
7143 sh_error("Can't open %s", bb_dev_null);
Eric Andersencb57d552001-06-28 07:25:16 +00007144 }
Eric Andersencb57d552001-06-28 07:25:16 +00007145 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007146 if (!oldlvl && iflag) {
Eric Andersenc470f442003-07-28 09:56:35 +00007147 setsignal(SIGINT);
7148 setsignal(SIGQUIT);
7149 setsignal(SIGTERM);
7150 }
7151 for (jp = curjob; jp; jp = jp->prev_job)
7152 freejob(jp);
7153 jobless = 0;
7154}
7155
Rob Landley88621d72006-08-29 19:41:06 +00007156static void forkparent(struct job *jp, union node *n, int mode, pid_t pid)
Eric Andersenc470f442003-07-28 09:56:35 +00007157{
7158 TRACE(("In parent shell: child = %d\n", pid));
7159 if (!jp) {
7160 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7161 jobless++;
7162 return;
7163 }
7164#if JOBS
7165 if (mode != FORK_NOJOB && jp->jobctl) {
7166 int pgrp;
7167
7168 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007169 pgrp = pid;
7170 else
7171 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007172 /* This can fail because we are doing it in the child also */
7173 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007174 }
Eric Andersen62483552001-07-10 06:09:16 +00007175#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007176 if (mode == FORK_BG) {
7177 backgndpid = pid; /* set $! */
7178 set_curjob(jp, CUR_RUNNING);
7179 }
Eric Andersencb57d552001-06-28 07:25:16 +00007180 if (jp) {
7181 struct procstat *ps = &jp->ps[jp->nprocs++];
7182 ps->pid = pid;
7183 ps->status = -1;
7184 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007185#if JOBS
7186 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007187 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007188#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007189 }
Eric Andersencb57d552001-06-28 07:25:16 +00007190}
7191
Eric Andersenc470f442003-07-28 09:56:35 +00007192static int
7193forkshell(struct job *jp, union node *n, int mode)
7194{
7195 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007196
Eric Andersenc470f442003-07-28 09:56:35 +00007197 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7198 pid = fork();
7199 if (pid < 0) {
7200 TRACE(("Fork failed, errno=%d", errno));
7201 if (jp)
7202 freejob(jp);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007203 sh_error("Cannot fork");
Eric Andersenc470f442003-07-28 09:56:35 +00007204 }
7205 if (pid == 0)
7206 forkchild(jp, n, mode);
7207 else
7208 forkparent(jp, n, mode, pid);
7209 return pid;
7210}
Eric Andersencb57d552001-06-28 07:25:16 +00007211
7212/*
7213 * Wait for job to finish.
7214 *
7215 * Under job control we have the problem that while a child process is
7216 * running interrupts generated by the user are sent to the child but not
7217 * to the shell. This means that an infinite loop started by an inter-
7218 * active user may be hard to kill. With job control turned off, an
7219 * interactive user may place an interactive program inside a loop. If
7220 * the interactive program catches interrupts, the user doesn't want
7221 * these interrupts to also abort the loop. The approach we take here
7222 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007223 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007224 * signal if the child process was terminated by an interrupt signal.
7225 * Unfortunately, some programs want to do a bit of cleanup and then
7226 * exit on interrupt; unless these processes terminate themselves by
7227 * sending a signal to themselves (instead of calling exit) they will
7228 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007229 *
7230 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007231 */
7232
Eric Andersenc470f442003-07-28 09:56:35 +00007233int
7234waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007235{
Eric Andersencb57d552001-06-28 07:25:16 +00007236 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007237
Eric Andersenc470f442003-07-28 09:56:35 +00007238 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7239 while (jp->state == JOBRUNNING) {
7240 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007241 }
Eric Andersenc470f442003-07-28 09:56:35 +00007242 st = getstatus(jp);
7243#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007244 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007245 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007246 /*
7247 * This is truly gross.
7248 * If we're doing job control, then we did a TIOCSPGRP which
7249 * caused us (the shell) to no longer be in the controlling
7250 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7251 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007252 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007253 */
Eric Andersenc470f442003-07-28 09:56:35 +00007254 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007255 raise(SIGINT);
7256 }
Eric Andersen2870d962001-07-02 17:27:21 +00007257 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007258#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007259 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007260 return st;
7261}
7262
7263
Eric Andersen62483552001-07-10 06:09:16 +00007264/*
7265 * Do a wait system call. If job control is compiled in, we accept
7266 * stopped processes. If block is zero, we return a value of zero
7267 * rather than blocking.
7268 *
7269 * System V doesn't have a non-blocking wait system call. It does
7270 * have a SIGCLD signal that is sent to a process when one of it's
7271 * children dies. The obvious way to use SIGCLD would be to install
7272 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7273 * was received, and have waitproc bump another counter when it got
7274 * the status of a process. Waitproc would then know that a wait
7275 * system call would not block if the two counters were different.
7276 * This approach doesn't work because if a process has children that
7277 * have not been waited for, System V will send it a SIGCLD when it
7278 * installs a signal handler for SIGCLD. What this means is that when
7279 * a child exits, the shell will be sent SIGCLD signals continuously
7280 * until is runs out of stack space, unless it does a wait call before
7281 * restoring the signal handler. The code below takes advantage of
7282 * this (mis)feature by installing a signal handler for SIGCLD and
7283 * then checking to see whether it was called. If there are any
7284 * children to be waited for, it will be.
7285 *
Eric Andersenc470f442003-07-28 09:56:35 +00007286 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7287 * waits at all. In this case, the user will not be informed when
7288 * a background process until the next time she runs a real program
7289 * (as opposed to running a builtin command or just typing return),
7290 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007291 */
7292
Rob Landley88621d72006-08-29 19:41:06 +00007293static int waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007294{
Eric Andersenc470f442003-07-28 09:56:35 +00007295 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007296
Eric Andersenc470f442003-07-28 09:56:35 +00007297#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007298 if (jobctl)
7299 flags |= WUNTRACED;
7300#endif
7301 if (block == 0)
7302 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007303 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007304}
7305
Eric Andersenc470f442003-07-28 09:56:35 +00007306/*
7307 * Wait for a process to terminate.
7308 */
7309
7310static int
7311dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007312{
7313 int pid;
7314 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007315 struct job *jp;
7316 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007317 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007318
7319 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007320 pid = waitproc(block, &status);
7321 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007322 if (pid <= 0)
7323 return pid;
7324 INTOFF;
7325 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007326 for (jp = curjob; jp; jp = jp->prev_job) {
7327 struct procstat *sp;
7328 struct procstat *spend;
7329 if (jp->state == JOBDONE)
7330 continue;
7331 state = JOBDONE;
7332 spend = jp->ps + jp->nprocs;
7333 sp = jp->ps;
7334 do {
7335 if (sp->pid == pid) {
7336 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7337 sp->status = status;
7338 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007339 }
Eric Andersenc470f442003-07-28 09:56:35 +00007340 if (sp->status == -1)
7341 state = JOBRUNNING;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007342#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007343 if (state == JOBRUNNING)
7344 continue;
7345 if (WIFSTOPPED(sp->status)) {
7346 jp->stopstatus = sp->status;
7347 state = JOBSTOPPED;
7348 }
Eric Andersencb57d552001-06-28 07:25:16 +00007349#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007350 } while (++sp < spend);
7351 if (thisjob)
7352 goto gotjob;
7353 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007354#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007355 if (!WIFSTOPPED(status))
7356#endif
7357
7358 jobless--;
7359 goto out;
7360
7361gotjob:
7362 if (state != JOBRUNNING) {
7363 thisjob->changed = 1;
7364
7365 if (thisjob->state != state) {
7366 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7367 thisjob->state = state;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007368#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007369 if (state == JOBSTOPPED) {
7370 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007371 }
Eric Andersenc470f442003-07-28 09:56:35 +00007372#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007373 }
7374 }
Eric Andersencb57d552001-06-28 07:25:16 +00007375
Eric Andersenc470f442003-07-28 09:56:35 +00007376out:
7377 INTON;
7378
7379 if (thisjob && thisjob == job) {
7380 char s[48 + 1];
7381 int len;
7382
7383 len = sprint_status(s, status, 1);
7384 if (len) {
7385 s[len] = '\n';
7386 s[len + 1] = 0;
7387 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007388 }
Eric Andersencb57d552001-06-28 07:25:16 +00007389 }
7390 return pid;
7391}
7392
7393
Eric Andersencb57d552001-06-28 07:25:16 +00007394/*
7395 * return 1 if there are stopped jobs, otherwise 0
7396 */
Eric Andersen90898442003-08-06 11:20:52 +00007397
Eric Andersenc470f442003-07-28 09:56:35 +00007398int
7399stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007400{
Eric Andersencb57d552001-06-28 07:25:16 +00007401 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007402 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007403
Eric Andersenc470f442003-07-28 09:56:35 +00007404 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007405 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007406 goto out;
7407 jp = curjob;
7408 if (jp && jp->state == JOBSTOPPED) {
7409 out2str("You have stopped jobs.\n");
7410 job_warning = 2;
7411 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007412 }
7413
Eric Andersenc470f442003-07-28 09:56:35 +00007414out:
7415 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007416}
7417
7418/*
7419 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007420 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007421 */
7422
Eric Andersenc470f442003-07-28 09:56:35 +00007423#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007424static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007425
Eric Andersenc470f442003-07-28 09:56:35 +00007426static char *
7427commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007428{
Eric Andersenc470f442003-07-28 09:56:35 +00007429 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007430
Eric Andersenc470f442003-07-28 09:56:35 +00007431 STARTSTACKSTR(cmdnextc);
7432 cmdtxt(n);
7433 name = stackblock();
7434 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7435 name, cmdnextc, cmdnextc));
7436 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007437}
7438
Eric Andersenc470f442003-07-28 09:56:35 +00007439static void
7440cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007441{
Eric Andersencb57d552001-06-28 07:25:16 +00007442 union node *np;
7443 struct nodelist *lp;
7444 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007445 char s[2];
7446
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007447 if (!n)
7448 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007449 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007450 default:
7451#if DEBUG
7452 abort();
7453#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007454 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007455 lp = n->npipe.cmdlist;
7456 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007457 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007458 lp = lp->next;
7459 if (!lp)
7460 break;
7461 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007462 }
7463 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007464 case NSEMI:
7465 p = "; ";
7466 goto binop;
7467 case NAND:
7468 p = " && ";
7469 goto binop;
7470 case NOR:
7471 p = " || ";
7472binop:
7473 cmdtxt(n->nbinary.ch1);
7474 cmdputs(p);
7475 n = n->nbinary.ch2;
7476 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007477 case NREDIR:
7478 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007479 n = n->nredir.n;
7480 goto donode;
7481 case NNOT:
7482 cmdputs("!");
7483 n = n->nnot.com;
7484donode:
7485 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007486 break;
7487 case NIF:
7488 cmdputs("if ");
7489 cmdtxt(n->nif.test);
7490 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007491 n = n->nif.ifpart;
7492 if (n->nif.elsepart) {
7493 cmdtxt(n);
7494 cmdputs("; else ");
7495 n = n->nif.elsepart;
7496 }
7497 p = "; fi";
7498 goto dotail;
7499 case NSUBSHELL:
7500 cmdputs("(");
7501 n = n->nredir.n;
7502 p = ")";
7503 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007504 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007505 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007506 goto until;
7507 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007508 p = "until ";
7509until:
7510 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007511 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007512 n = n->nbinary.ch2;
7513 p = "; done";
7514dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007515 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007516dotail:
7517 cmdtxt(n);
7518 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007519 case NFOR:
7520 cmdputs("for ");
7521 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007522 cmdputs(" in ");
7523 cmdlist(n->nfor.args, 1);
7524 n = n->nfor.body;
7525 p = "; done";
7526 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007527 case NDEFUN:
7528 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007529 p = "() { ... }";
7530 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007531 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007532 cmdlist(n->ncmd.args, 1);
7533 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007534 break;
7535 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007536 p = n->narg.text;
7537dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007538 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007539 break;
7540 case NHERE:
7541 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007542 p = "<<...";
7543 goto dotail2;
7544 case NCASE:
7545 cmdputs("case ");
7546 cmdputs(n->ncase.expr->narg.text);
7547 cmdputs(" in ");
7548 for (np = n->ncase.cases; np; np = np->nclist.next) {
7549 cmdtxt(np->nclist.pattern);
7550 cmdputs(") ");
7551 cmdtxt(np->nclist.body);
7552 cmdputs(";; ");
7553 }
7554 p = "esac";
7555 goto dotail2;
7556 case NTO:
7557 p = ">";
7558 goto redir;
7559 case NCLOBBER:
7560 p = ">|";
7561 goto redir;
7562 case NAPPEND:
7563 p = ">>";
7564 goto redir;
7565 case NTOFD:
7566 p = ">&";
7567 goto redir;
7568 case NFROM:
7569 p = "<";
7570 goto redir;
7571 case NFROMFD:
7572 p = "<&";
7573 goto redir;
7574 case NFROMTO:
7575 p = "<>";
7576redir:
7577 s[0] = n->nfile.fd + '0';
7578 s[1] = '\0';
7579 cmdputs(s);
7580 cmdputs(p);
7581 if (n->type == NTOFD || n->type == NFROMFD) {
7582 s[0] = n->ndup.dupfd + '0';
7583 p = s;
7584 goto dotail2;
7585 } else {
7586 n = n->nfile.fname;
7587 goto donode;
7588 }
Eric Andersencb57d552001-06-28 07:25:16 +00007589 }
7590}
Eric Andersencb57d552001-06-28 07:25:16 +00007591
Eric Andersenc470f442003-07-28 09:56:35 +00007592static void
7593cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007594{
Eric Andersenc470f442003-07-28 09:56:35 +00007595 for (; np; np = np->narg.next) {
7596 if (!sep)
7597 cmdputs(spcstr);
7598 cmdtxt(np);
7599 if (sep && np->narg.next)
7600 cmdputs(spcstr);
7601 }
Eric Andersencb57d552001-06-28 07:25:16 +00007602}
7603
Eric Andersenc470f442003-07-28 09:56:35 +00007604static void
7605cmdputs(const char *s)
7606{
7607 const char *p, *str;
7608 char c, cc[2] = " ";
7609 char *nextc;
7610 int subtype = 0;
7611 int quoted = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007612 static const char vstype[VSTYPE + 1][4] = {
7613 "", "}", "-", "+", "?", "=",
7614 "%", "%%", "#", "##"
Eric Andersenc470f442003-07-28 09:56:35 +00007615 };
Eric Andersenc470f442003-07-28 09:56:35 +00007616 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7617 p = s;
7618 while ((c = *p++) != 0) {
7619 str = 0;
7620 switch (c) {
7621 case CTLESC:
7622 c = *p++;
7623 break;
7624 case CTLVAR:
7625 subtype = *p++;
7626 if ((subtype & VSTYPE) == VSLENGTH)
7627 str = "${#";
7628 else
7629 str = "${";
7630 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7631 quoted ^= 1;
7632 c = '"';
7633 } else
7634 goto dostr;
7635 break;
7636 case CTLENDVAR:
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007637 str = "\"}" + !(quoted & 1);
Eric Andersenc470f442003-07-28 09:56:35 +00007638 quoted >>= 1;
7639 subtype = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007640 goto dostr;
Eric Andersenc470f442003-07-28 09:56:35 +00007641 case CTLBACKQ:
7642 str = "$(...)";
7643 goto dostr;
7644 case CTLBACKQ+CTLQUOTE:
7645 str = "\"$(...)\"";
7646 goto dostr;
7647#ifdef CONFIG_ASH_MATH_SUPPORT
7648 case CTLARI:
7649 str = "$((";
7650 goto dostr;
7651 case CTLENDARI:
7652 str = "))";
7653 goto dostr;
7654#endif
7655 case CTLQUOTEMARK:
7656 quoted ^= 1;
7657 c = '"';
7658 break;
7659 case '=':
7660 if (subtype == 0)
7661 break;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007662 if ((subtype & VSTYPE) != VSNORMAL)
7663 quoted <<= 1;
Eric Andersenc470f442003-07-28 09:56:35 +00007664 str = vstype[subtype & VSTYPE];
7665 if (subtype & VSNUL)
7666 c = ':';
7667 else
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007668 goto checkstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007669 break;
7670 case '\'':
7671 case '\\':
7672 case '"':
7673 case '$':
7674 /* These can only happen inside quotes */
7675 cc[0] = c;
7676 str = cc;
7677 c = '\\';
7678 break;
7679 default:
7680 break;
7681 }
7682 USTPUTC(c, nextc);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007683checkstr:
Eric Andersenc470f442003-07-28 09:56:35 +00007684 if (!str)
7685 continue;
7686dostr:
7687 while ((c = *str++)) {
7688 USTPUTC(c, nextc);
7689 }
7690 }
7691 if (quoted & 1) {
7692 USTPUTC('"', nextc);
7693 }
7694 *nextc = 0;
7695 cmdnextc = nextc;
7696}
7697
7698
7699static void
7700showpipe(struct job *jp, FILE *out)
7701{
7702 struct procstat *sp;
7703 struct procstat *spend;
7704
7705 spend = jp->ps + jp->nprocs;
7706 for (sp = jp->ps + 1; sp < spend; sp++)
7707 fprintf(out, " | %s", sp->cmd);
7708 outcslow('\n', out);
7709 flushall();
7710}
7711
7712static void
7713xtcsetpgrp(int fd, pid_t pgrp)
7714{
7715 if (tcsetpgrp(fd, pgrp))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007716 sh_error("Cannot set tty process group (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +00007717}
7718#endif /* JOBS */
7719
7720static int
7721getstatus(struct job *job) {
7722 int status;
7723 int retval;
7724
7725 status = job->ps[job->nprocs - 1].status;
7726 retval = WEXITSTATUS(status);
7727 if (!WIFEXITED(status)) {
7728#if JOBS
7729 retval = WSTOPSIG(status);
7730 if (!WIFSTOPPED(status))
7731#endif
7732 {
7733 /* XXX: limits number of signals */
7734 retval = WTERMSIG(status);
7735#if JOBS
7736 if (retval == SIGINT)
7737 job->sigint = 1;
7738#endif
7739 }
7740 retval += 128;
7741 }
7742 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7743 jobno(job), job->nprocs, status, retval));
7744 return retval;
7745}
7746
Eric Andersend35c5df2002-01-09 15:37:36 +00007747#ifdef CONFIG_ASH_MAIL
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007748/* mail.c */
Eric Andersenec074692001-10-31 11:05:49 +00007749
Eric Andersencb57d552001-06-28 07:25:16 +00007750/*
Eric Andersenc470f442003-07-28 09:56:35 +00007751 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007752 */
7753
Eric Andersencb57d552001-06-28 07:25:16 +00007754#define MAXMBOXES 10
7755
Eric Andersenc470f442003-07-28 09:56:35 +00007756/* times of mailboxes */
7757static time_t mailtime[MAXMBOXES];
7758/* Set if MAIL or MAILPATH is changed. */
7759static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007760
7761
7762
7763/*
Eric Andersenc470f442003-07-28 09:56:35 +00007764 * Print appropriate message(s) if mail has arrived.
7765 * If mail_var_path_changed is set,
7766 * then the value of MAIL has mail_var_path_changed,
7767 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007768 */
7769
Eric Andersenc470f442003-07-28 09:56:35 +00007770static void
7771chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007772{
Eric Andersencb57d552001-06-28 07:25:16 +00007773 const char *mpath;
7774 char *p;
7775 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007776 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007777 struct stackmark smark;
7778 struct stat statb;
7779
Eric Andersencb57d552001-06-28 07:25:16 +00007780 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007781 mpath = mpathset() ? mpathval() : mailval();
7782 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007783 p = padvance(&mpath, nullstr);
7784 if (p == NULL)
7785 break;
7786 if (*p == '\0')
7787 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007788 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007789#ifdef DEBUG
7790 if (q[-1] != '/')
7791 abort();
7792#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007793 q[-1] = '\0'; /* delete trailing '/' */
7794 if (stat(p, &statb) < 0) {
7795 *mtp = 0;
7796 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007797 }
Eric Andersenc470f442003-07-28 09:56:35 +00007798 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7799 fprintf(
7800 stderr, snlfmt,
7801 pathopt ? pathopt : "you have mail"
7802 );
7803 }
7804 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007805 }
Eric Andersenc470f442003-07-28 09:56:35 +00007806 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007807 popstackmark(&smark);
7808}
Eric Andersencb57d552001-06-28 07:25:16 +00007809
Eric Andersenec074692001-10-31 11:05:49 +00007810
Eric Andersenc470f442003-07-28 09:56:35 +00007811static void
7812changemail(const char *val)
7813{
7814 mail_var_path_changed++;
7815}
7816
7817#endif /* CONFIG_ASH_MAIL */
7818
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007819/* main.c */
Eric Andersenc470f442003-07-28 09:56:35 +00007820
Eric Andersencb57d552001-06-28 07:25:16 +00007821
Eric Andersencb57d552001-06-28 07:25:16 +00007822#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007823static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007824extern int etext();
7825#endif
7826
Eric Andersenc470f442003-07-28 09:56:35 +00007827static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007828
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007829static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007830
Eric Andersencb57d552001-06-28 07:25:16 +00007831/*
7832 * Main routine. We initialize things, parse the arguments, execute
7833 * profiles if we're a login shell, and then call cmdloop to execute
7834 * commands. The setjmp call sets up the location to jump to when an
7835 * exception occurs. When an exception occurs the variable "state"
7836 * is used to figure out how far we had gotten.
7837 */
7838
Eric Andersenc470f442003-07-28 09:56:35 +00007839int
7840ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007841{
Eric Andersenc470f442003-07-28 09:56:35 +00007842 char *shinit;
7843 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007844 struct jmploc jmploc;
7845 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007846
Eric Andersenc470f442003-07-28 09:56:35 +00007847#ifdef __GLIBC__
7848 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007849#endif
7850
Eric Andersencb57d552001-06-28 07:25:16 +00007851#if PROFILE
7852 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7853#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007854 state = 0;
7855 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007856 int e;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007857 int s;
Eric Andersenc470f442003-07-28 09:56:35 +00007858
Eric Andersencb57d552001-06-28 07:25:16 +00007859 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007860
7861 e = exception;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007862 if (e == EXERROR)
7863 exitstatus = 2;
7864 s = state;
7865 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00007866 exitshell();
7867
Eric Andersen90898442003-08-06 11:20:52 +00007868 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007869 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007870 }
7871 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007872 FORCEINTON; /* enable interrupts */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007873 if (s == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00007874 goto state1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007875 else if (s == 2)
Eric Andersencb57d552001-06-28 07:25:16 +00007876 goto state2;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007877 else if (s == 3)
Eric Andersencb57d552001-06-28 07:25:16 +00007878 goto state3;
7879 else
7880 goto state4;
7881 }
7882 handler = &jmploc;
7883#ifdef DEBUG
7884 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007885 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007886#endif
7887 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007888
7889#ifdef CONFIG_ASH_RANDOM_SUPPORT
7890 rseed = rootpid + ((time_t)time((time_t *)0));
7891#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007892 init();
7893 setstackmark(&smark);
7894 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007895#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7896 if ( iflag ) {
7897 const char *hp = lookupvar("HISTFILE");
7898
7899 if(hp == NULL ) {
7900 hp = lookupvar("HOME");
7901 if(hp != NULL) {
7902 char *defhp = concat_path_file(hp, ".ash_history");
7903 setvar("HISTFILE", defhp, 0);
7904 free(defhp);
7905 }
7906 }
7907 }
7908#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007909 if (argv[0] && argv[0][0] == '-')
7910 isloginsh = 1;
7911 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007912 state = 1;
7913 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007914state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007915 state = 2;
7916 read_profile(".profile");
7917 }
Eric Andersenc470f442003-07-28 09:56:35 +00007918state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007919 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007920 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007921#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007922 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007923#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007924 iflag
7925 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007926 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007927 read_profile(shinit);
7928 }
Eric Andersencb57d552001-06-28 07:25:16 +00007929 }
Eric Andersenc470f442003-07-28 09:56:35 +00007930state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007931 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007932 if (minusc)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007933 evalstring(minusc, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007934
7935 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007936#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007937 if ( iflag ) {
7938 const char *hp = lookupvar("HISTFILE");
7939
7940 if(hp != NULL )
7941 load_history ( hp );
7942 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007943#endif
Eric Andersen90898442003-08-06 11:20:52 +00007944state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007945 cmdloop(1);
7946 }
7947#if PROFILE
7948 monitor(0);
7949#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007950#if GPROF
7951 {
7952 extern void _mcleanup(void);
7953 _mcleanup();
7954 }
7955#endif
7956 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007957 /* NOTREACHED */
7958}
7959
7960
7961/*
7962 * Read and execute commands. "Top" is nonzero for the top level command
7963 * loop; it turns on prompting if the shell is interactive.
7964 */
7965
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007966static int
Eric Andersenc470f442003-07-28 09:56:35 +00007967cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007968{
7969 union node *n;
7970 struct stackmark smark;
7971 int inter;
7972 int numeof = 0;
7973
7974 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00007975 for (;;) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007976 int skip;
7977
Glenn L McGrath76620622004-01-13 10:19:37 +00007978 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007979#if JOBS
7980 if (jobctl)
7981 showjobs(stderr, SHOW_CHANGED);
7982#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007983 inter = 0;
7984 if (iflag && top) {
7985 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00007986#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007987 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00007988#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007989 }
7990 n = parsecmd(inter);
7991 /* showtree(n); DEBUG */
7992 if (n == NEOF) {
7993 if (!top || numeof >= 50)
7994 break;
7995 if (!stoppedjobs()) {
7996 if (!Iflag)
7997 break;
7998 out2str("\nUse \"exit\" to leave shell.\n");
7999 }
8000 numeof++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008001 } else if (nflag == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008002 job_warning = (job_warning == 2) ? 1 : 0;
8003 numeof = 0;
8004 evaltree(n, 0);
8005 }
8006 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008007 skip = evalskip;
8008
8009 if (skip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008010 evalskip = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008011 return skip & SKIPEVAL;
Eric Andersencb57d552001-06-28 07:25:16 +00008012 }
8013 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008014
8015 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008016}
8017
8018
Eric Andersencb57d552001-06-28 07:25:16 +00008019/*
8020 * Read /etc/profile or .profile. Return on error.
8021 */
8022
Eric Andersenc470f442003-07-28 09:56:35 +00008023static void
8024read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008025{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008026 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008027
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008028 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008029 return;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008030
8031 skip = cmdloop(0);
Eric Andersencb57d552001-06-28 07:25:16 +00008032 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008033
8034 if (skip)
8035 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00008036}
8037
8038
Eric Andersencb57d552001-06-28 07:25:16 +00008039/*
8040 * Read a file containing shell functions.
8041 */
8042
Eric Andersenc470f442003-07-28 09:56:35 +00008043static void
8044readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008045{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008046 setinputfile(name, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008047 cmdloop(0);
8048 popfile();
8049}
8050
8051
Eric Andersencb57d552001-06-28 07:25:16 +00008052/*
Eric Andersenc470f442003-07-28 09:56:35 +00008053 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008054 * search for the file, which is necessary to find sub-commands.
8055 */
8056
Rob Landley88621d72006-08-29 19:41:06 +00008057static char * find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008058{
8059 char *fullname;
8060 const char *path = pathval();
8061 struct stat statb;
8062
8063 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008064 if (strchr(name, '/'))
8065 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008066
Eric Andersenc470f442003-07-28 09:56:35 +00008067 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008068 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8069 /*
8070 * Don't bother freeing here, since it will
8071 * be freed by the caller.
8072 */
8073 return fullname;
8074 }
8075 stunalloc(fullname);
8076 }
8077
8078 /* not found in the PATH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008079 sh_error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008080 /* NOTREACHED */
8081}
8082
Eric Andersen1e6aba92004-04-12 19:12:13 +00008083static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008084{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008085 struct strlist *sp;
8086 volatile struct shparam saveparam;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008087 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008088
Eric Andersen1e6aba92004-04-12 19:12:13 +00008089 for (sp = cmdenviron; sp; sp = sp->next)
Rob Landleyd921b2e2006-08-03 15:41:12 +00008090 setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008091
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00008092 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008093 char *fullname;
Eric Andersencb57d552001-06-28 07:25:16 +00008094
Eric Andersencb57d552001-06-28 07:25:16 +00008095 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008096
8097 if (argc > 2) {
8098 saveparam = shellparam;
8099 shellparam.malloc = 0;
8100 shellparam.nparam = argc - 2;
8101 shellparam.p = argv + 2;
8102 };
8103
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008104 setinputfile(fullname, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008105 commandname = fullname;
8106 cmdloop(0);
8107 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008108
8109 if (argc > 2) {
8110 freeparam(&shellparam);
8111 shellparam = saveparam;
8112 };
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008113 status = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00008114 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008115 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008116}
8117
8118
Eric Andersenc470f442003-07-28 09:56:35 +00008119static int
8120exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008121{
8122 if (stoppedjobs())
8123 return 0;
8124 if (argc > 1)
8125 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008126 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008127 /* NOTREACHED */
8128}
Eric Andersen62483552001-07-10 06:09:16 +00008129
Paul Fox0b621582005-08-09 19:38:05 +00008130#ifdef CONFIG_ASH_BUILTIN_ECHO
8131static int
8132echocmd(int argc, char **argv)
8133{
8134 return bb_echo(argc, argv);
8135}
8136#endif
Paul Fox6ab03782006-06-08 21:37:26 +00008137
8138#ifdef CONFIG_ASH_BUILTIN_TEST
8139static int
8140testcmd(int argc, char **argv)
8141{
8142 return bb_test(argc, argv);
8143}
8144#endif
8145
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008146/* memalloc.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008147
8148/*
Eric Andersen90898442003-08-06 11:20:52 +00008149 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008150 */
8151
8152static pointer
8153ckrealloc(pointer p, size_t nbytes)
8154{
8155 p = realloc(p, nbytes);
8156 if (p == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008157 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008158 return p;
8159}
8160
Eric Andersen90898442003-08-06 11:20:52 +00008161static pointer
8162ckmalloc(size_t nbytes)
8163{
8164 return ckrealloc(NULL, nbytes);
8165}
Eric Andersenc470f442003-07-28 09:56:35 +00008166
8167/*
8168 * Make a copy of a string in safe storage.
8169 */
8170
8171static char *
8172savestr(const char *s)
8173{
8174 char *p = strdup(s);
8175 if (!p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008176 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008177 return p;
8178}
8179
8180
8181/*
8182 * Parse trees for commands are allocated in lifo order, so we use a stack
8183 * to make this more efficient, and also to avoid all sorts of exception
8184 * handling code to handle interrupts in the middle of a parse.
8185 *
8186 * The size 504 was chosen because the Ultrix malloc handles that size
8187 * well.
8188 */
8189
8190
8191static pointer
8192stalloc(size_t nbytes)
8193{
8194 char *p;
8195 size_t aligned;
8196
8197 aligned = SHELL_ALIGN(nbytes);
8198 if (aligned > stacknleft) {
8199 size_t len;
8200 size_t blocksize;
8201 struct stack_block *sp;
8202
8203 blocksize = aligned;
8204 if (blocksize < MINSIZE)
8205 blocksize = MINSIZE;
8206 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8207 if (len < blocksize)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008208 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008209 INTOFF;
8210 sp = ckmalloc(len);
8211 sp->prev = stackp;
8212 stacknxt = sp->space;
8213 stacknleft = blocksize;
8214 sstrend = stacknxt + blocksize;
8215 stackp = sp;
8216 INTON;
8217 }
8218 p = stacknxt;
8219 stacknxt += aligned;
8220 stacknleft -= aligned;
8221 return p;
8222}
8223
8224
8225void
8226stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008227{
Eric Andersencb57d552001-06-28 07:25:16 +00008228#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008229 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008230 write(2, "stunalloc\n", 10);
8231 abort();
8232 }
8233#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008234 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008235 stacknxt = p;
8236}
8237
8238
Eric Andersenc470f442003-07-28 09:56:35 +00008239void
8240setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008241{
Eric Andersencb57d552001-06-28 07:25:16 +00008242 mark->stackp = stackp;
8243 mark->stacknxt = stacknxt;
8244 mark->stacknleft = stacknleft;
8245 mark->marknext = markp;
8246 markp = mark;
8247}
8248
8249
Eric Andersenc470f442003-07-28 09:56:35 +00008250void
8251popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008252{
Eric Andersencb57d552001-06-28 07:25:16 +00008253 struct stack_block *sp;
8254
8255 INTOFF;
8256 markp = mark->marknext;
8257 while (stackp != mark->stackp) {
8258 sp = stackp;
8259 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008260 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008261 }
8262 stacknxt = mark->stacknxt;
8263 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008264 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008265 INTON;
8266}
8267
8268
8269/*
8270 * When the parser reads in a string, it wants to stick the string on the
8271 * stack and only adjust the stack pointer when it knows how big the
8272 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8273 * of space on top of the stack and stackblocklen returns the length of
8274 * this block. Growstackblock will grow this space by at least one byte,
8275 * possibly moving it (like realloc). Grabstackblock actually allocates the
8276 * part of the block that has been used.
8277 */
8278
Eric Andersenc470f442003-07-28 09:56:35 +00008279void
8280growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008281{
Eric Andersenc470f442003-07-28 09:56:35 +00008282 size_t newlen;
8283
8284 newlen = stacknleft * 2;
8285 if (newlen < stacknleft)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008286 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008287 if (newlen < 128)
8288 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008289
8290 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008291 struct stack_block *oldstackp;
8292 struct stackmark *xmark;
8293 struct stack_block *sp;
8294 struct stack_block *prevstackp;
8295 size_t grosslen;
8296
Eric Andersencb57d552001-06-28 07:25:16 +00008297 INTOFF;
8298 oldstackp = stackp;
8299 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008300 prevstackp = sp->prev;
8301 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8302 sp = ckrealloc((pointer)sp, grosslen);
8303 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008304 stackp = sp;
8305 stacknxt = sp->space;
8306 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008307 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008308
Eric Andersenc470f442003-07-28 09:56:35 +00008309 /*
8310 * Stack marks pointing to the start of the old block
8311 * must be relocated to point to the new block
8312 */
8313 xmark = markp;
8314 while (xmark != NULL && xmark->stackp == oldstackp) {
8315 xmark->stackp = stackp;
8316 xmark->stacknxt = stacknxt;
8317 xmark->stacknleft = stacknleft;
8318 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008319 }
8320 INTON;
8321 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008322 char *oldspace = stacknxt;
8323 int oldlen = stacknleft;
8324 char *p = stalloc(newlen);
8325
8326 /* free the space we just allocated */
8327 stacknxt = memcpy(p, oldspace, oldlen);
8328 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008329 }
8330}
8331
Rob Landley88621d72006-08-29 19:41:06 +00008332static void grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008333{
Eric Andersenc470f442003-07-28 09:56:35 +00008334 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008335 stacknxt += len;
8336 stacknleft -= len;
8337}
8338
Eric Andersencb57d552001-06-28 07:25:16 +00008339/*
Eric Andersenc470f442003-07-28 09:56:35 +00008340 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008341 * The user declares a variable of type STACKSTR, which may be declared
8342 * to be a register. The macro STARTSTACKSTR initializes things. Then
8343 * the user uses the macro STPUTC to add characters to the string. In
8344 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8345 * grown as necessary. When the user is done, she can just leave the
8346 * string there and refer to it using stackblock(). Or she can allocate
8347 * the space for it using grabstackstr(). If it is necessary to allow
8348 * someone else to use the stack temporarily and then continue to grow
8349 * the string, the user should use grabstack to allocate the space, and
8350 * then call ungrabstr(p) to return to the previous mode of operation.
8351 *
8352 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8353 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8354 * is space for at least one character.
8355 */
8356
Eric Andersenc470f442003-07-28 09:56:35 +00008357void *
8358growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008359{
Eric Andersenc470f442003-07-28 09:56:35 +00008360 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008361 if (herefd >= 0 && len >= 1024) {
Rob Landley53437472006-07-16 08:14:35 +00008362 full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008363 return stackblock();
8364 }
8365 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008366 return stackblock() + len;
8367}
8368
Eric Andersencb57d552001-06-28 07:25:16 +00008369/*
8370 * Called from CHECKSTRSPACE.
8371 */
8372
Eric Andersenc470f442003-07-28 09:56:35 +00008373char *
8374makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008375{
Eric Andersenc470f442003-07-28 09:56:35 +00008376 size_t len = p - stacknxt;
8377 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008378
Eric Andersenc470f442003-07-28 09:56:35 +00008379 for (;;) {
8380 size_t nleft;
8381
8382 size = stackblocksize();
8383 nleft = size - len;
8384 if (nleft >= newlen)
8385 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008386 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008387 }
Eric Andersencb57d552001-06-28 07:25:16 +00008388 return stackblock() + len;
8389}
8390
Eric Andersenc470f442003-07-28 09:56:35 +00008391char *
8392stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008393{
Eric Andersenc470f442003-07-28 09:56:35 +00008394 p = makestrspace(n, p);
8395 p = mempcpy(p, s, n);
8396 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008397}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008398
Eric Andersenc470f442003-07-28 09:56:35 +00008399char *
8400stputs(const char *s, char *p)
8401{
8402 return stnputs(s, strlen(s), p);
8403}
8404
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008405/* mystring.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008406
Eric Andersencb57d552001-06-28 07:25:16 +00008407/*
Eric Andersenc470f442003-07-28 09:56:35 +00008408 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008409 *
Eric Andersenc470f442003-07-28 09:56:35 +00008410 * number(s) Convert a string of digits to an integer.
8411 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008412 */
8413
Eric Andersencb57d552001-06-28 07:25:16 +00008414/*
8415 * prefix -- see if pfx is a prefix of string.
8416 */
8417
Eric Andersenc470f442003-07-28 09:56:35 +00008418char *
8419prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008420{
Eric Andersencb57d552001-06-28 07:25:16 +00008421 while (*pfx) {
8422 if (*pfx++ != *string++)
8423 return 0;
8424 }
Eric Andersenc470f442003-07-28 09:56:35 +00008425 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008426}
8427
8428
8429/*
8430 * Convert a string of digits to an integer, printing an error message on
8431 * failure.
8432 */
8433
Eric Andersenc470f442003-07-28 09:56:35 +00008434int
8435number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008436{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008437
Eric Andersenc470f442003-07-28 09:56:35 +00008438 if (! is_number(s))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008439 sh_error(illnum, s);
Eric Andersenc470f442003-07-28 09:56:35 +00008440 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008441}
8442
Eric Andersenc470f442003-07-28 09:56:35 +00008443
Eric Andersenc470f442003-07-28 09:56:35 +00008444/*
8445 * Check for a valid number. This should be elsewhere.
8446 */
8447
8448int
8449is_number(const char *p)
8450{
8451 do {
8452 if (! is_digit(*p))
8453 return 0;
8454 } while (*++p != '\0');
8455 return 1;
8456}
8457
8458
Eric Andersencb57d552001-06-28 07:25:16 +00008459/*
8460 * Produce a possibly single quoted string suitable as input to the shell.
8461 * The return string is allocated on the stack.
8462 */
8463
Eric Andersenc470f442003-07-28 09:56:35 +00008464char *
8465single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008466 char *p;
8467
8468 STARTSTACKSTR(p);
8469
8470 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008471 char *q;
8472 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008473
Eric Andersenc470f442003-07-28 09:56:35 +00008474 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008475
Eric Andersenc470f442003-07-28 09:56:35 +00008476 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008477
Eric Andersenc470f442003-07-28 09:56:35 +00008478 *q++ = '\'';
8479 q = mempcpy(q, s, len);
8480 *q++ = '\'';
8481 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008482
Eric Andersenc470f442003-07-28 09:56:35 +00008483 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008484
Eric Andersenc470f442003-07-28 09:56:35 +00008485 len = strspn(s, "'");
8486 if (!len)
8487 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008488
Eric Andersenc470f442003-07-28 09:56:35 +00008489 q = p = makestrspace(len + 3, p);
8490
8491 *q++ = '"';
8492 q = mempcpy(q, s, len);
8493 *q++ = '"';
8494 s += len;
8495
8496 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008497 } while (*s);
8498
8499 USTPUTC(0, p);
8500
Eric Andersenc470f442003-07-28 09:56:35 +00008501 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008502}
8503
8504/*
Eric Andersenc470f442003-07-28 09:56:35 +00008505 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008506 */
8507
Eric Andersenc470f442003-07-28 09:56:35 +00008508char *
8509sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008510{
Eric Andersenc470f442003-07-28 09:56:35 +00008511 size_t len = strlen(p) + 1;
8512 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008513}
Eric Andersenc470f442003-07-28 09:56:35 +00008514
8515
8516static void
8517calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008518{
Eric Andersenc470f442003-07-28 09:56:35 +00008519 if (n == NULL)
8520 return;
8521 funcblocksize += nodesize[n->type];
8522 switch (n->type) {
8523 case NCMD:
8524 calcsize(n->ncmd.redirect);
8525 calcsize(n->ncmd.args);
8526 calcsize(n->ncmd.assign);
8527 break;
8528 case NPIPE:
8529 sizenodelist(n->npipe.cmdlist);
8530 break;
8531 case NREDIR:
8532 case NBACKGND:
8533 case NSUBSHELL:
8534 calcsize(n->nredir.redirect);
8535 calcsize(n->nredir.n);
8536 break;
8537 case NAND:
8538 case NOR:
8539 case NSEMI:
8540 case NWHILE:
8541 case NUNTIL:
8542 calcsize(n->nbinary.ch2);
8543 calcsize(n->nbinary.ch1);
8544 break;
8545 case NIF:
8546 calcsize(n->nif.elsepart);
8547 calcsize(n->nif.ifpart);
8548 calcsize(n->nif.test);
8549 break;
8550 case NFOR:
8551 funcstringsize += strlen(n->nfor.var) + 1;
8552 calcsize(n->nfor.body);
8553 calcsize(n->nfor.args);
8554 break;
8555 case NCASE:
8556 calcsize(n->ncase.cases);
8557 calcsize(n->ncase.expr);
8558 break;
8559 case NCLIST:
8560 calcsize(n->nclist.body);
8561 calcsize(n->nclist.pattern);
8562 calcsize(n->nclist.next);
8563 break;
8564 case NDEFUN:
8565 case NARG:
8566 sizenodelist(n->narg.backquote);
8567 funcstringsize += strlen(n->narg.text) + 1;
8568 calcsize(n->narg.next);
8569 break;
8570 case NTO:
8571 case NCLOBBER:
8572 case NFROM:
8573 case NFROMTO:
8574 case NAPPEND:
8575 calcsize(n->nfile.fname);
8576 calcsize(n->nfile.next);
8577 break;
8578 case NTOFD:
8579 case NFROMFD:
8580 calcsize(n->ndup.vname);
8581 calcsize(n->ndup.next);
8582 break;
8583 case NHERE:
8584 case NXHERE:
8585 calcsize(n->nhere.doc);
8586 calcsize(n->nhere.next);
8587 break;
8588 case NNOT:
8589 calcsize(n->nnot.com);
8590 break;
8591 };
Eric Andersencb57d552001-06-28 07:25:16 +00008592}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008593
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008594
Eric Andersenc470f442003-07-28 09:56:35 +00008595static void
8596sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008597{
8598 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008599 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008600 calcsize(lp->n);
8601 lp = lp->next;
8602 }
8603}
Eric Andersencb57d552001-06-28 07:25:16 +00008604
8605
Eric Andersenc470f442003-07-28 09:56:35 +00008606static union node *
8607copynode(union node *n)
8608{
8609 union node *new;
8610
8611 if (n == NULL)
8612 return NULL;
8613 new = funcblock;
8614 funcblock = (char *) funcblock + nodesize[n->type];
8615 switch (n->type) {
8616 case NCMD:
8617 new->ncmd.redirect = copynode(n->ncmd.redirect);
8618 new->ncmd.args = copynode(n->ncmd.args);
8619 new->ncmd.assign = copynode(n->ncmd.assign);
8620 break;
8621 case NPIPE:
8622 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8623 new->npipe.backgnd = n->npipe.backgnd;
8624 break;
8625 case NREDIR:
8626 case NBACKGND:
8627 case NSUBSHELL:
8628 new->nredir.redirect = copynode(n->nredir.redirect);
8629 new->nredir.n = copynode(n->nredir.n);
8630 break;
8631 case NAND:
8632 case NOR:
8633 case NSEMI:
8634 case NWHILE:
8635 case NUNTIL:
8636 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8637 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8638 break;
8639 case NIF:
8640 new->nif.elsepart = copynode(n->nif.elsepart);
8641 new->nif.ifpart = copynode(n->nif.ifpart);
8642 new->nif.test = copynode(n->nif.test);
8643 break;
8644 case NFOR:
8645 new->nfor.var = nodesavestr(n->nfor.var);
8646 new->nfor.body = copynode(n->nfor.body);
8647 new->nfor.args = copynode(n->nfor.args);
8648 break;
8649 case NCASE:
8650 new->ncase.cases = copynode(n->ncase.cases);
8651 new->ncase.expr = copynode(n->ncase.expr);
8652 break;
8653 case NCLIST:
8654 new->nclist.body = copynode(n->nclist.body);
8655 new->nclist.pattern = copynode(n->nclist.pattern);
8656 new->nclist.next = copynode(n->nclist.next);
8657 break;
8658 case NDEFUN:
8659 case NARG:
8660 new->narg.backquote = copynodelist(n->narg.backquote);
8661 new->narg.text = nodesavestr(n->narg.text);
8662 new->narg.next = copynode(n->narg.next);
8663 break;
8664 case NTO:
8665 case NCLOBBER:
8666 case NFROM:
8667 case NFROMTO:
8668 case NAPPEND:
8669 new->nfile.fname = copynode(n->nfile.fname);
8670 new->nfile.fd = n->nfile.fd;
8671 new->nfile.next = copynode(n->nfile.next);
8672 break;
8673 case NTOFD:
8674 case NFROMFD:
8675 new->ndup.vname = copynode(n->ndup.vname);
8676 new->ndup.dupfd = n->ndup.dupfd;
8677 new->ndup.fd = n->ndup.fd;
8678 new->ndup.next = copynode(n->ndup.next);
8679 break;
8680 case NHERE:
8681 case NXHERE:
8682 new->nhere.doc = copynode(n->nhere.doc);
8683 new->nhere.fd = n->nhere.fd;
8684 new->nhere.next = copynode(n->nhere.next);
8685 break;
8686 case NNOT:
8687 new->nnot.com = copynode(n->nnot.com);
8688 break;
8689 };
8690 new->type = n->type;
8691 return new;
8692}
8693
8694
8695static struct nodelist *
8696copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008697{
8698 struct nodelist *start;
8699 struct nodelist **lpp;
8700
8701 lpp = &start;
8702 while (lp) {
8703 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008704 funcblock = (char *) funcblock +
8705 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008706 (*lpp)->n = copynode(lp->n);
8707 lp = lp->next;
8708 lpp = &(*lpp)->next;
8709 }
8710 *lpp = NULL;
8711 return start;
8712}
8713
8714
Eric Andersenc470f442003-07-28 09:56:35 +00008715static char *
8716nodesavestr(char *s)
8717{
8718 char *rtn = funcstring;
8719
8720 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008721 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008722}
8723
Eric Andersenc470f442003-07-28 09:56:35 +00008724
Eric Andersenc470f442003-07-28 09:56:35 +00008725/*
8726 * Free a parse tree.
8727 */
8728
8729static void
8730freefunc(struct funcnode *f)
8731{
8732 if (f && --f->count < 0)
8733 ckfree(f);
8734}
8735
8736
8737static void options(int);
8738static void setoption(int, int);
8739
Eric Andersencb57d552001-06-28 07:25:16 +00008740
Eric Andersencb57d552001-06-28 07:25:16 +00008741/*
8742 * Process the shell command line arguments.
8743 */
8744
Eric Andersenc470f442003-07-28 09:56:35 +00008745void
8746procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008747{
8748 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008749 const char *xminusc;
8750 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008751
Eric Andersenc470f442003-07-28 09:56:35 +00008752 xargv = argv;
8753 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008754 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008755 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008756 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008757 optlist[i] = 2;
8758 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008759 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008760 xargv = argptr;
8761 xminusc = minusc;
8762 if (*xargv == NULL) {
8763 if (xminusc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +00008764 sh_error(bb_msg_requires_arg, "-c");
Eric Andersencb57d552001-06-28 07:25:16 +00008765 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008766 }
Eric Andersencb57d552001-06-28 07:25:16 +00008767 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8768 iflag = 1;
8769 if (mflag == 2)
8770 mflag = iflag;
8771 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008772 if (optlist[i] == 2)
8773 optlist[i] = 0;
8774#if DEBUG == 2
8775 debug = 1;
8776#endif
8777 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8778 if (xminusc) {
8779 minusc = *xargv++;
8780 if (*xargv)
8781 goto setarg0;
8782 } else if (!sflag) {
8783 setinputfile(*xargv, 0);
8784setarg0:
8785 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008786 commandname = arg0;
8787 }
Eric Andersencb57d552001-06-28 07:25:16 +00008788
Eric Andersenc470f442003-07-28 09:56:35 +00008789 shellparam.p = xargv;
8790#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008791 shellparam.optind = 1;
8792 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008793#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008794 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008795 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008796 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008797 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008798 }
8799 optschanged();
8800}
8801
8802
Eric Andersenc470f442003-07-28 09:56:35 +00008803void
8804optschanged(void)
8805{
8806#ifdef DEBUG
8807 opentrace();
8808#endif
8809 setinteractive(iflag);
8810 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008811 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008812}
Eric Andersencb57d552001-06-28 07:25:16 +00008813
Rob Landley88621d72006-08-29 19:41:06 +00008814static void minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008815{
8816 int i;
8817
8818 if (name == NULL) {
8819 out1str("Current option settings\n");
8820 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008821 out1fmt("%-16s%s\n", optnames(i),
8822 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008823 } else {
8824 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008825 if (equal(name, optnames(i))) {
8826 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008827 return;
8828 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008829 sh_error("Illegal option -o %s", name);
Eric Andersen62483552001-07-10 06:09:16 +00008830 }
8831}
8832
Eric Andersenc470f442003-07-28 09:56:35 +00008833/*
8834 * Process shell options. The global variable argptr contains a pointer
8835 * to the argument list; we advance it past the options.
8836 */
Eric Andersen62483552001-07-10 06:09:16 +00008837
Eric Andersenc470f442003-07-28 09:56:35 +00008838static void
8839options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008840{
8841 char *p;
8842 int val;
8843 int c;
8844
8845 if (cmdline)
8846 minusc = NULL;
8847 while ((p = *argptr) != NULL) {
8848 argptr++;
8849 if ((c = *p++) == '-') {
8850 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008851 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8852 if (!cmdline) {
8853 /* "-" means turn off -x and -v */
8854 if (p[0] == '\0')
8855 xflag = vflag = 0;
8856 /* "--" means reset params */
8857 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008858 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008859 }
Eric Andersenc470f442003-07-28 09:56:35 +00008860 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008861 }
8862 } else if (c == '+') {
8863 val = 0;
8864 } else {
8865 argptr--;
8866 break;
8867 }
8868 while ((c = *p++) != '\0') {
8869 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008870 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008871 } else if (c == 'o') {
8872 minus_o(*argptr, val);
8873 if (*argptr)
8874 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008875 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008876 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008877 isloginsh = 1;
8878 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008879 } else {
8880 setoption(c, val);
8881 }
8882 }
8883 }
8884}
8885
Eric Andersencb57d552001-06-28 07:25:16 +00008886
Eric Andersenc470f442003-07-28 09:56:35 +00008887static void
8888setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008889{
Eric Andersencb57d552001-06-28 07:25:16 +00008890 int i;
8891
8892 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008893 if (optletters(i) == flag) {
8894 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008895 return;
8896 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008897 sh_error("Illegal option -%c", flag);
Eric Andersencb57d552001-06-28 07:25:16 +00008898 /* NOTREACHED */
8899}
8900
8901
8902
Eric Andersencb57d552001-06-28 07:25:16 +00008903/*
8904 * Set the shell parameters.
8905 */
8906
Eric Andersenc470f442003-07-28 09:56:35 +00008907void
8908setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008909{
Eric Andersencb57d552001-06-28 07:25:16 +00008910 char **newparam;
8911 char **ap;
8912 int nparam;
8913
Eric Andersenc470f442003-07-28 09:56:35 +00008914 for (nparam = 0 ; argv[nparam] ; nparam++);
8915 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008916 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008917 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008918 }
8919 *ap = NULL;
8920 freeparam(&shellparam);
8921 shellparam.malloc = 1;
8922 shellparam.nparam = nparam;
8923 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008924#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008925 shellparam.optind = 1;
8926 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008927#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008928}
8929
8930
8931/*
8932 * Free the list of positional parameters.
8933 */
8934
Eric Andersenc470f442003-07-28 09:56:35 +00008935void
8936freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008937{
Eric Andersencb57d552001-06-28 07:25:16 +00008938 char **ap;
8939
8940 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008941 for (ap = param->p ; *ap ; ap++)
8942 ckfree(*ap);
8943 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008944 }
8945}
8946
8947
8948
8949/*
8950 * The shift builtin command.
8951 */
8952
Eric Andersenc470f442003-07-28 09:56:35 +00008953int
8954shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008955{
8956 int n;
8957 char **ap1, **ap2;
8958
8959 n = 1;
8960 if (argc > 1)
8961 n = number(argv[1]);
8962 if (n > shellparam.nparam)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008963 sh_error("can't shift that many");
Eric Andersencb57d552001-06-28 07:25:16 +00008964 INTOFF;
8965 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008966 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008967 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008968 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008969 }
8970 ap2 = shellparam.p;
8971 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008972#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008973 shellparam.optind = 1;
8974 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008975#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008976 INTON;
8977 return 0;
8978}
8979
8980
8981
8982/*
8983 * The set command builtin.
8984 */
8985
Eric Andersenc470f442003-07-28 09:56:35 +00008986int
8987setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008988{
8989 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00008990 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00008991 INTOFF;
8992 options(0);
8993 optschanged();
8994 if (*argptr != NULL) {
8995 setparam(argptr);
8996 }
8997 INTON;
8998 return 0;
8999}
9000
9001
Eric Andersenc470f442003-07-28 09:56:35 +00009002#ifdef CONFIG_ASH_GETOPTS
9003static void
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00009004getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009005{
9006 shellparam.optind = number(value);
9007 shellparam.optoff = -1;
9008}
Eric Andersenc470f442003-07-28 09:56:35 +00009009#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009010
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009011#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009012static void change_lc_all(const char *value)
9013{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009014 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009015 setlocale(LC_ALL, value);
9016}
9017
9018static void change_lc_ctype(const char *value)
9019{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009020 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009021 setlocale(LC_CTYPE, value);
9022}
9023
9024#endif
9025
Eric Andersen16767e22004-03-16 05:14:10 +00009026#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009027/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009028static void change_random(const char *value)
9029{
Eric Andersen16767e22004-03-16 05:14:10 +00009030 if(value == NULL) {
9031 /* "get", generate */
9032 char buf[16];
9033
9034 rseed = rseed * 1103515245 + 12345;
9035 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9036 /* set without recursion */
9037 setvar(vrandom.text, buf, VNOFUNC);
9038 vrandom.flags &= ~VNOFUNC;
9039 } else {
9040 /* set/reset */
9041 rseed = strtoul(value, (char **)NULL, 10);
9042 }
Eric Andersenef02f822004-03-11 13:34:24 +00009043}
Eric Andersen16767e22004-03-16 05:14:10 +00009044#endif
9045
Eric Andersenef02f822004-03-11 13:34:24 +00009046
Eric Andersend35c5df2002-01-09 15:37:36 +00009047#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009048static int
Eric Andersenc470f442003-07-28 09:56:35 +00009049getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009050{
9051 char *p, *q;
9052 char c = '?';
9053 int done = 0;
9054 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009055 char s[12];
9056 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009057
Eric Andersena48b0a32003-10-22 10:56:47 +00009058 if(*param_optind < 1)
9059 return 1;
9060 optnext = optfirst + *param_optind - 1;
9061
9062 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009063 p = NULL;
9064 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009065 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009066 if (p == NULL || *p == '\0') {
9067 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009068 p = *optnext;
9069 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009070atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009071 p = NULL;
9072 done = 1;
9073 goto out;
9074 }
9075 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009076 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009077 goto atend;
9078 }
9079
9080 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009081 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009082 if (*q == '\0') {
9083 if (optstr[0] == ':') {
9084 s[0] = c;
9085 s[1] = '\0';
9086 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009087 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009088 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009089 (void) unsetvar("OPTARG");
9090 }
9091 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009092 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009093 }
9094 if (*++q == ':')
9095 q++;
9096 }
9097
9098 if (*++q == ':') {
9099 if (*p == '\0' && (p = *optnext) == NULL) {
9100 if (optstr[0] == ':') {
9101 s[0] = c;
9102 s[1] = '\0';
9103 err |= setvarsafe("OPTARG", s, 0);
9104 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009105 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009106 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009107 (void) unsetvar("OPTARG");
9108 c = '?';
9109 }
Eric Andersenc470f442003-07-28 09:56:35 +00009110 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009111 }
9112
9113 if (p == *optnext)
9114 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009115 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009116 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009117 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009118 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009119
Eric Andersenc470f442003-07-28 09:56:35 +00009120out:
Eric Andersencb57d552001-06-28 07:25:16 +00009121 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009122 *param_optind = optnext - optfirst + 1;
9123 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009124 err |= setvarsafe("OPTIND", s, VNOFUNC);
9125 s[0] = c;
9126 s[1] = '\0';
9127 err |= setvarsafe(optvar, s, 0);
9128 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009129 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009130 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009131 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009132 exraise(EXERROR);
9133 }
9134 return done;
9135}
Eric Andersenc470f442003-07-28 09:56:35 +00009136
9137/*
9138 * The getopts builtin. Shellparam.optnext points to the next argument
9139 * to be processed. Shellparam.optptr points to the next character to
9140 * be processed in the current argument. If shellparam.optnext is NULL,
9141 * then it's the first time getopts has been called.
9142 */
9143
9144int
9145getoptscmd(int argc, char **argv)
9146{
9147 char **optbase;
9148
9149 if (argc < 3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009150 sh_error("Usage: getopts optstring var [arg]");
Eric Andersenc470f442003-07-28 09:56:35 +00009151 else if (argc == 3) {
9152 optbase = shellparam.p;
9153 if (shellparam.optind > shellparam.nparam + 1) {
9154 shellparam.optind = 1;
9155 shellparam.optoff = -1;
9156 }
9157 }
9158 else {
9159 optbase = &argv[3];
9160 if (shellparam.optind > argc - 2) {
9161 shellparam.optind = 1;
9162 shellparam.optoff = -1;
9163 }
9164 }
9165
9166 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9167 &shellparam.optoff);
9168}
9169#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009170
9171/*
9172 * XXX - should get rid of. have all builtins use getopt(3). the
9173 * library getopt must have the BSD extension static variable "optreset"
9174 * otherwise it can't be used within the shell safely.
9175 *
9176 * Standard option processing (a la getopt) for builtin routines. The
9177 * only argument that is passed to nextopt is the option string; the
9178 * other arguments are unnecessary. It return the character, or '\0' on
9179 * end of input.
9180 */
9181
Eric Andersenc470f442003-07-28 09:56:35 +00009182static int
9183nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009184{
Eric Andersencb57d552001-06-28 07:25:16 +00009185 char *p;
9186 const char *q;
9187 char c;
9188
9189 if ((p = optptr) == NULL || *p == '\0') {
9190 p = *argptr;
9191 if (p == NULL || *p != '-' || *++p == '\0')
9192 return '\0';
9193 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009194 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009195 return '\0';
9196 }
9197 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009198 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009199 if (*q == '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009200 sh_error("Illegal option -%c", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009201 if (*++q == ':')
9202 q++;
9203 }
9204 if (*++q == ':') {
9205 if (*p == '\0' && (p = *argptr++) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009206 sh_error("No arg for -%c option", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009207 optionarg = p;
9208 p = NULL;
9209 }
9210 optptr = p;
9211 return c;
9212}
9213
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009214
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009215/* output.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009216
Eric Andersenc470f442003-07-28 09:56:35 +00009217void
9218outstr(const char *p, FILE *file)
9219{
9220 INTOFF;
9221 fputs(p, file);
9222 INTON;
9223}
9224
9225void
9226flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009227{
Eric Andersencb57d552001-06-28 07:25:16 +00009228 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009229 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009230 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009231 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009232}
9233
Eric Andersenc470f442003-07-28 09:56:35 +00009234void
Eric Andersen16767e22004-03-16 05:14:10 +00009235flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009236{
9237 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009238 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009239 INTON;
9240}
9241
9242static void
9243outcslow(int c, FILE *dest)
9244{
9245 INTOFF;
9246 putc(c, dest);
9247 fflush(dest);
9248 INTON;
9249}
9250
9251
9252static int
9253out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009254{
9255 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009256 int r;
9257
9258 INTOFF;
9259 va_start(ap, fmt);
9260 r = vprintf(fmt, ap);
9261 va_end(ap);
9262 INTON;
9263 return r;
9264}
9265
9266
9267int
9268fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9269{
9270 va_list ap;
9271 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009272
Eric Andersencb57d552001-06-28 07:25:16 +00009273 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009274 INTOFF;
9275 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009276 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009277 INTON;
9278 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009279}
9280
Eric Andersenc470f442003-07-28 09:56:35 +00009281
Eric Andersencb57d552001-06-28 07:25:16 +00009282
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009283/* parser.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009284
9285
Eric Andersencb57d552001-06-28 07:25:16 +00009286/*
9287 * Shell command parser.
9288 */
9289
9290#define EOFMARKLEN 79
9291
9292
Eric Andersencb57d552001-06-28 07:25:16 +00009293struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009294 struct heredoc *next; /* next here document in list */
9295 union node *here; /* redirection node */
9296 char *eofmark; /* string indicating end of input */
9297 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009298};
9299
9300
9301
Eric Andersenc470f442003-07-28 09:56:35 +00009302static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009303
9304
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009305static union node *list(int);
9306static union node *andor(void);
9307static union node *pipeline(void);
9308static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009309static union node *simplecmd(void);
9310static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009311static void parsefname(void);
9312static void parseheredoc(void);
9313static char peektoken(void);
9314static int readtoken(void);
9315static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009316static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009317static int noexpand(char *);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00009318static void synexpect(int) ATTRIBUTE_NORETURN;
9319static void synerror(const char *) ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009320static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009321
9322
Eric Andersenc470f442003-07-28 09:56:35 +00009323
Eric Andersenc470f442003-07-28 09:56:35 +00009324
Eric Andersencb57d552001-06-28 07:25:16 +00009325/*
9326 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9327 * valid parse tree indicating a blank line.)
9328 */
9329
Eric Andersenc470f442003-07-28 09:56:35 +00009330union node *
9331parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009332{
9333 int t;
9334
9335 tokpushback = 0;
9336 doprompt = interact;
9337 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009338 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009339 needprompt = 0;
9340 t = readtoken();
9341 if (t == TEOF)
9342 return NEOF;
9343 if (t == TNL)
9344 return NULL;
9345 tokpushback++;
9346 return list(1);
9347}
9348
9349
Eric Andersenc470f442003-07-28 09:56:35 +00009350static union node *
9351list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009352{
9353 union node *n1, *n2, *n3;
9354 int tok;
9355
Eric Andersenc470f442003-07-28 09:56:35 +00009356 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9357 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009358 return NULL;
9359 n1 = NULL;
9360 for (;;) {
9361 n2 = andor();
9362 tok = readtoken();
9363 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009364 if (n2->type == NPIPE) {
9365 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009366 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009367 if (n2->type != NREDIR) {
9368 n3 = stalloc(sizeof(struct nredir));
9369 n3->nredir.n = n2;
9370 n3->nredir.redirect = NULL;
9371 n2 = n3;
9372 }
9373 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009374 }
9375 }
9376 if (n1 == NULL) {
9377 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009378 }
9379 else {
9380 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009381 n3->type = NSEMI;
9382 n3->nbinary.ch1 = n1;
9383 n3->nbinary.ch2 = n2;
9384 n1 = n3;
9385 }
9386 switch (tok) {
9387 case TBACKGND:
9388 case TSEMI:
9389 tok = readtoken();
9390 /* fall through */
9391 case TNL:
9392 if (tok == TNL) {
9393 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009394 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009395 return n1;
9396 } else {
9397 tokpushback++;
9398 }
Eric Andersenc470f442003-07-28 09:56:35 +00009399 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009400 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009401 return n1;
9402 break;
9403 case TEOF:
9404 if (heredoclist)
9405 parseheredoc();
9406 else
Eric Andersenc470f442003-07-28 09:56:35 +00009407 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009408 return n1;
9409 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009410 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009411 synexpect(-1);
9412 tokpushback++;
9413 return n1;
9414 }
9415 }
9416}
9417
9418
9419
Eric Andersenc470f442003-07-28 09:56:35 +00009420static union node *
9421andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009422{
Eric Andersencb57d552001-06-28 07:25:16 +00009423 union node *n1, *n2, *n3;
9424 int t;
9425
Eric Andersencb57d552001-06-28 07:25:16 +00009426 n1 = pipeline();
9427 for (;;) {
9428 if ((t = readtoken()) == TAND) {
9429 t = NAND;
9430 } else if (t == TOR) {
9431 t = NOR;
9432 } else {
9433 tokpushback++;
9434 return n1;
9435 }
Eric Andersenc470f442003-07-28 09:56:35 +00009436 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009437 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009438 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009439 n3->type = t;
9440 n3->nbinary.ch1 = n1;
9441 n3->nbinary.ch2 = n2;
9442 n1 = n3;
9443 }
9444}
9445
9446
9447
Eric Andersenc470f442003-07-28 09:56:35 +00009448static union node *
9449pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009450{
Eric Andersencb57d552001-06-28 07:25:16 +00009451 union node *n1, *n2, *pipenode;
9452 struct nodelist *lp, *prev;
9453 int negate;
9454
9455 negate = 0;
9456 TRACE(("pipeline: entered\n"));
9457 if (readtoken() == TNOT) {
9458 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009459 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009460 } else
9461 tokpushback++;
9462 n1 = command();
9463 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009464 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009465 pipenode->type = NPIPE;
9466 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009467 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009468 pipenode->npipe.cmdlist = lp;
9469 lp->n = n1;
9470 do {
9471 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009472 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9473 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009474 lp->n = command();
9475 prev->next = lp;
9476 } while (readtoken() == TPIPE);
9477 lp->next = NULL;
9478 n1 = pipenode;
9479 }
9480 tokpushback++;
9481 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009482 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009483 n2->type = NNOT;
9484 n2->nnot.com = n1;
9485 return n2;
9486 } else
9487 return n1;
9488}
9489
9490
9491
Eric Andersenc470f442003-07-28 09:56:35 +00009492static union node *
9493command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009494{
Eric Andersencb57d552001-06-28 07:25:16 +00009495 union node *n1, *n2;
9496 union node *ap, **app;
9497 union node *cp, **cpp;
9498 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009499 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009500 int t;
9501
9502 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009503 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009504
Eric Andersencb57d552001-06-28 07:25:16 +00009505 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009506 default:
9507 synexpect(-1);
9508 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009509 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009510 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009511 n1->type = NIF;
9512 n1->nif.test = list(0);
9513 if (readtoken() != TTHEN)
9514 synexpect(TTHEN);
9515 n1->nif.ifpart = list(0);
9516 n2 = n1;
9517 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009518 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009519 n2 = n2->nif.elsepart;
9520 n2->type = NIF;
9521 n2->nif.test = list(0);
9522 if (readtoken() != TTHEN)
9523 synexpect(TTHEN);
9524 n2->nif.ifpart = list(0);
9525 }
9526 if (lasttoken == TELSE)
9527 n2->nif.elsepart = list(0);
9528 else {
9529 n2->nif.elsepart = NULL;
9530 tokpushback++;
9531 }
Eric Andersenc470f442003-07-28 09:56:35 +00009532 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009533 break;
9534 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009535 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009536 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009537 n1 = (union node *)stalloc(sizeof (struct nbinary));
9538 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009539 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009540 if ((got=readtoken()) != TDO) {
9541TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009542 synexpect(TDO);
9543 }
9544 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009545 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009546 break;
9547 }
9548 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009549 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009550 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009551 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009552 n1->type = NFOR;
9553 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009554 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009555 if (readtoken() == TIN) {
9556 app = &ap;
9557 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009558 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009559 n2->type = NARG;
9560 n2->narg.text = wordtext;
9561 n2->narg.backquote = backquotelist;
9562 *app = n2;
9563 app = &n2->narg.next;
9564 }
9565 *app = NULL;
9566 n1->nfor.args = ap;
9567 if (lasttoken != TNL && lasttoken != TSEMI)
9568 synexpect(-1);
9569 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009570 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009571 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009572 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009573 n2->narg.backquote = NULL;
9574 n2->narg.next = NULL;
9575 n1->nfor.args = n2;
9576 /*
9577 * Newline or semicolon here is optional (but note
9578 * that the original Bourne shell only allowed NL).
9579 */
9580 if (lasttoken != TNL && lasttoken != TSEMI)
9581 tokpushback++;
9582 }
Eric Andersenc470f442003-07-28 09:56:35 +00009583 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009584 if (readtoken() != TDO)
9585 synexpect(TDO);
9586 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009587 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009588 break;
9589 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009590 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009591 n1->type = NCASE;
9592 if (readtoken() != TWORD)
9593 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009594 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009595 n2->type = NARG;
9596 n2->narg.text = wordtext;
9597 n2->narg.backquote = backquotelist;
9598 n2->narg.next = NULL;
9599 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009600 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009601 } while (readtoken() == TNL);
9602 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009603 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009604 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009605next_case:
9606 checkkwd = CHKNL | CHKKWD;
9607 t = readtoken();
9608 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009609 if (lasttoken == TLP)
9610 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009611 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009612 cp->type = NCLIST;
9613 app = &cp->nclist.pattern;
9614 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009615 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009616 ap->type = NARG;
9617 ap->narg.text = wordtext;
9618 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009619 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009620 break;
9621 app = &ap->narg.next;
9622 readtoken();
9623 }
9624 ap->narg.next = NULL;
9625 if (lasttoken != TRP)
9626 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009627 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009628
Eric Andersenc470f442003-07-28 09:56:35 +00009629 cpp = &cp->nclist.next;
9630
9631 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009632 if ((t = readtoken()) != TESAC) {
9633 if (t != TENDCASE)
9634 synexpect(TENDCASE);
9635 else
Eric Andersenc470f442003-07-28 09:56:35 +00009636 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009637 }
Eric Andersenc470f442003-07-28 09:56:35 +00009638 }
Eric Andersencb57d552001-06-28 07:25:16 +00009639 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009640 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009641 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009642 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009643 n1->type = NSUBSHELL;
9644 n1->nredir.n = list(0);
9645 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009646 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009647 break;
9648 case TBEGIN:
9649 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009650 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009651 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009652 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009653 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009654 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009655 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009656 }
9657
Eric Andersenc470f442003-07-28 09:56:35 +00009658 if (readtoken() != t)
9659 synexpect(t);
9660
9661redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009662 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009663 checkkwd = CHKKWD | CHKALIAS;
9664 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009665 while (readtoken() == TREDIR) {
9666 *rpp = n2 = redirnode;
9667 rpp = &n2->nfile.next;
9668 parsefname();
9669 }
9670 tokpushback++;
9671 *rpp = NULL;
9672 if (redir) {
9673 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009674 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009675 n2->type = NREDIR;
9676 n2->nredir.n = n1;
9677 n1 = n2;
9678 }
9679 n1->nredir.redirect = redir;
9680 }
9681
9682 return n1;
9683}
9684
9685
Eric Andersenc470f442003-07-28 09:56:35 +00009686static union node *
9687simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009688 union node *args, **app;
9689 union node *n = NULL;
9690 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009691 union node **rpp, *redir;
9692 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009693
9694 args = NULL;
9695 app = &args;
9696 vars = NULL;
9697 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009698 redir = NULL;
9699 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009700
Eric Andersenc470f442003-07-28 09:56:35 +00009701 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009702 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009703 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009704 switch (readtoken()) {
9705 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009706 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009707 n->type = NARG;
9708 n->narg.text = wordtext;
9709 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009710 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009711 *vpp = n;
9712 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009713 } else {
9714 *app = n;
9715 app = &n->narg.next;
9716 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009717 }
9718 break;
9719 case TREDIR:
9720 *rpp = n = redirnode;
9721 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009722 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009723 break;
9724 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009725 if (
9726 args && app == &args->narg.next &&
9727 !vars && !redir
9728 ) {
9729 struct builtincmd *bcmd;
9730 const char *name;
9731
Eric Andersencb57d552001-06-28 07:25:16 +00009732 /* We have a function */
9733 if (readtoken() != TRP)
9734 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009735 name = n->narg.text;
9736 if (
9737 !goodname(name) || (
9738 (bcmd = find_builtin(name)) &&
9739 IS_BUILTIN_SPECIAL(bcmd)
9740 )
9741 )
9742 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009743 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009744 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009745 n->narg.next = command();
9746 return n;
9747 }
9748 /* fall through */
9749 default:
9750 tokpushback++;
9751 goto out;
9752 }
9753 }
Eric Andersenc470f442003-07-28 09:56:35 +00009754out:
Eric Andersencb57d552001-06-28 07:25:16 +00009755 *app = NULL;
9756 *vpp = NULL;
9757 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009758 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009759 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009760 n->ncmd.args = args;
9761 n->ncmd.assign = vars;
9762 n->ncmd.redirect = redir;
9763 return n;
9764}
9765
Eric Andersenc470f442003-07-28 09:56:35 +00009766static union node *
9767makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009768{
Eric Andersencb57d552001-06-28 07:25:16 +00009769 union node *n;
9770
Eric Andersenc470f442003-07-28 09:56:35 +00009771 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009772 n->type = NARG;
9773 n->narg.next = NULL;
9774 n->narg.text = wordtext;
9775 n->narg.backquote = backquotelist;
9776 return n;
9777}
9778
Eric Andersenc470f442003-07-28 09:56:35 +00009779void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009780{
Eric Andersencb57d552001-06-28 07:25:16 +00009781 TRACE(("Fix redir %s %d\n", text, err));
9782 if (!err)
9783 n->ndup.vname = NULL;
9784
9785 if (is_digit(text[0]) && text[1] == '\0')
9786 n->ndup.dupfd = digit_val(text[0]);
9787 else if (text[0] == '-' && text[1] == '\0')
9788 n->ndup.dupfd = -1;
9789 else {
9790
9791 if (err)
9792 synerror("Bad fd number");
9793 else
9794 n->ndup.vname = makename();
9795 }
9796}
9797
9798
Eric Andersenc470f442003-07-28 09:56:35 +00009799static void
9800parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009801{
Eric Andersencb57d552001-06-28 07:25:16 +00009802 union node *n = redirnode;
9803
9804 if (readtoken() != TWORD)
9805 synexpect(-1);
9806 if (n->type == NHERE) {
9807 struct heredoc *here = heredoc;
9808 struct heredoc *p;
9809 int i;
9810
9811 if (quoteflag == 0)
9812 n->type = NXHERE;
9813 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009814 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009815 synerror("Illegal eof marker for << redirection");
9816 rmescapes(wordtext);
9817 here->eofmark = wordtext;
9818 here->next = NULL;
9819 if (heredoclist == NULL)
9820 heredoclist = here;
9821 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009822 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009823 p->next = here;
9824 }
9825 } else if (n->type == NTOFD || n->type == NFROMFD) {
9826 fixredir(n, wordtext, 0);
9827 } else {
9828 n->nfile.fname = makename();
9829 }
9830}
9831
9832
9833/*
9834 * Input any here documents.
9835 */
9836
Eric Andersenc470f442003-07-28 09:56:35 +00009837static void
9838parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009839{
Eric Andersencb57d552001-06-28 07:25:16 +00009840 struct heredoc *here;
9841 union node *n;
9842
Eric Andersenc470f442003-07-28 09:56:35 +00009843 here = heredoclist;
9844 heredoclist = 0;
9845
9846 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009847 if (needprompt) {
9848 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009849 }
Eric Andersenc470f442003-07-28 09:56:35 +00009850 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9851 here->eofmark, here->striptabs);
9852 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009853 n->narg.type = NARG;
9854 n->narg.next = NULL;
9855 n->narg.text = wordtext;
9856 n->narg.backquote = backquotelist;
9857 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009858 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009859 }
9860}
9861
Eric Andersenc470f442003-07-28 09:56:35 +00009862static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009863{
Eric Andersencb57d552001-06-28 07:25:16 +00009864 int t;
9865
9866 t = readtoken();
9867 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009868 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009869}
9870
Eric Andersenc470f442003-07-28 09:56:35 +00009871static int
9872readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009873{
Eric Andersencb57d552001-06-28 07:25:16 +00009874 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009875#ifdef DEBUG
9876 int alreadyseen = tokpushback;
9877#endif
9878
Eric Andersend35c5df2002-01-09 15:37:36 +00009879#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009880top:
Eric Andersen2870d962001-07-02 17:27:21 +00009881#endif
9882
Eric Andersencb57d552001-06-28 07:25:16 +00009883 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009884
Eric Andersenc470f442003-07-28 09:56:35 +00009885 /*
9886 * eat newlines
9887 */
9888 if (checkkwd & CHKNL) {
9889 while (t == TNL) {
9890 parseheredoc();
9891 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009892 }
9893 }
9894
Eric Andersenc470f442003-07-28 09:56:35 +00009895 if (t != TWORD || quoteflag) {
9896 goto out;
9897 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009898
Eric Andersenc470f442003-07-28 09:56:35 +00009899 /*
9900 * check for keywords
9901 */
9902 if (checkkwd & CHKKWD) {
9903 const char *const *pp;
9904
9905 if ((pp = findkwd(wordtext))) {
9906 lasttoken = t = pp - tokname_array;
9907 TRACE(("keyword %s recognized\n", tokname(t)));
9908 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009909 }
Eric Andersenc470f442003-07-28 09:56:35 +00009910 }
9911
9912 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009913#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009914 struct alias *ap;
9915 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009916 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009917 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009918 }
Eric Andersencb57d552001-06-28 07:25:16 +00009919 goto top;
9920 }
Eric Andersen2870d962001-07-02 17:27:21 +00009921#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009922 }
Eric Andersenc470f442003-07-28 09:56:35 +00009923out:
9924 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009925#ifdef DEBUG
9926 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009927 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009928 else
Eric Andersenc470f442003-07-28 09:56:35 +00009929 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009930#endif
9931 return (t);
9932}
9933
9934
9935/*
9936 * Read the next input token.
9937 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009938 * backquotes. We set quoteflag to true if any part of the word was
9939 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009940 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009941 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009942 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009943 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009944 *
9945 * [Change comment: here documents and internal procedures]
9946 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9947 * word parsing code into a separate routine. In this case, readtoken
9948 * doesn't need to have any internal procedures, but parseword does.
9949 * We could also make parseoperator in essence the main routine, and
9950 * have parseword (readtoken1?) handle both words and redirection.]
9951 */
9952
Eric Andersen81fe1232003-07-29 06:38:40 +00009953#define NEW_xxreadtoken
9954#ifdef NEW_xxreadtoken
9955
9956/* singles must be first! */
9957static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9958
9959static const char xxreadtoken_tokens[] = {
9960 TNL, TLP, TRP, /* only single occurrence allowed */
9961 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9962 TEOF, /* corresponds to trailing nul */
9963 TAND, TOR, TENDCASE, /* if double occurrence */
9964};
9965
9966#define xxreadtoken_doubles \
9967 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9968#define xxreadtoken_singles \
9969 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9970
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00009971static int xxreadtoken(void)
Eric Andersen81fe1232003-07-29 06:38:40 +00009972{
9973 int c;
9974
9975 if (tokpushback) {
9976 tokpushback = 0;
9977 return lasttoken;
9978 }
9979 if (needprompt) {
9980 setprompt(2);
Eric Andersen81fe1232003-07-29 06:38:40 +00009981 }
9982 startlinno = plinno;
9983 for (;;) { /* until token or start of word found */
9984 c = pgetc_macro();
9985
9986 if ((c != ' ') && (c != '\t')
9987#ifdef CONFIG_ASH_ALIAS
9988 && (c != PEOA)
9989#endif
9990 ) {
9991 if (c == '#') {
9992 while ((c = pgetc()) != '\n' && c != PEOF);
9993 pungetc();
9994 } else if (c == '\\') {
9995 if (pgetc() != '\n') {
9996 pungetc();
9997 goto READTOKEN1;
9998 }
9999 startlinno = ++plinno;
10000 if (doprompt)
10001 setprompt(2);
10002 } else {
10003 const char *p
10004 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10005
10006 if (c != PEOF) {
10007 if (c == '\n') {
10008 plinno++;
10009 needprompt = doprompt;
10010 }
10011
10012 p = strchr(xxreadtoken_chars, c);
10013 if (p == NULL) {
10014 READTOKEN1:
10015 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10016 }
10017
10018 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10019 if (pgetc() == *p) { /* double occurrence? */
10020 p += xxreadtoken_doubles + 1;
10021 } else {
10022 pungetc();
10023 }
10024 }
10025 }
10026
10027 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10028 }
10029 }
10030 }
10031}
10032
10033
10034#else
Eric Andersen2870d962001-07-02 17:27:21 +000010035#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010036
Eric Andersenc470f442003-07-28 09:56:35 +000010037static int
10038xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010039{
Eric Andersencb57d552001-06-28 07:25:16 +000010040 int c;
10041
10042 if (tokpushback) {
10043 tokpushback = 0;
10044 return lasttoken;
10045 }
10046 if (needprompt) {
10047 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010048 }
10049 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010050 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010051 c = pgetc_macro();
10052 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010053 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010054#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010055 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010056#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010057 continue;
10058 case '#':
10059 while ((c = pgetc()) != '\n' && c != PEOF);
10060 pungetc();
10061 continue;
10062 case '\\':
10063 if (pgetc() == '\n') {
10064 startlinno = ++plinno;
10065 if (doprompt)
10066 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010067 continue;
10068 }
10069 pungetc();
10070 goto breakloop;
10071 case '\n':
10072 plinno++;
10073 needprompt = doprompt;
10074 RETURN(TNL);
10075 case PEOF:
10076 RETURN(TEOF);
10077 case '&':
10078 if (pgetc() == '&')
10079 RETURN(TAND);
10080 pungetc();
10081 RETURN(TBACKGND);
10082 case '|':
10083 if (pgetc() == '|')
10084 RETURN(TOR);
10085 pungetc();
10086 RETURN(TPIPE);
10087 case ';':
10088 if (pgetc() == ';')
10089 RETURN(TENDCASE);
10090 pungetc();
10091 RETURN(TSEMI);
10092 case '(':
10093 RETURN(TLP);
10094 case ')':
10095 RETURN(TRP);
10096 default:
10097 goto breakloop;
10098 }
10099 }
Eric Andersenc470f442003-07-28 09:56:35 +000010100breakloop:
10101 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010102#undef RETURN
10103}
Eric Andersen81fe1232003-07-29 06:38:40 +000010104#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010105
Eric Andersencb57d552001-06-28 07:25:16 +000010106
Eric Andersencb57d552001-06-28 07:25:16 +000010107/*
10108 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10109 * is not NULL, read a here document. In the latter case, eofmark is the
10110 * word which marks the end of the document and striptabs is true if
10111 * leading tabs should be stripped from the document. The argument firstc
10112 * is the first character of the input token or document.
10113 *
10114 * Because C does not have internal subroutines, I have simulated them
10115 * using goto's to implement the subroutine linkage. The following macros
10116 * will run code that appears at the end of readtoken1.
10117 */
10118
Eric Andersen2870d962001-07-02 17:27:21 +000010119#define CHECKEND() {goto checkend; checkend_return:;}
10120#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10121#define PARSESUB() {goto parsesub; parsesub_return:;}
10122#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10123#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10124#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010125
10126static int
Eric Andersenc470f442003-07-28 09:56:35 +000010127readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010128{
Eric Andersencb57d552001-06-28 07:25:16 +000010129 int c = firstc;
10130 char *out;
10131 int len;
10132 char line[EOFMARKLEN + 1];
Eric Andersena68ea1c2006-01-30 22:48:39 +000010133 struct nodelist *bqlist = 0;
10134 int quotef = 0;
10135 int dblquote = 0;
10136 int varnest = 0; /* levels of variables expansion */
10137 int arinest = 0; /* levels of arithmetic expansion */
10138 int parenlevel = 0; /* levels of parens in arithmetic */
10139 int dqvarnest = 0; /* levels of variables expansion within double quotes */
10140 int oldstyle = 0;
10141 int prevsyntax = 0; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010142#if __GNUC__
10143 /* Avoid longjmp clobbering */
10144 (void) &out;
10145 (void) &quotef;
10146 (void) &dblquote;
10147 (void) &varnest;
10148 (void) &arinest;
10149 (void) &parenlevel;
10150 (void) &dqvarnest;
10151 (void) &oldstyle;
10152 (void) &prevsyntax;
10153 (void) &syntax;
10154#endif
10155
10156 startlinno = plinno;
10157 dblquote = 0;
10158 if (syntax == DQSYNTAX)
10159 dblquote = 1;
10160 quotef = 0;
10161 bqlist = NULL;
10162 varnest = 0;
10163 arinest = 0;
10164 parenlevel = 0;
10165 dqvarnest = 0;
10166
10167 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010168 loop: { /* for each line, until end of word */
10169 CHECKEND(); /* set c to PEOF if at end of here document */
10170 for (;;) { /* until end of line or end of word */
10171 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10172 switch(SIT(c, syntax)) {
10173 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010174 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010175 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010176 USTPUTC(c, out);
10177 plinno++;
10178 if (doprompt)
10179 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010180 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010181 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010182 case CWORD:
10183 USTPUTC(c, out);
10184 break;
10185 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010186 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010187 USTPUTC(CTLESC, out);
10188 USTPUTC(c, out);
10189 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010190 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010191 c = pgetc2();
10192 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010193 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010194 USTPUTC('\\', out);
10195 pungetc();
10196 } else if (c == '\n') {
10197 if (doprompt)
10198 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010199 } else {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010200 if (dblquote &&
Eric Andersenc470f442003-07-28 09:56:35 +000010201 c != '\\' && c != '`' &&
10202 c != '$' && (
10203 c != '"' ||
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010204 eofmark != NULL)
Eric Andersenc470f442003-07-28 09:56:35 +000010205 ) {
10206 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010207 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010208 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010209 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010210 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010211 USTPUTC(c, out);
10212 quotef++;
10213 }
10214 break;
10215 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010216 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010217quotemark:
10218 if (eofmark == NULL) {
10219 USTPUTC(CTLQUOTEMARK, out);
10220 }
Eric Andersencb57d552001-06-28 07:25:16 +000010221 break;
10222 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010223 syntax = DQSYNTAX;
10224 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010225 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010226 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010227 if (eofmark != NULL && arinest == 0 &&
10228 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010229 USTPUTC(c, out);
10230 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010231 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010232 syntax = BASESYNTAX;
10233 dblquote = 0;
10234 }
10235 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010236 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010237 }
10238 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010239 case CVAR: /* '$' */
10240 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010241 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010242 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010243 if (varnest > 0) {
10244 varnest--;
10245 if (dqvarnest > 0) {
10246 dqvarnest--;
10247 }
10248 USTPUTC(CTLENDVAR, out);
10249 } else {
10250 USTPUTC(c, out);
10251 }
10252 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010253#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010254 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010255 parenlevel++;
10256 USTPUTC(c, out);
10257 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010258 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010259 if (parenlevel > 0) {
10260 USTPUTC(c, out);
10261 --parenlevel;
10262 } else {
10263 if (pgetc() == ')') {
10264 if (--arinest == 0) {
10265 USTPUTC(CTLENDARI, out);
10266 syntax = prevsyntax;
10267 if (syntax == DQSYNTAX)
10268 dblquote = 1;
10269 else
10270 dblquote = 0;
10271 } else
10272 USTPUTC(')', out);
10273 } else {
10274 /*
10275 * unbalanced parens
10276 * (don't 2nd guess - no error)
10277 */
10278 pungetc();
10279 USTPUTC(')', out);
10280 }
10281 }
10282 break;
10283#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010284 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010285 PARSEBACKQOLD();
10286 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010287 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010288 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010289 case CIGN:
10290 break;
10291 default:
10292 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010293 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010294#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010295 if (c != PEOA)
10296#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010297 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010298
Eric Andersencb57d552001-06-28 07:25:16 +000010299 }
10300 c = pgetc_macro();
10301 }
10302 }
Eric Andersenc470f442003-07-28 09:56:35 +000010303endword:
10304#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010305 if (syntax == ARISYNTAX)
10306 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010307#endif
10308 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010309 synerror("Unterminated quoted string");
10310 if (varnest != 0) {
10311 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010312 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010313 synerror("Missing '}'");
10314 }
10315 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010316 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010317 out = stackblock();
10318 if (eofmark == NULL) {
10319 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010320 && quotef == 0
10321 && len <= 2
10322 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010323 PARSEREDIR();
10324 return lasttoken = TREDIR;
10325 } else {
10326 pungetc();
10327 }
10328 }
10329 quoteflag = quotef;
10330 backquotelist = bqlist;
10331 grabstackblock(len);
10332 wordtext = out;
10333 return lasttoken = TWORD;
10334/* end of readtoken routine */
10335
10336
10337
10338/*
10339 * Check to see whether we are at the end of the here document. When this
10340 * is called, c is set to the first character of the next input line. If
10341 * we are at the end of the here document, this routine sets the c to PEOF.
10342 */
10343
Eric Andersenc470f442003-07-28 09:56:35 +000010344checkend: {
10345 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010346#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010347 if (c == PEOA) {
10348 c = pgetc2();
10349 }
10350#endif
10351 if (striptabs) {
10352 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010353 c = pgetc2();
10354 }
Eric Andersenc470f442003-07-28 09:56:35 +000010355 }
10356 if (c == *eofmark) {
10357 if (pfgets(line, sizeof line) != NULL) {
10358 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010359
Eric Andersenc470f442003-07-28 09:56:35 +000010360 p = line;
10361 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10362 if (*p == '\n' && *q == '\0') {
10363 c = PEOF;
10364 plinno++;
10365 needprompt = doprompt;
10366 } else {
10367 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010368 }
10369 }
10370 }
10371 }
Eric Andersenc470f442003-07-28 09:56:35 +000010372 goto checkend_return;
10373}
Eric Andersencb57d552001-06-28 07:25:16 +000010374
10375
10376/*
10377 * Parse a redirection operator. The variable "out" points to a string
10378 * specifying the fd to be redirected. The variable "c" contains the
10379 * first character of the redirection operator.
10380 */
10381
Eric Andersenc470f442003-07-28 09:56:35 +000010382parseredir: {
10383 char fd = *out;
10384 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010385
Eric Andersenc470f442003-07-28 09:56:35 +000010386 np = (union node *)stalloc(sizeof (struct nfile));
10387 if (c == '>') {
10388 np->nfile.fd = 1;
10389 c = pgetc();
10390 if (c == '>')
10391 np->type = NAPPEND;
10392 else if (c == '|')
10393 np->type = NCLOBBER;
10394 else if (c == '&')
10395 np->type = NTOFD;
10396 else {
10397 np->type = NTO;
10398 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010399 }
Eric Andersenc470f442003-07-28 09:56:35 +000010400 } else { /* c == '<' */
10401 np->nfile.fd = 0;
10402 switch (c = pgetc()) {
10403 case '<':
10404 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10405 np = (union node *)stalloc(sizeof (struct nhere));
10406 np->nfile.fd = 0;
10407 }
10408 np->type = NHERE;
10409 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10410 heredoc->here = np;
10411 if ((c = pgetc()) == '-') {
10412 heredoc->striptabs = 1;
10413 } else {
10414 heredoc->striptabs = 0;
10415 pungetc();
10416 }
10417 break;
10418
10419 case '&':
10420 np->type = NFROMFD;
10421 break;
10422
10423 case '>':
10424 np->type = NFROMTO;
10425 break;
10426
10427 default:
10428 np->type = NFROM;
10429 pungetc();
10430 break;
10431 }
Eric Andersencb57d552001-06-28 07:25:16 +000010432 }
Eric Andersenc470f442003-07-28 09:56:35 +000010433 if (fd != '\0')
10434 np->nfile.fd = digit_val(fd);
10435 redirnode = np;
10436 goto parseredir_return;
10437}
Eric Andersencb57d552001-06-28 07:25:16 +000010438
10439
10440/*
10441 * Parse a substitution. At this point, we have read the dollar sign
10442 * and nothing else.
10443 */
10444
Eric Andersenc470f442003-07-28 09:56:35 +000010445parsesub: {
10446 int subtype;
10447 int typeloc;
10448 int flags;
10449 char *p;
10450 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010451
Eric Andersenc470f442003-07-28 09:56:35 +000010452 c = pgetc();
10453 if (
10454 c <= PEOA_OR_PEOF ||
10455 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10456 ) {
10457 USTPUTC('$', out);
10458 pungetc();
10459 } else if (c == '(') { /* $(command) or $((arith)) */
10460 if (pgetc() == '(') {
10461#ifdef CONFIG_ASH_MATH_SUPPORT
10462 PARSEARITH();
10463#else
10464 synerror("We unsupport $((arith))");
10465#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010466 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010467 pungetc();
10468 PARSEBACKQNEW();
10469 }
10470 } else {
10471 USTPUTC(CTLVAR, out);
10472 typeloc = out - (char *)stackblock();
10473 USTPUTC(VSNORMAL, out);
10474 subtype = VSNORMAL;
10475 if (c == '{') {
10476 c = pgetc();
10477 if (c == '#') {
10478 if ((c = pgetc()) == '}')
10479 c = '#';
10480 else
10481 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010482 }
Eric Andersenc470f442003-07-28 09:56:35 +000010483 else
10484 subtype = 0;
10485 }
10486 if (c > PEOA_OR_PEOF && is_name(c)) {
10487 do {
10488 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010489 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010490 } while (c > PEOA_OR_PEOF && is_in_name(c));
10491 } else if (is_digit(c)) {
10492 do {
10493 STPUTC(c, out);
10494 c = pgetc();
10495 } while (is_digit(c));
10496 }
10497 else if (is_special(c)) {
10498 USTPUTC(c, out);
10499 c = pgetc();
10500 }
10501 else
10502badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010503
Eric Andersenc470f442003-07-28 09:56:35 +000010504 STPUTC('=', out);
10505 flags = 0;
10506 if (subtype == 0) {
10507 switch (c) {
10508 case ':':
10509 flags = VSNUL;
10510 c = pgetc();
10511 /*FALLTHROUGH*/
10512 default:
10513 p = strchr(types, c);
10514 if (p == NULL)
10515 goto badsub;
10516 subtype = p - types + VSNORMAL;
10517 break;
10518 case '%':
10519 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010520 {
10521 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010522 subtype = c == '#' ? VSTRIMLEFT :
10523 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010524 c = pgetc();
10525 if (c == cc)
10526 subtype++;
10527 else
10528 pungetc();
10529 break;
10530 }
10531 }
Eric Andersenc470f442003-07-28 09:56:35 +000010532 } else {
10533 pungetc();
10534 }
10535 if (dblquote || arinest)
10536 flags |= VSQUOTE;
10537 *((char *)stackblock() + typeloc) = subtype | flags;
10538 if (subtype != VSNORMAL) {
10539 varnest++;
10540 if (dblquote || arinest) {
10541 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010542 }
10543 }
10544 }
Eric Andersenc470f442003-07-28 09:56:35 +000010545 goto parsesub_return;
10546}
Eric Andersencb57d552001-06-28 07:25:16 +000010547
10548
10549/*
10550 * Called to parse command substitutions. Newstyle is set if the command
10551 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10552 * list of commands (passed by reference), and savelen is the number of
10553 * characters on the top of the stack which must be preserved.
10554 */
10555
Eric Andersenc470f442003-07-28 09:56:35 +000010556parsebackq: {
10557 struct nodelist **nlpp;
10558 int savepbq;
10559 union node *n;
10560 char *volatile str;
10561 struct jmploc jmploc;
10562 struct jmploc *volatile savehandler;
10563 size_t savelen;
Eric Andersena68ea1c2006-01-30 22:48:39 +000010564 int saveprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010565#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010566 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010567#endif
10568
Eric Andersenc470f442003-07-28 09:56:35 +000010569 savepbq = parsebackquote;
10570 if (setjmp(jmploc.loc)) {
10571 if (str)
10572 ckfree(str);
10573 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010574 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010575 longjmp(handler->loc, 1);
10576 }
10577 INTOFF;
10578 str = NULL;
10579 savelen = out - (char *)stackblock();
10580 if (savelen > 0) {
10581 str = ckmalloc(savelen);
10582 memcpy(str, stackblock(), savelen);
10583 }
10584 savehandler = handler;
10585 handler = &jmploc;
10586 INTON;
10587 if (oldstyle) {
10588 /* We must read until the closing backquote, giving special
10589 treatment to some slashes, and then push the string and
10590 reread it as input, interpreting it normally. */
10591 char *pout;
10592 int pc;
10593 size_t psavelen;
10594 char *pstr;
10595
10596
10597 STARTSTACKSTR(pout);
10598 for (;;) {
10599 if (needprompt) {
10600 setprompt(2);
Eric Andersenc470f442003-07-28 09:56:35 +000010601 }
10602 switch (pc = pgetc()) {
10603 case '`':
10604 goto done;
10605
10606 case '\\':
10607 if ((pc = pgetc()) == '\n') {
10608 plinno++;
10609 if (doprompt)
10610 setprompt(2);
10611 /*
10612 * If eating a newline, avoid putting
10613 * the newline into the new character
10614 * stream (via the STPUTC after the
10615 * switch).
10616 */
10617 continue;
10618 }
10619 if (pc != '\\' && pc != '`' && pc != '$'
10620 && (!dblquote || pc != '"'))
10621 STPUTC('\\', pout);
10622 if (pc > PEOA_OR_PEOF) {
10623 break;
10624 }
10625 /* fall through */
10626
10627 case PEOF:
10628#ifdef CONFIG_ASH_ALIAS
10629 case PEOA:
10630#endif
10631 startlinno = plinno;
10632 synerror("EOF in backquote substitution");
10633
10634 case '\n':
10635 plinno++;
10636 needprompt = doprompt;
10637 break;
10638
10639 default:
10640 break;
10641 }
10642 STPUTC(pc, pout);
10643 }
10644done:
10645 STPUTC('\0', pout);
10646 psavelen = pout - (char *)stackblock();
10647 if (psavelen > 0) {
10648 pstr = grabstackstr(pout);
10649 setinputstring(pstr);
10650 }
10651 }
10652 nlpp = &bqlist;
10653 while (*nlpp)
10654 nlpp = &(*nlpp)->next;
10655 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10656 (*nlpp)->next = NULL;
10657 parsebackquote = oldstyle;
10658
10659 if (oldstyle) {
10660 saveprompt = doprompt;
10661 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010662 }
10663
Eric Andersenc470f442003-07-28 09:56:35 +000010664 n = list(2);
10665
10666 if (oldstyle)
10667 doprompt = saveprompt;
10668 else {
10669 if (readtoken() != TRP)
10670 synexpect(TRP);
10671 }
10672
10673 (*nlpp)->n = n;
10674 if (oldstyle) {
10675 /*
10676 * Start reading from old file again, ignoring any pushed back
10677 * tokens left from the backquote parsing
10678 */
10679 popfile();
10680 tokpushback = 0;
10681 }
10682 while (stackblocksize() <= savelen)
10683 growstackblock();
10684 STARTSTACKSTR(out);
10685 if (str) {
10686 memcpy(out, str, savelen);
10687 STADJUST(savelen, out);
10688 INTOFF;
10689 ckfree(str);
10690 str = NULL;
10691 INTON;
10692 }
10693 parsebackquote = savepbq;
10694 handler = savehandler;
10695 if (arinest || dblquote)
10696 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10697 else
10698 USTPUTC(CTLBACKQ, out);
10699 if (oldstyle)
10700 goto parsebackq_oldreturn;
10701 else
10702 goto parsebackq_newreturn;
10703}
10704
10705#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010706/*
10707 * Parse an arithmetic expansion (indicate start of one and set state)
10708 */
Eric Andersenc470f442003-07-28 09:56:35 +000010709parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010710
Eric Andersenc470f442003-07-28 09:56:35 +000010711 if (++arinest == 1) {
10712 prevsyntax = syntax;
10713 syntax = ARISYNTAX;
10714 USTPUTC(CTLARI, out);
10715 if (dblquote)
10716 USTPUTC('"',out);
10717 else
10718 USTPUTC(' ',out);
10719 } else {
10720 /*
10721 * we collapse embedded arithmetic expansion to
10722 * parenthesis, which should be equivalent
10723 */
10724 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010725 }
Eric Andersenc470f442003-07-28 09:56:35 +000010726 goto parsearith_return;
10727}
10728#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010729
Eric Andersenc470f442003-07-28 09:56:35 +000010730} /* end of readtoken */
10731
Eric Andersencb57d552001-06-28 07:25:16 +000010732
10733
Eric Andersencb57d552001-06-28 07:25:16 +000010734/*
10735 * Returns true if the text contains nothing to expand (no dollar signs
10736 * or backquotes).
10737 */
10738
Eric Andersenc470f442003-07-28 09:56:35 +000010739static int
10740noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010741{
Eric Andersencb57d552001-06-28 07:25:16 +000010742 char *p;
10743 char c;
10744
10745 p = text;
10746 while ((c = *p++) != '\0') {
10747 if (c == CTLQUOTEMARK)
10748 continue;
10749 if (c == CTLESC)
10750 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010751 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010752 return 0;
10753 }
10754 return 1;
10755}
10756
10757
10758/*
Eric Andersenc470f442003-07-28 09:56:35 +000010759 * Return of a legal variable name (a letter or underscore followed by zero or
10760 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010761 */
10762
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010763static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010764endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010765{
Eric Andersenc470f442003-07-28 09:56:35 +000010766 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010767
Eric Andersenc470f442003-07-28 09:56:35 +000010768 p = (char *) name;
10769 if (! is_name(*p))
10770 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010771 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010772 if (! is_in_name(*p))
10773 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010774 }
Eric Andersenc470f442003-07-28 09:56:35 +000010775 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010776}
10777
10778
10779/*
10780 * Called when an unexpected token is read during the parse. The argument
10781 * is the token that is expected, or -1 if more than one type of token can
10782 * occur at this point.
10783 */
10784
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010785static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010786{
10787 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010788 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010789
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010790 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10791 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010792 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010793 synerror(msg);
10794 /* NOTREACHED */
10795}
10796
Eric Andersenc470f442003-07-28 09:56:35 +000010797static void
10798synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010799{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010800 sh_error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010801 /* NOTREACHED */
10802}
10803
Eric Andersencb57d552001-06-28 07:25:16 +000010804
10805/*
10806 * called by editline -- any expansions to the prompt
10807 * should be added here.
10808 */
Eric Andersenc470f442003-07-28 09:56:35 +000010809
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010810#ifdef CONFIG_ASH_EXPAND_PRMT
10811static const char *
10812expandstr(const char *ps)
10813{
10814 union node n;
10815
10816 /* XXX Fix (char *) cast. */
10817 setinputstring((char *)ps);
10818 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10819 popfile();
10820
10821 n.narg.type = NARG;
10822 n.narg.next = NULL;
10823 n.narg.text = wordtext;
10824 n.narg.backquote = backquotelist;
10825
10826 expandarg(&n, NULL, 0);
10827 return stackblock();
10828}
10829#endif
10830
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010831static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010832{
Eric Andersenc470f442003-07-28 09:56:35 +000010833 const char *prompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010834#ifdef CONFIG_ASH_EXPAND_PRMT
10835 struct stackmark smark;
10836#endif
10837
10838 needprompt = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010839
10840 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010841 case 1:
10842 prompt = ps1val();
10843 break;
10844 case 2:
10845 prompt = ps2val();
10846 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010847 default: /* 0 */
10848 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010849 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010850#ifdef CONFIG_ASH_EXPAND_PRMT
10851 setstackmark(&smark);
10852 stalloc(stackblocksize());
10853#endif
10854 putprompt(expandstr(prompt));
10855#ifdef CONFIG_ASH_EXPAND_PRMT
10856 popstackmark(&smark);
10857#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010858}
10859
Eric Andersencb57d552001-06-28 07:25:16 +000010860
Eric Andersenc470f442003-07-28 09:56:35 +000010861static const char *const *findkwd(const char *s)
10862{
10863 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010864 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010865 sizeof(const char *), pstrcmp);
10866}
10867
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010868/* redir.c */
Eric Andersenc470f442003-07-28 09:56:35 +000010869
Eric Andersencb57d552001-06-28 07:25:16 +000010870/*
10871 * Code for dealing with input/output redirection.
10872 */
10873
Eric Andersenc470f442003-07-28 09:56:35 +000010874#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010875#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010876# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010877#else
10878# define PIPESIZE PIPE_BUF
10879#endif
10880
Eric Andersen62483552001-07-10 06:09:16 +000010881/*
10882 * Open a file in noclobber mode.
10883 * The code was copied from bash.
10884 */
Rob Landley88621d72006-08-29 19:41:06 +000010885static int noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010886{
10887 int r, fd;
10888 struct stat finfo, finfo2;
10889
10890 /*
10891 * If the file exists and is a regular file, return an error
10892 * immediately.
10893 */
10894 r = stat(fname, &finfo);
10895 if (r == 0 && S_ISREG(finfo.st_mode)) {
10896 errno = EEXIST;
10897 return -1;
10898 }
10899
10900 /*
10901 * If the file was not present (r != 0), make sure we open it
10902 * exclusively so that if it is created before we open it, our open
10903 * will fail. Make sure that we do not truncate an existing file.
10904 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10905 * file was not a regular file, we leave O_EXCL off.
10906 */
10907 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010908 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10909 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010910
10911 /* If the open failed, return the file descriptor right away. */
10912 if (fd < 0)
10913 return fd;
10914
10915 /*
10916 * OK, the open succeeded, but the file may have been changed from a
10917 * non-regular file to a regular file between the stat and the open.
10918 * We are assuming that the O_EXCL open handles the case where FILENAME
10919 * did not exist and is symlinked to an existing file between the stat
10920 * and open.
10921 */
10922
10923 /*
10924 * If we can open it and fstat the file descriptor, and neither check
10925 * revealed that it was a regular file, and the file has not been
10926 * replaced, return the file descriptor.
10927 */
Eric Andersenc470f442003-07-28 09:56:35 +000010928 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10929 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010930 return fd;
10931
10932 /* The file has been replaced. badness. */
10933 close(fd);
10934 errno = EEXIST;
10935 return -1;
10936}
Eric Andersencb57d552001-06-28 07:25:16 +000010937
10938/*
Eric Andersen62483552001-07-10 06:09:16 +000010939 * Handle here documents. Normally we fork off a process to write the
10940 * data to a pipe. If the document is short, we can stuff the data in
10941 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010942 */
10943
Rob Landley88621d72006-08-29 19:41:06 +000010944static int openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010945{
10946 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010947 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010948
Eric Andersen62483552001-07-10 06:09:16 +000010949 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010950 sh_error("Pipe call failed");
Eric Andersen62483552001-07-10 06:09:16 +000010951 if (redir->type == NHERE) {
10952 len = strlen(redir->nhere.doc->narg.text);
10953 if (len <= PIPESIZE) {
Rob Landley53437472006-07-16 08:14:35 +000010954 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010955 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010956 }
Eric Andersencb57d552001-06-28 07:25:16 +000010957 }
Eric Andersenc470f442003-07-28 09:56:35 +000010958 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010959 close(pip[0]);
10960 signal(SIGINT, SIG_IGN);
10961 signal(SIGQUIT, SIG_IGN);
10962 signal(SIGHUP, SIG_IGN);
10963#ifdef SIGTSTP
10964 signal(SIGTSTP, SIG_IGN);
10965#endif
10966 signal(SIGPIPE, SIG_DFL);
10967 if (redir->type == NHERE)
Rob Landley53437472006-07-16 08:14:35 +000010968 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010969 else
10970 expandhere(redir->nhere.doc, pip[1]);
10971 _exit(0);
10972 }
Eric Andersenc470f442003-07-28 09:56:35 +000010973out:
Eric Andersen62483552001-07-10 06:09:16 +000010974 close(pip[1]);
10975 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010976}
10977
Eric Andersenc470f442003-07-28 09:56:35 +000010978static int
10979openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010980{
Eric Andersencb57d552001-06-28 07:25:16 +000010981 char *fname;
10982 int f;
10983
10984 switch (redir->nfile.type) {
10985 case NFROM:
10986 fname = redir->nfile.expfname;
10987 if ((f = open(fname, O_RDONLY)) < 0)
10988 goto eopen;
10989 break;
10990 case NFROMTO:
10991 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010992 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010993 goto ecreate;
10994 break;
10995 case NTO:
10996 /* Take care of noclobber mode. */
10997 if (Cflag) {
10998 fname = redir->nfile.expfname;
10999 if ((f = noclobberopen(fname)) < 0)
11000 goto ecreate;
11001 break;
11002 }
Eric Andersenc470f442003-07-28 09:56:35 +000011003 /* FALLTHROUGH */
11004 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011005 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011006 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011007 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011008 break;
11009 case NAPPEND:
11010 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011011 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011012 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011013 break;
11014 default:
11015#ifdef DEBUG
11016 abort();
11017#endif
11018 /* Fall through to eliminate warning. */
11019 case NTOFD:
11020 case NFROMFD:
11021 f = -1;
11022 break;
11023 case NHERE:
11024 case NXHERE:
11025 f = openhere(redir);
11026 break;
11027 }
11028
11029 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011030ecreate:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011031 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011032eopen:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011033 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
Eric Andersencb57d552001-06-28 07:25:16 +000011034}
11035
Rob Landley88621d72006-08-29 19:41:06 +000011036static void dupredirect(union node *redir, int f)
Eric Andersenc470f442003-07-28 09:56:35 +000011037{
11038 int fd = redir->nfile.fd;
11039
11040 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11041 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11042 copyfd(redir->ndup.dupfd, fd);
11043 }
11044 return;
11045 }
11046
11047 if (f != fd) {
11048 copyfd(f, fd);
11049 close(f);
11050 }
11051 return;
11052}
Eric Andersencb57d552001-06-28 07:25:16 +000011053
Eric Andersen62483552001-07-10 06:09:16 +000011054/*
11055 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11056 * old file descriptors are stashed away so that the redirection can be
11057 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11058 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011059 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011060 */
11061
Eric Andersenc470f442003-07-28 09:56:35 +000011062static void
11063redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011064{
11065 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011066 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011067 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011068 int fd;
11069 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011070 int *p;
11071 nullredirs++;
11072 if (!redir) {
11073 return;
Eric Andersen62483552001-07-10 06:09:16 +000011074 }
Eric Andersenc470f442003-07-28 09:56:35 +000011075 sv = NULL;
11076 INTOFF;
11077 if (flags & REDIR_PUSH) {
11078 struct redirtab *q;
11079 q = ckmalloc(sizeof (struct redirtab));
11080 q->next = redirlist;
11081 redirlist = q;
11082 q->nullredirs = nullredirs - 1;
11083 for (i = 0 ; i < 10 ; i++)
11084 q->renamed[i] = EMPTY;
11085 nullredirs = 0;
11086 sv = q;
11087 }
11088 n = redir;
11089 do {
Eric Andersen62483552001-07-10 06:09:16 +000011090 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011091 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011092 n->ndup.dupfd == fd)
11093 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011094
Eric Andersen62483552001-07-10 06:09:16 +000011095 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011096 if (fd == newfd)
11097 continue;
11098 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11099 i = fcntl(fd, F_DUPFD, 10);
11100
11101 if (i == -1) {
11102 i = errno;
11103 if (i != EBADF) {
11104 close(newfd);
11105 errno = i;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011106 sh_error("%d: %m", fd);
Eric Andersen62483552001-07-10 06:09:16 +000011107 /* NOTREACHED */
11108 }
Eric Andersenc470f442003-07-28 09:56:35 +000011109 } else {
11110 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011111 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011112 }
Eric Andersenc470f442003-07-28 09:56:35 +000011113 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011114 close(fd);
11115 }
Eric Andersenc470f442003-07-28 09:56:35 +000011116 dupredirect(n, newfd);
11117 } while ((n = n->nfile.next));
11118 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011119 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11120 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011121}
11122
11123
Eric Andersencb57d552001-06-28 07:25:16 +000011124/*
11125 * Undo the effects of the last redirection.
11126 */
11127
Eric Andersenc470f442003-07-28 09:56:35 +000011128void
11129popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011130{
Eric Andersenc470f442003-07-28 09:56:35 +000011131 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011132 int i;
11133
Eric Andersenc470f442003-07-28 09:56:35 +000011134 if (--nullredirs >= 0)
11135 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011136 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011137 rp = redirlist;
11138 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011139 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011140 if (!drop) {
11141 close(i);
11142 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011143 }
Eric Andersenc470f442003-07-28 09:56:35 +000011144 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011145 }
11146 }
11147 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011148 nullredirs = rp->nullredirs;
11149 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011150 INTON;
11151}
11152
11153/*
Eric Andersenc470f442003-07-28 09:56:35 +000011154 * Undo all redirections. Called on error or interrupt.
11155 */
11156
11157/*
Eric Andersencb57d552001-06-28 07:25:16 +000011158 * Discard all saved file descriptors.
11159 */
11160
Eric Andersenc470f442003-07-28 09:56:35 +000011161void
11162clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011163{
Eric Andersenc470f442003-07-28 09:56:35 +000011164 for (;;) {
11165 nullredirs = 0;
11166 if (!redirlist)
11167 break;
11168 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011169 }
Eric Andersencb57d552001-06-28 07:25:16 +000011170}
11171
11172
Eric Andersencb57d552001-06-28 07:25:16 +000011173/*
11174 * Copy a file descriptor to be >= to. Returns -1
11175 * if the source file descriptor is closed, EMPTY if there are no unused
11176 * file descriptors left.
11177 */
11178
Eric Andersenc470f442003-07-28 09:56:35 +000011179int
11180copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011181{
11182 int newfd;
11183
11184 newfd = fcntl(from, F_DUPFD, to);
11185 if (newfd < 0) {
11186 if (errno == EMFILE)
11187 return EMPTY;
11188 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011189 sh_error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011190 }
11191 return newfd;
11192}
11193
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011194
Eric Andersenc470f442003-07-28 09:56:35 +000011195int
11196redirectsafe(union node *redir, int flags)
11197{
11198 int err;
11199 volatile int saveint;
11200 struct jmploc *volatile savehandler = handler;
11201 struct jmploc jmploc;
11202
11203 SAVEINT(saveint);
11204 if (!(err = setjmp(jmploc.loc) * 2)) {
11205 handler = &jmploc;
11206 redirect(redir, flags);
11207 }
11208 handler = savehandler;
11209 if (err && exception != EXERROR)
11210 longjmp(handler->loc, 1);
11211 RESTOREINT(saveint);
11212 return err;
11213}
11214
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011215/* show.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011216
11217#ifdef DEBUG
11218static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011219static void shcmd(union node *, FILE *);
11220static void sharg(union node *, FILE *);
11221static void indent(int, char *, FILE *);
11222static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011223
11224
Eric Andersenc470f442003-07-28 09:56:35 +000011225void
11226showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011227{
11228 trputs("showtree called\n");
11229 shtree(n, 1, NULL, stdout);
11230}
Eric Andersencb57d552001-06-28 07:25:16 +000011231
Eric Andersenc470f442003-07-28 09:56:35 +000011232
11233static void
11234shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011235{
11236 struct nodelist *lp;
11237 const char *s;
11238
11239 if (n == NULL)
11240 return;
11241
11242 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011243 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011244 case NSEMI:
11245 s = "; ";
11246 goto binop;
11247 case NAND:
11248 s = " && ";
11249 goto binop;
11250 case NOR:
11251 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011252binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011253 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011254 /* if (ind < 0) */
11255 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011256 shtree(n->nbinary.ch2, ind, NULL, fp);
11257 break;
11258 case NCMD:
11259 shcmd(n, fp);
11260 if (ind >= 0)
11261 putc('\n', fp);
11262 break;
11263 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011264 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011265 shcmd(lp->n, fp);
11266 if (lp->next)
11267 fputs(" | ", fp);
11268 }
11269 if (n->npipe.backgnd)
11270 fputs(" &", fp);
11271 if (ind >= 0)
11272 putc('\n', fp);
11273 break;
11274 default:
11275 fprintf(fp, "<node type %d>", n->type);
11276 if (ind >= 0)
11277 putc('\n', fp);
11278 break;
11279 }
11280}
11281
11282
Eric Andersenc470f442003-07-28 09:56:35 +000011283static void
11284shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011285{
11286 union node *np;
11287 int first;
11288 const char *s;
11289 int dftfd;
11290
11291 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011292 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11293 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011294 putchar(' ');
11295 sharg(np, fp);
11296 first = 0;
11297 }
Eric Andersenc470f442003-07-28 09:56:35 +000011298 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11299 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011300 putchar(' ');
11301 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011302 case NTO: s = ">"; dftfd = 1; break;
11303 case NCLOBBER: s = ">|"; dftfd = 1; break;
11304 case NAPPEND: s = ">>"; dftfd = 1; break;
11305 case NTOFD: s = ">&"; dftfd = 1; break;
11306 case NFROM: s = "<"; dftfd = 0; break;
11307 case NFROMFD: s = "<&"; dftfd = 0; break;
11308 case NFROMTO: s = "<>"; dftfd = 0; break;
11309 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011310 }
11311 if (np->nfile.fd != dftfd)
11312 fprintf(fp, "%d", np->nfile.fd);
11313 fputs(s, fp);
11314 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11315 fprintf(fp, "%d", np->ndup.dupfd);
11316 } else {
11317 sharg(np->nfile.fname, fp);
11318 }
11319 first = 0;
11320 }
11321}
11322
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011323
Eric Andersenc470f442003-07-28 09:56:35 +000011324
11325static void
11326sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011327{
Eric Andersencb57d552001-06-28 07:25:16 +000011328 char *p;
11329 struct nodelist *bqlist;
11330 int subtype;
11331
11332 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011333 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011334 abort();
11335 }
11336 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011337 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011338 switch (*p) {
11339 case CTLESC:
11340 putc(*++p, fp);
11341 break;
11342 case CTLVAR:
11343 putc('$', fp);
11344 putc('{', fp);
11345 subtype = *++p;
11346 if (subtype == VSLENGTH)
11347 putc('#', fp);
11348
11349 while (*p != '=')
11350 putc(*p++, fp);
11351
11352 if (subtype & VSNUL)
11353 putc(':', fp);
11354
11355 switch (subtype & VSTYPE) {
11356 case VSNORMAL:
11357 putc('}', fp);
11358 break;
11359 case VSMINUS:
11360 putc('-', fp);
11361 break;
11362 case VSPLUS:
11363 putc('+', fp);
11364 break;
11365 case VSQUESTION:
11366 putc('?', fp);
11367 break;
11368 case VSASSIGN:
11369 putc('=', fp);
11370 break;
11371 case VSTRIMLEFT:
11372 putc('#', fp);
11373 break;
11374 case VSTRIMLEFTMAX:
11375 putc('#', fp);
11376 putc('#', fp);
11377 break;
11378 case VSTRIMRIGHT:
11379 putc('%', fp);
11380 break;
11381 case VSTRIMRIGHTMAX:
11382 putc('%', fp);
11383 putc('%', fp);
11384 break;
11385 case VSLENGTH:
11386 break;
11387 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011388 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011389 }
11390 break;
11391 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011392 putc('}', fp);
11393 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011394 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011395 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011396 putc('$', fp);
11397 putc('(', fp);
11398 shtree(bqlist->n, -1, NULL, fp);
11399 putc(')', fp);
11400 break;
11401 default:
11402 putc(*p, fp);
11403 break;
11404 }
11405 }
11406}
11407
11408
Eric Andersenc470f442003-07-28 09:56:35 +000011409static void
11410indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011411{
11412 int i;
11413
Eric Andersenc470f442003-07-28 09:56:35 +000011414 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011415 if (pfx && i == amount - 1)
11416 fputs(pfx, fp);
11417 putc('\t', fp);
11418 }
11419}
Eric Andersencb57d552001-06-28 07:25:16 +000011420
Eric Andersenc470f442003-07-28 09:56:35 +000011421
11422
11423/*
11424 * Debugging stuff.
11425 */
11426
11427
Eric Andersencb57d552001-06-28 07:25:16 +000011428FILE *tracefile;
11429
Eric Andersencb57d552001-06-28 07:25:16 +000011430
Eric Andersenc470f442003-07-28 09:56:35 +000011431void
11432trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011433{
Eric Andersenc470f442003-07-28 09:56:35 +000011434 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011435 return;
11436 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011437}
11438
Eric Andersenc470f442003-07-28 09:56:35 +000011439void
11440trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011441{
11442 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011443
Eric Andersenc470f442003-07-28 09:56:35 +000011444 if (debug != 1)
11445 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011446 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011447 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011448 va_end(va);
11449}
11450
Eric Andersenc470f442003-07-28 09:56:35 +000011451void
11452tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011453{
Eric Andersenc470f442003-07-28 09:56:35 +000011454 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011455 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011456 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011457}
11458
11459
Eric Andersenc470f442003-07-28 09:56:35 +000011460void
11461trputs(const char *s)
11462{
11463 if (debug != 1)
11464 return;
11465 fputs(s, tracefile);
11466}
11467
11468
11469static void
11470trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011471{
11472 char *p;
11473 char c;
11474
Eric Andersenc470f442003-07-28 09:56:35 +000011475 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011476 return;
11477 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011478 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011479 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011480 case '\n': c = 'n'; goto backslash;
11481 case '\t': c = 't'; goto backslash;
11482 case '\r': c = 'r'; goto backslash;
11483 case '"': c = '"'; goto backslash;
11484 case '\\': c = '\\'; goto backslash;
11485 case CTLESC: c = 'e'; goto backslash;
11486 case CTLVAR: c = 'v'; goto backslash;
11487 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11488 case CTLBACKQ: c = 'q'; goto backslash;
11489 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11490backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011491 putc(c, tracefile);
11492 break;
11493 default:
11494 if (*p >= ' ' && *p <= '~')
11495 putc(*p, tracefile);
11496 else {
11497 putc('\\', tracefile);
11498 putc(*p >> 6 & 03, tracefile);
11499 putc(*p >> 3 & 07, tracefile);
11500 putc(*p & 07, tracefile);
11501 }
11502 break;
11503 }
11504 }
11505 putc('"', tracefile);
11506}
11507
11508
Eric Andersenc470f442003-07-28 09:56:35 +000011509void
11510trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011511{
Eric Andersenc470f442003-07-28 09:56:35 +000011512 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011513 return;
11514 while (*ap) {
11515 trstring(*ap++);
11516 if (*ap)
11517 putc(' ', tracefile);
11518 else
11519 putc('\n', tracefile);
11520 }
Eric Andersencb57d552001-06-28 07:25:16 +000011521}
11522
11523
Eric Andersenc470f442003-07-28 09:56:35 +000011524void
11525opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011526{
Eric Andersencb57d552001-06-28 07:25:16 +000011527 char s[100];
11528#ifdef O_APPEND
11529 int flags;
11530#endif
11531
Eric Andersenc470f442003-07-28 09:56:35 +000011532 if (debug != 1) {
11533 if (tracefile)
11534 fflush(tracefile);
11535 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011536 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011537 }
Eric Andersenc470f442003-07-28 09:56:35 +000011538 scopy("./trace", s);
11539 if (tracefile) {
11540 if (!freopen(s, "a", tracefile)) {
11541 fprintf(stderr, "Can't re-open %s\n", s);
11542 debug = 0;
11543 return;
11544 }
11545 } else {
11546 if ((tracefile = fopen(s, "a")) == NULL) {
11547 fprintf(stderr, "Can't open %s\n", s);
11548 debug = 0;
11549 return;
11550 }
11551 }
Eric Andersencb57d552001-06-28 07:25:16 +000011552#ifdef O_APPEND
11553 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11554 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11555#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011556 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011557 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011558}
Eric Andersenc470f442003-07-28 09:56:35 +000011559#endif /* DEBUG */
11560
11561
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011562/* trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011563
11564/*
11565 * Sigmode records the current value of the signal handlers for the various
11566 * modes. A value of zero means that the current handler is not known.
11567 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11568 */
11569
11570#define S_DFL 1 /* default signal handling (SIG_DFL) */
11571#define S_CATCH 2 /* signal is caught */
11572#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11573#define S_HARD_IGN 4 /* signal is ignored permenantly */
11574#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11575
Eric Andersencb57d552001-06-28 07:25:16 +000011576
11577
11578/*
Eric Andersencb57d552001-06-28 07:25:16 +000011579 * The trap builtin.
11580 */
11581
Eric Andersenc470f442003-07-28 09:56:35 +000011582int
11583trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011584{
11585 char *action;
11586 char **ap;
11587 int signo;
11588
Eric Andersenc470f442003-07-28 09:56:35 +000011589 nextopt(nullstr);
11590 ap = argptr;
11591 if (!*ap) {
11592 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011593 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011594 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011595
Rob Landleyc9c1a412006-07-12 19:17:55 +000011596 sn = get_signame(signo);
Eric Andersenc470f442003-07-28 09:56:35 +000011597 out1fmt("trap -- %s %s\n",
11598 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011599 }
11600 }
11601 return 0;
11602 }
Eric Andersenc470f442003-07-28 09:56:35 +000011603 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011604 action = NULL;
11605 else
11606 action = *ap++;
11607 while (*ap) {
Rob Landleyc9c1a412006-07-12 19:17:55 +000011608 if ((signo = get_signum(*ap)) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011609 sh_error("%s: bad trap", *ap);
Eric Andersencb57d552001-06-28 07:25:16 +000011610 INTOFF;
11611 if (action) {
11612 if (action[0] == '-' && action[1] == '\0')
11613 action = NULL;
11614 else
Eric Andersenc470f442003-07-28 09:56:35 +000011615 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011616 }
Eric Andersenc470f442003-07-28 09:56:35 +000011617 if (trap[signo])
11618 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011619 trap[signo] = action;
11620 if (signo != 0)
11621 setsignal(signo);
11622 INTON;
11623 ap++;
11624 }
11625 return 0;
11626}
11627
11628
Eric Andersenc470f442003-07-28 09:56:35 +000011629/*
11630 * Clear traps on a fork.
11631 */
11632
11633void
11634clear_traps(void)
11635{
11636 char **tp;
11637
11638 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11639 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11640 INTOFF;
11641 ckfree(*tp);
11642 *tp = NULL;
11643 if (tp != &trap[0])
11644 setsignal(tp - trap);
11645 INTON;
11646 }
11647 }
11648}
11649
11650
Eric Andersencb57d552001-06-28 07:25:16 +000011651/*
11652 * Set the signal handler for the specified signal. The routine figures
11653 * out what it should be set to.
11654 */
11655
Eric Andersenc470f442003-07-28 09:56:35 +000011656void
11657setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011658{
11659 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011660 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011661 struct sigaction act;
11662
11663 if ((t = trap[signo]) == NULL)
11664 action = S_DFL;
11665 else if (*t != '\0')
11666 action = S_CATCH;
11667 else
11668 action = S_IGN;
11669 if (rootshell && action == S_DFL) {
11670 switch (signo) {
11671 case SIGINT:
11672 if (iflag || minusc || sflag == 0)
11673 action = S_CATCH;
11674 break;
11675 case SIGQUIT:
11676#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011677 if (debug)
11678 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011679#endif
11680 /* FALLTHROUGH */
11681 case SIGTERM:
11682 if (iflag)
11683 action = S_IGN;
11684 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011685#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011686 case SIGTSTP:
11687 case SIGTTOU:
11688 if (mflag)
11689 action = S_IGN;
11690 break;
11691#endif
11692 }
11693 }
11694
11695 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011696 tsig = *t;
11697 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011698 /*
11699 * current setting unknown
11700 */
11701 if (sigaction(signo, 0, &act) == -1) {
11702 /*
11703 * Pretend it worked; maybe we should give a warning
11704 * here, but other shells don't. We don't alter
11705 * sigmode, so that we retry every time.
11706 */
11707 return;
11708 }
11709 if (act.sa_handler == SIG_IGN) {
11710 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011711 signo == SIGTTIN || signo == SIGTTOU)) {
11712 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011713 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011714 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011715 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011716 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011717 }
11718 }
Eric Andersenc470f442003-07-28 09:56:35 +000011719 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011720 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011721 switch (action) {
11722 case S_CATCH:
11723 act.sa_handler = onsig;
11724 break;
11725 case S_IGN:
11726 act.sa_handler = SIG_IGN;
11727 break;
11728 default:
11729 act.sa_handler = SIG_DFL;
11730 }
Eric Andersencb57d552001-06-28 07:25:16 +000011731 *t = action;
11732 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011733 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011734 sigaction(signo, &act, 0);
11735}
11736
11737/*
11738 * Ignore a signal.
11739 */
11740
Eric Andersenc470f442003-07-28 09:56:35 +000011741void
11742ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011743{
11744 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11745 signal(signo, SIG_IGN);
11746 }
11747 sigmode[signo - 1] = S_HARD_IGN;
11748}
11749
11750
Eric Andersencb57d552001-06-28 07:25:16 +000011751/*
11752 * Signal handler.
11753 */
11754
Eric Andersenc470f442003-07-28 09:56:35 +000011755void
11756onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011757{
Eric Andersencb57d552001-06-28 07:25:16 +000011758 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011759 pendingsigs = signo;
11760
11761 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11762 if (!suppressint)
11763 onint();
11764 intpending = 1;
11765 }
Eric Andersencb57d552001-06-28 07:25:16 +000011766}
11767
11768
Eric Andersencb57d552001-06-28 07:25:16 +000011769/*
11770 * Called to execute a trap. Perhaps we should avoid entering new trap
11771 * handlers while we are executing a trap handler.
11772 */
11773
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011774int
Eric Andersenc470f442003-07-28 09:56:35 +000011775dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011776{
Eric Andersenc470f442003-07-28 09:56:35 +000011777 char *p;
11778 char *q;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011779 int i;
Eric Andersencb57d552001-06-28 07:25:16 +000011780 int savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011781 int skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011782
Eric Andersenc470f442003-07-28 09:56:35 +000011783 savestatus = exitstatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011784 pendingsigs = 0;
11785 xbarrier();
11786
11787 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11788 if (!*q)
11789 continue;
11790 *q = 0;
11791
11792 p = trap[i + 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011793 if (!p)
11794 continue;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011795 skip = evalstring(p, SKIPEVAL);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011796 exitstatus = savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011797 if (skip)
11798 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011799 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011800
11801 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +000011802}
11803
Eric Andersenc470f442003-07-28 09:56:35 +000011804
Eric Andersenc470f442003-07-28 09:56:35 +000011805/*
11806 * Controls whether the shell is interactive or not.
11807 */
11808
Eric Andersenc470f442003-07-28 09:56:35 +000011809void
11810setinteractive(int on)
11811{
11812 static int is_interactive;
11813
11814 if (++on == is_interactive)
11815 return;
11816 is_interactive = on;
11817 setsignal(SIGINT);
11818 setsignal(SIGQUIT);
11819 setsignal(SIGTERM);
11820#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11821 if(is_interactive > 1) {
11822 /* Looks like they want an interactive shell */
11823 static int do_banner;
11824
11825 if(!do_banner) {
11826 out1fmt(
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +000011827 "\n\n%s Built-in shell (ash)\n"
11828 "Enter 'help' for a list of built-in commands.\n\n",
11829 BB_BANNER);
Eric Andersenc470f442003-07-28 09:56:35 +000011830 do_banner++;
11831 }
11832 }
11833#endif
11834}
11835
11836
11837#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11838/*** List the available builtins ***/
11839
11840static int helpcmd(int argc, char **argv)
11841{
11842 int col, i;
11843
11844 out1fmt("\nBuilt-in commands:\n-------------------\n");
11845 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11846 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11847 builtincmd[i].name + 1);
11848 if (col > 60) {
11849 out1fmt("\n");
11850 col = 0;
11851 }
11852 }
11853#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11854 {
11855 extern const struct BB_applet applets[];
11856 extern const size_t NUM_APPLETS;
11857
11858 for (i = 0; i < NUM_APPLETS; i++) {
11859
11860 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11861 if (col > 60) {
11862 out1fmt("\n");
11863 col = 0;
11864 }
11865 }
11866 }
11867#endif
11868 out1fmt("\n\n");
11869 return EXIT_SUCCESS;
11870}
11871#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11872
Eric Andersencb57d552001-06-28 07:25:16 +000011873/*
11874 * Called to exit the shell.
11875 */
11876
Eric Andersenc470f442003-07-28 09:56:35 +000011877void
11878exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011879{
Eric Andersenc470f442003-07-28 09:56:35 +000011880 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011881 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011882 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011883
Eric Andersenc470f442003-07-28 09:56:35 +000011884 status = exitstatus;
11885 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011886 if (setjmp(loc.loc)) {
11887 if (exception == EXEXIT)
11888 _exit(exitstatus);
Eric Andersenc470f442003-07-28 09:56:35 +000011889 goto out;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011890 }
Eric Andersenc470f442003-07-28 09:56:35 +000011891 handler = &loc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011892 if ((p = trap[0])) {
Eric Andersencb57d552001-06-28 07:25:16 +000011893 trap[0] = NULL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011894 evalstring(p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011895 }
Eric Andersencb57d552001-06-28 07:25:16 +000011896 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011897 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011898#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11899 if (iflag && rootshell) {
11900 const char *hp = lookupvar("HISTFILE");
11901
11902 if(hp != NULL )
11903 save_history ( hp );
11904 }
11905#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011906out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011907 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011908 /* NOTREACHED */
11909}
11910
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011911/* var.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011912
11913static struct var *vartab[VTABSIZE];
11914
11915static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011916static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011917
11918/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011919 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011920 */
11921
Eric Andersenc470f442003-07-28 09:56:35 +000011922
11923#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011924/*
Eric Andersenc470f442003-07-28 09:56:35 +000011925 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011926 */
11927
Eric Andersenc470f442003-07-28 09:56:35 +000011928int
11929setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011930{
Eric Andersenc470f442003-07-28 09:56:35 +000011931 int err;
11932 volatile int saveint;
11933 struct jmploc *volatile savehandler = handler;
11934 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011935
Eric Andersenc470f442003-07-28 09:56:35 +000011936 SAVEINT(saveint);
11937 if (setjmp(jmploc.loc))
11938 err = 1;
11939 else {
11940 handler = &jmploc;
11941 setvar(name, val, flags);
11942 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011943 }
Eric Andersenc470f442003-07-28 09:56:35 +000011944 handler = savehandler;
11945 RESTOREINT(saveint);
11946 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011947}
Eric Andersenc470f442003-07-28 09:56:35 +000011948#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011949
11950/*
11951 * Set the value of a variable. The flags argument is ored with the
11952 * flags of the variable. If val is NULL, the variable is unset.
11953 */
11954
Eric Andersenc470f442003-07-28 09:56:35 +000011955static void
11956setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011957{
Eric Andersenc470f442003-07-28 09:56:35 +000011958 char *p, *q;
11959 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011960 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011961 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011962
Eric Andersenc470f442003-07-28 09:56:35 +000011963 q = endofname(name);
11964 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011965 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011966 if (!namelen || p != q)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011967 sh_error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011968 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011969 if (val == NULL) {
11970 flags |= VUNSET;
11971 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011972 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011973 }
11974 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011975 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
Paul Fox8de331d2005-07-21 12:03:05 +000011976 if (val) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011977 *p++ = '=';
Eric Andersenc470f442003-07-28 09:56:35 +000011978 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011979 }
Eric Andersenc470f442003-07-28 09:56:35 +000011980 *p = '\0';
11981 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011982 INTON;
11983}
11984
11985
Eric Andersencb57d552001-06-28 07:25:16 +000011986/*
11987 * Same as setvar except that the variable and value are passed in
11988 * the first argument as name=value. Since the first argument will
11989 * be actually stored in the table, it should not be a string that
11990 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000011991 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000011992 */
11993
Eric Andersenc470f442003-07-28 09:56:35 +000011994void
11995setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011996{
11997 struct var *vp, **vpp;
11998
11999 vpp = hashvar(s);
12000 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012001 vp = *findvar(vpp, s);
12002 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012003 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12004 const char *n;
12005
Eric Andersenc470f442003-07-28 09:56:35 +000012006 if (flags & VNOSAVE)
12007 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012008 n = vp->text;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012009 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012010 }
Eric Andersenc470f442003-07-28 09:56:35 +000012011
12012 if (flags & VNOSET)
12013 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012014
12015 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012016 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012017
Eric Andersenc470f442003-07-28 09:56:35 +000012018 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12019 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012020
Eric Andersenc470f442003-07-28 09:56:35 +000012021 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12022 } else {
12023 if (flags & VNOSET)
12024 return;
12025 /* not found */
12026 vp = ckmalloc(sizeof (*vp));
12027 vp->next = *vpp;
12028 vp->func = NULL;
12029 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012030 }
Eric Andersenc470f442003-07-28 09:56:35 +000012031 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12032 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012033 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012034 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012035}
12036
12037
Eric Andersencb57d552001-06-28 07:25:16 +000012038/*
12039 * Process a linked list of variable assignments.
12040 */
12041
Eric Andersenc470f442003-07-28 09:56:35 +000012042static void
12043listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012044{
Eric Andersenc470f442003-07-28 09:56:35 +000012045 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012046
Eric Andersenc470f442003-07-28 09:56:35 +000012047 if (!lp)
12048 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012049 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012050 do {
12051 setvareq(lp->text, flags);
12052 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012053 INTON;
12054}
12055
12056
Eric Andersencb57d552001-06-28 07:25:16 +000012057/*
12058 * Find the value of a variable. Returns NULL if not set.
12059 */
12060
Eric Andersenc470f442003-07-28 09:56:35 +000012061static char *
12062lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012063{
Eric Andersencb57d552001-06-28 07:25:16 +000012064 struct var *v;
12065
Eric Andersen16767e22004-03-16 05:14:10 +000012066 if ((v = *findvar(hashvar(name), name))) {
12067#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012068 /*
12069 * Dynamic variables are implemented roughly the same way they are
12070 * in bash. Namely, they're "special" so long as they aren't unset.
12071 * As soon as they're unset, they're no longer dynamic, and dynamic
12072 * lookup will no longer happen at that point. -- PFM.
12073 */
Eric Andersen16767e22004-03-16 05:14:10 +000012074 if((v->flags & VDYNAMIC))
12075 (*v->func)(NULL);
12076#endif
12077 if(!(v->flags & VUNSET))
12078 return strchrnul(v->text, '=') + 1;
12079 }
Eric Andersenef02f822004-03-11 13:34:24 +000012080
Eric Andersencb57d552001-06-28 07:25:16 +000012081 return NULL;
12082}
12083
12084
Eric Andersencb57d552001-06-28 07:25:16 +000012085/*
12086 * Search the environment of a builtin command.
12087 */
12088
Eric Andersenc470f442003-07-28 09:56:35 +000012089static char *
12090bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012091{
Eric Andersenc470f442003-07-28 09:56:35 +000012092 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012093
Eric Andersenc470f442003-07-28 09:56:35 +000012094 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012095 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012096 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012097 }
12098 return lookupvar(name);
12099}
12100
12101
Eric Andersencb57d552001-06-28 07:25:16 +000012102/*
Eric Andersenc470f442003-07-28 09:56:35 +000012103 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012104 */
12105
Eric Andersenc470f442003-07-28 09:56:35 +000012106static char **
12107listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012108{
Eric Andersencb57d552001-06-28 07:25:16 +000012109 struct var **vpp;
12110 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012111 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012112 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012113
Eric Andersenc470f442003-07-28 09:56:35 +000012114 STARTSTACKSTR(ep);
12115 vpp = vartab;
12116 mask = on | off;
12117 do {
12118 for (vp = *vpp ; vp ; vp = vp->next)
12119 if ((vp->flags & mask) == on) {
12120 if (ep == stackstrend())
12121 ep = growstackstr();
12122 *ep++ = (char *) vp->text;
12123 }
12124 } while (++vpp < vartab + VTABSIZE);
12125 if (ep == stackstrend())
12126 ep = growstackstr();
12127 if (end)
12128 *end = ep;
12129 *ep++ = NULL;
12130 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012131}
12132
12133
12134/*
Eric Andersenc470f442003-07-28 09:56:35 +000012135 * POSIX requires that 'set' (but not export or readonly) output the
12136 * variables in lexicographic order - by the locale's collating order (sigh).
12137 * Maybe we could keep them in an ordered balanced binary tree
12138 * instead of hashed lists.
12139 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012140 */
12141
Eric Andersenc470f442003-07-28 09:56:35 +000012142static int
12143showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012144{
Eric Andersenc470f442003-07-28 09:56:35 +000012145 const char *sep;
12146 char **ep, **epend;
12147
12148 ep = listvars(on, off, &epend);
12149 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12150
12151 sep = *sep_prefix ? spcstr : sep_prefix;
12152
12153 for (; ep < epend; ep++) {
12154 const char *p;
12155 const char *q;
12156
12157 p = strchrnul(*ep, '=');
12158 q = nullstr;
12159 if (*p)
12160 q = single_quote(++p);
12161
12162 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12163 }
12164
Eric Andersencb57d552001-06-28 07:25:16 +000012165 return 0;
12166}
12167
12168
12169
12170/*
12171 * The export and readonly commands.
12172 */
12173
Eric Andersenc470f442003-07-28 09:56:35 +000012174static int
12175exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012176{
12177 struct var *vp;
12178 char *name;
12179 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012180 char **aptr;
12181 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12182 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012183
Eric Andersenc470f442003-07-28 09:56:35 +000012184 notp = nextopt("p") - 'p';
12185 if (notp && ((name = *(aptr = argptr)))) {
12186 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012187 if ((p = strchr(name, '=')) != NULL) {
12188 p++;
12189 } else {
12190 if ((vp = *findvar(hashvar(name), name))) {
12191 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012192 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012193 }
12194 }
12195 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012196 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012197 } else {
12198 showvars(argv[0], flag, 0);
12199 }
12200 return 0;
12201}
12202
Eric Andersen34506362001-08-02 05:02:46 +000012203
Eric Andersencb57d552001-06-28 07:25:16 +000012204/*
Eric Andersencb57d552001-06-28 07:25:16 +000012205 * Make a variable a local variable. When a variable is made local, it's
12206 * value and flags are saved in a localvar structure. The saved values
12207 * will be restored when the shell function returns. We handle the name
12208 * "-" as a special case.
12209 */
12210
Rob Landley88621d72006-08-29 19:41:06 +000012211static void mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012212{
Eric Andersencb57d552001-06-28 07:25:16 +000012213 struct localvar *lvp;
12214 struct var **vpp;
12215 struct var *vp;
12216
12217 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012218 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012219 if (name[0] == '-' && name[1] == '\0') {
12220 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012221 p = ckmalloc(sizeof(optlist));
12222 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012223 vp = NULL;
12224 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012225 char *eq;
12226
Eric Andersencb57d552001-06-28 07:25:16 +000012227 vpp = hashvar(name);
12228 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012229 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012230 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012231 if (eq)
12232 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012233 else
12234 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012235 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012236 lvp->flags = VUNSET;
12237 } else {
12238 lvp->text = vp->text;
12239 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012240 vp->flags |= VSTRFIXED|VTEXTFIXED;
12241 if (eq)
12242 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012243 }
12244 }
12245 lvp->vp = vp;
12246 lvp->next = localvars;
12247 localvars = lvp;
12248 INTON;
12249}
12250
Eric Andersenc470f442003-07-28 09:56:35 +000012251/*
12252 * The "local" command.
12253 */
12254
12255static int
12256localcmd(int argc, char **argv)
12257{
12258 char *name;
12259
12260 argv = argptr;
12261 while ((name = *argv++) != NULL) {
12262 mklocal(name);
12263 }
12264 return 0;
12265}
12266
12267
Eric Andersencb57d552001-06-28 07:25:16 +000012268/*
12269 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012270 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012271 */
12272
Eric Andersenc470f442003-07-28 09:56:35 +000012273static void
12274poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012275{
Eric Andersencb57d552001-06-28 07:25:16 +000012276 struct localvar *lvp;
12277 struct var *vp;
12278
12279 while ((lvp = localvars) != NULL) {
12280 localvars = lvp->next;
12281 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012282 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12283 if (vp == NULL) { /* $- saved */
12284 memcpy(optlist, lvp->text, sizeof(optlist));
12285 ckfree(lvp->text);
12286 optschanged();
12287 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12288 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012289 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012290 if (vp->func)
12291 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12292 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12293 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012294 vp->flags = lvp->flags;
12295 vp->text = lvp->text;
12296 }
Eric Andersenc470f442003-07-28 09:56:35 +000012297 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012298 }
12299}
12300
12301
Eric Andersencb57d552001-06-28 07:25:16 +000012302/*
12303 * The unset builtin command. We unset the function before we unset the
12304 * variable to allow a function to be unset when there is a readonly variable
12305 * with the same name.
12306 */
12307
Eric Andersenc470f442003-07-28 09:56:35 +000012308int
12309unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012310{
12311 char **ap;
12312 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012313 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012314 int ret = 0;
12315
12316 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012317 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012318 }
Eric Andersencb57d552001-06-28 07:25:16 +000012319
Eric Andersenc470f442003-07-28 09:56:35 +000012320 for (ap = argptr; *ap ; ap++) {
12321 if (flag != 'f') {
12322 i = unsetvar(*ap);
12323 ret |= i;
12324 if (!(i & 2))
12325 continue;
12326 }
12327 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012328 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012329 }
Eric Andersenc470f442003-07-28 09:56:35 +000012330 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012331}
12332
12333
12334/*
12335 * Unset the specified variable.
12336 */
12337
Eric Andersenc470f442003-07-28 09:56:35 +000012338int
12339unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012340{
Eric Andersencb57d552001-06-28 07:25:16 +000012341 struct var **vpp;
12342 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012343 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012344
12345 vpp = findvar(hashvar(s), s);
12346 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012347 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012348 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012349 int flags = vp->flags;
12350
12351 retval = 1;
12352 if (flags & VREADONLY)
12353 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012354#ifdef DYNAMIC_VAR
12355 vp->flags &= ~VDYNAMIC;
12356#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012357 if (flags & VUNSET)
12358 goto ok;
12359 if ((flags & VSTRFIXED) == 0) {
12360 INTOFF;
12361 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12362 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012363 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012364 ckfree(vp);
12365 INTON;
12366 } else {
12367 setvar(s, 0, 0);
12368 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012369 }
Eric Andersenc470f442003-07-28 09:56:35 +000012370ok:
12371 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012372 }
12373
Eric Andersenc470f442003-07-28 09:56:35 +000012374out:
12375 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012376}
12377
12378
12379
12380/*
12381 * Find the appropriate entry in the hash table from the name.
12382 */
12383
Eric Andersenc470f442003-07-28 09:56:35 +000012384static struct var **
12385hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012386{
Eric Andersencb57d552001-06-28 07:25:16 +000012387 unsigned int hashval;
12388
12389 hashval = ((unsigned char) *p) << 4;
12390 while (*p && *p != '=')
12391 hashval += (unsigned char) *p++;
12392 return &vartab[hashval % VTABSIZE];
12393}
12394
12395
12396
12397/*
Eric Andersenc470f442003-07-28 09:56:35 +000012398 * Compares two strings up to the first = or '\0'. The first
12399 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012400 * either '=' or '\0'.
12401 */
12402
Eric Andersenc470f442003-07-28 09:56:35 +000012403int
12404varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012405{
Eric Andersenc470f442003-07-28 09:56:35 +000012406 int c, d;
12407
12408 while ((c = *p) == (d = *q)) {
12409 if (!c || c == '=')
12410 goto out;
12411 p++;
12412 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012413 }
Eric Andersenc470f442003-07-28 09:56:35 +000012414 if (c == '=')
12415 c = 0;
12416 if (d == '=')
12417 d = 0;
12418out:
12419 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012420}
12421
Eric Andersenc470f442003-07-28 09:56:35 +000012422static int
12423vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012424{
Eric Andersenc470f442003-07-28 09:56:35 +000012425 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012426}
12427
Eric Andersenc470f442003-07-28 09:56:35 +000012428static struct var **
12429findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012430{
12431 for (; *vpp; vpp = &(*vpp)->next) {
12432 if (varequal((*vpp)->text, name)) {
12433 break;
12434 }
12435 }
12436 return vpp;
12437}
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012438/* setmode.c */
Eric Andersencb57d552001-06-28 07:25:16 +000012439
Eric Andersenc470f442003-07-28 09:56:35 +000012440#include <sys/times.h>
12441
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012442static const unsigned char timescmd_str[] = {
12443 ' ', offsetof(struct tms, tms_utime),
12444 '\n', offsetof(struct tms, tms_stime),
12445 ' ', offsetof(struct tms, tms_cutime),
12446 '\n', offsetof(struct tms, tms_cstime),
12447 0
12448};
Eric Andersencb57d552001-06-28 07:25:16 +000012449
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012450static int timescmd(int ac, char **av)
12451{
12452 long int clk_tck, s, t;
12453 const unsigned char *p;
12454 struct tms buf;
12455
12456 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012457 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012458
12459 p = timescmd_str;
12460 do {
12461 t = *(clock_t *)(((char *) &buf) + p[1]);
12462 s = t / clk_tck;
12463 out1fmt("%ldm%ld.%.3lds%c",
12464 s/60, s%60,
12465 ((t - s * clk_tck) * 1000) / clk_tck,
12466 p[0]);
12467 } while (*(p += 2));
12468
Eric Andersencb57d552001-06-28 07:25:16 +000012469 return 0;
12470}
12471
Eric Andersend35c5df2002-01-09 15:37:36 +000012472#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012473static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012474dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012475{
Eric Andersened9ecf72004-06-22 08:29:45 +000012476 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012477 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012478
Eric Andersenc470f442003-07-28 09:56:35 +000012479 INTOFF;
12480 result = arith(s, &errcode);
12481 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012482 if (errcode == -3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012483 sh_error("exponent less than 0");
Eric Andersen90898442003-08-06 11:20:52 +000012484 else if (errcode == -2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012485 sh_error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012486 else if (errcode == -5)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012487 sh_error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012488 else
12489 synerror(s);
12490 }
12491 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012492
Eric Andersenc470f442003-07-28 09:56:35 +000012493 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012494}
Eric Andersenc470f442003-07-28 09:56:35 +000012495
12496
12497/*
Eric Andersen90898442003-08-06 11:20:52 +000012498 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12499 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12500 *
12501 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012502 */
Eric Andersen90898442003-08-06 11:20:52 +000012503
Eric Andersenc470f442003-07-28 09:56:35 +000012504static int
Eric Andersen90898442003-08-06 11:20:52 +000012505letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012506{
Eric Andersenc470f442003-07-28 09:56:35 +000012507 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012508 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012509
Eric Andersen90898442003-08-06 11:20:52 +000012510 ap = argv + 1;
12511 if(!*ap)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012512 sh_error("expression expected");
Eric Andersen90898442003-08-06 11:20:52 +000012513 for (ap = argv + 1; *ap; ap++) {
12514 i = dash_arith(*ap);
12515 }
Eric Andersenc470f442003-07-28 09:56:35 +000012516
Eric Andersen90898442003-08-06 11:20:52 +000012517 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012518}
12519#endif /* CONFIG_ASH_MATH_SUPPORT */
12520
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012521/* miscbltin.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012522
12523/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012524 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012525 */
12526
12527#undef rflag
12528
12529#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012530#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012531typedef enum __rlimit_resource rlim_t;
12532#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012533#endif
12534
12535
Eric Andersenc470f442003-07-28 09:56:35 +000012536/*
12537 * The read builtin. The -e option causes backslashes to escape the
12538 * following character.
12539 *
12540 * This uses unbuffered input, which may be avoidable in some cases.
12541 */
12542
12543static int
12544readcmd(int argc, char **argv)
12545{
12546 char **ap;
12547 int backslash;
12548 char c;
12549 int rflag;
12550 char *prompt;
12551 const char *ifs;
12552 char *p;
12553 int startword;
12554 int status;
12555 int i;
Paul Fox02eb9342005-09-07 16:56:02 +000012556#if defined(CONFIG_ASH_READ_NCHARS)
12557 int nch_flag = 0;
12558 int nchars = 0;
12559 int silent = 0;
12560 struct termios tty, old_tty;
12561#endif
12562#if defined(CONFIG_ASH_READ_TIMEOUT)
12563 fd_set set;
12564 struct timeval ts;
12565
12566 ts.tv_sec = ts.tv_usec = 0;
12567#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012568
12569 rflag = 0;
12570 prompt = NULL;
Paul Fox02eb9342005-09-07 16:56:02 +000012571#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12572 while ((i = nextopt("p:rt:n:s")) != '\0')
12573#elif defined(CONFIG_ASH_READ_NCHARS)
12574 while ((i = nextopt("p:rn:s")) != '\0')
12575#elif defined(CONFIG_ASH_READ_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012576 while ((i = nextopt("p:rt:")) != '\0')
12577#else
12578 while ((i = nextopt("p:r")) != '\0')
12579#endif
12580 {
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012581 switch(i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012582 case 'p':
Eric Andersenc470f442003-07-28 09:56:35 +000012583 prompt = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012584 break;
12585#if defined(CONFIG_ASH_READ_NCHARS)
12586 case 'n':
12587 nchars = strtol(optionarg, &p, 10);
12588 if (*p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012589 sh_error("invalid count");
Paul Fox02eb9342005-09-07 16:56:02 +000012590 nch_flag = (nchars > 0);
12591 break;
12592 case 's':
12593 silent = 1;
12594 break;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012595#endif
Paul Fox02eb9342005-09-07 16:56:02 +000012596#if defined(CONFIG_ASH_READ_TIMEOUT)
12597 case 't':
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012598 ts.tv_sec = strtol(optionarg, &p, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012599 ts.tv_usec = 0;
12600 if (*p == '.') {
12601 char *p2;
12602 if (*++p) {
12603 int scale;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012604 ts.tv_usec = strtol(p, &p2, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012605 if (*p2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012606 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012607 scale = p2 - p;
12608 /* normalize to usec */
12609 if (scale > 6)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012610 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012611 while (scale++ < 6)
12612 ts.tv_usec *= 10;
12613 }
12614 } else if (*p) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012615 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012616 }
12617 if ( ! ts.tv_sec && ! ts.tv_usec)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012618 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012619 break;
12620#endif
12621 case 'r':
12622 rflag = 1;
12623 break;
12624 default:
12625 break;
12626 }
Eric Andersenc470f442003-07-28 09:56:35 +000012627 }
12628 if (prompt && isatty(0)) {
12629 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012630 }
12631 if (*(ap = argptr) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012632 sh_error("arg count");
Eric Andersenc470f442003-07-28 09:56:35 +000012633 if ((ifs = bltinlookup("IFS")) == NULL)
12634 ifs = defifs;
Paul Fox02eb9342005-09-07 16:56:02 +000012635#if defined(CONFIG_ASH_READ_NCHARS)
12636 if (nch_flag || silent) {
12637 tcgetattr(0, &tty);
12638 old_tty = tty;
12639 if (nch_flag) {
12640 tty.c_lflag &= ~ICANON;
12641 tty.c_cc[VMIN] = nchars;
12642 }
12643 if (silent) {
12644 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12645
12646 }
12647 tcsetattr(0, TCSANOW, &tty);
12648 }
12649#endif
12650#if defined(CONFIG_ASH_READ_TIMEOUT)
12651 if (ts.tv_sec || ts.tv_usec) {
12652 FD_ZERO (&set);
12653 FD_SET (0, &set);
12654
12655 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12656 if (!i) {
12657#if defined(CONFIG_ASH_READ_NCHARS)
12658 if (nch_flag)
12659 tcsetattr(0, TCSANOW, &old_tty);
12660#endif
12661 return 1;
12662 }
12663 }
Ned Ludd2123b7c2005-02-09 21:07:23 +000012664#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012665 status = 0;
12666 startword = 1;
12667 backslash = 0;
12668 STARTSTACKSTR(p);
Paul Fox02eb9342005-09-07 16:56:02 +000012669#if defined(CONFIG_ASH_READ_NCHARS)
12670 while (!nch_flag || nchars--)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012671#else
12672 for (;;)
12673#endif
12674 {
Eric Andersenc470f442003-07-28 09:56:35 +000012675 if (read(0, &c, 1) != 1) {
12676 status = 1;
12677 break;
12678 }
12679 if (c == '\0')
12680 continue;
12681 if (backslash) {
12682 backslash = 0;
12683 if (c != '\n')
12684 goto put;
12685 continue;
12686 }
12687 if (!rflag && c == '\\') {
12688 backslash++;
12689 continue;
12690 }
12691 if (c == '\n')
12692 break;
12693 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12694 continue;
12695 }
12696 startword = 0;
12697 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12698 STACKSTRNUL(p);
12699 setvar(*ap, stackblock(), 0);
12700 ap++;
12701 startword = 1;
12702 STARTSTACKSTR(p);
12703 } else {
12704put:
12705 STPUTC(c, p);
12706 }
12707 }
Paul Fox02eb9342005-09-07 16:56:02 +000012708#if defined(CONFIG_ASH_READ_NCHARS)
12709 if (nch_flag || silent)
12710 tcsetattr(0, TCSANOW, &old_tty);
12711#endif
12712
Eric Andersenc470f442003-07-28 09:56:35 +000012713 STACKSTRNUL(p);
12714 /* Remove trailing blanks */
12715 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12716 *p = '\0';
12717 setvar(*ap, stackblock(), 0);
12718 while (*++ap != NULL)
12719 setvar(*ap, nullstr, 0);
12720 return status;
12721}
12722
12723
12724static int umaskcmd(int argc, char **argv)
12725{
12726 static const char permuser[3] = "ugo";
12727 static const char permmode[3] = "rwx";
12728 static const short int permmask[] = {
12729 S_IRUSR, S_IWUSR, S_IXUSR,
12730 S_IRGRP, S_IWGRP, S_IXGRP,
12731 S_IROTH, S_IWOTH, S_IXOTH
12732 };
12733
12734 char *ap;
12735 mode_t mask;
12736 int i;
12737 int symbolic_mode = 0;
12738
12739 while (nextopt("S") != '\0') {
12740 symbolic_mode = 1;
12741 }
12742
12743 INTOFF;
12744 mask = umask(0);
12745 umask(mask);
12746 INTON;
12747
12748 if ((ap = *argptr) == NULL) {
12749 if (symbolic_mode) {
12750 char buf[18];
12751 char *p = buf;
12752
12753 for (i = 0; i < 3; i++) {
12754 int j;
12755
12756 *p++ = permuser[i];
12757 *p++ = '=';
12758 for (j = 0; j < 3; j++) {
12759 if ((mask & permmask[3 * i + j]) == 0) {
12760 *p++ = permmode[j];
12761 }
12762 }
12763 *p++ = ',';
12764 }
12765 *--p = 0;
12766 puts(buf);
12767 } else {
12768 out1fmt("%.4o\n", mask);
12769 }
12770 } else {
12771 if (is_digit((unsigned char) *ap)) {
12772 mask = 0;
12773 do {
12774 if (*ap >= '8' || *ap < '0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012775 sh_error(illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012776 mask = (mask << 3) + (*ap - '0');
12777 } while (*++ap != '\0');
12778 umask(mask);
12779 } else {
12780 mask = ~mask & 0777;
12781 if (!bb_parse_mode(ap, &mask)) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012782 sh_error("Illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012783 }
12784 umask(~mask & 0777);
12785 }
12786 }
12787 return 0;
12788}
12789
12790/*
12791 * ulimit builtin
12792 *
12793 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12794 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12795 * ash by J.T. Conklin.
12796 *
12797 * Public domain.
12798 */
12799
12800struct limits {
12801 const char *name;
12802 int cmd;
12803 int factor; /* multiply by to get rlim_{cur,max} values */
12804 char option;
12805};
12806
12807static const struct limits limits[] = {
12808#ifdef RLIMIT_CPU
12809 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12810#endif
12811#ifdef RLIMIT_FSIZE
12812 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12813#endif
12814#ifdef RLIMIT_DATA
12815 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12816#endif
12817#ifdef RLIMIT_STACK
12818 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12819#endif
12820#ifdef RLIMIT_CORE
12821 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12822#endif
12823#ifdef RLIMIT_RSS
12824 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12825#endif
12826#ifdef RLIMIT_MEMLOCK
12827 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12828#endif
12829#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012830 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012831#endif
12832#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012833 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012834#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012835#ifdef RLIMIT_AS
12836 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012837#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012838#ifdef RLIMIT_LOCKS
12839 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012840#endif
12841 { (char *) 0, 0, 0, '\0' }
12842};
12843
Glenn L McGrath76620622004-01-13 10:19:37 +000012844enum limtype { SOFT = 0x1, HARD = 0x2 };
12845
12846static void printlim(enum limtype how, const struct rlimit *limit,
12847 const struct limits *l)
12848{
12849 rlim_t val;
12850
12851 val = limit->rlim_max;
12852 if (how & SOFT)
12853 val = limit->rlim_cur;
12854
12855 if (val == RLIM_INFINITY)
12856 out1fmt("unlimited\n");
12857 else {
12858 val /= l->factor;
12859 out1fmt("%lld\n", (long long) val);
12860 }
12861}
12862
Eric Andersenc470f442003-07-28 09:56:35 +000012863int
12864ulimitcmd(int argc, char **argv)
12865{
12866 int c;
12867 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012868 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012869 const struct limits *l;
12870 int set, all = 0;
12871 int optc, what;
12872 struct rlimit limit;
12873
12874 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012875 while ((optc = nextopt("HSa"
12876#ifdef RLIMIT_CPU
12877 "t"
12878#endif
12879#ifdef RLIMIT_FSIZE
12880 "f"
12881#endif
12882#ifdef RLIMIT_DATA
12883 "d"
12884#endif
12885#ifdef RLIMIT_STACK
12886 "s"
12887#endif
12888#ifdef RLIMIT_CORE
12889 "c"
12890#endif
12891#ifdef RLIMIT_RSS
12892 "m"
12893#endif
12894#ifdef RLIMIT_MEMLOCK
12895 "l"
12896#endif
12897#ifdef RLIMIT_NPROC
12898 "p"
12899#endif
12900#ifdef RLIMIT_NOFILE
12901 "n"
12902#endif
12903#ifdef RLIMIT_AS
12904 "v"
12905#endif
12906#ifdef RLIMIT_LOCKS
12907 "w"
12908#endif
12909 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012910 switch (optc) {
12911 case 'H':
12912 how = HARD;
12913 break;
12914 case 'S':
12915 how = SOFT;
12916 break;
12917 case 'a':
12918 all = 1;
12919 break;
12920 default:
12921 what = optc;
12922 }
12923
Glenn L McGrath76620622004-01-13 10:19:37 +000012924 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012925 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012926
12927 set = *argptr ? 1 : 0;
12928 if (set) {
12929 char *p = *argptr;
12930
12931 if (all || argptr[1])
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012932 sh_error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012933 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012934 val = RLIM_INFINITY;
12935 else {
12936 val = (rlim_t) 0;
12937
12938 while ((c = *p++) >= '0' && c <= '9')
12939 {
12940 val = (val * 10) + (long)(c - '0');
12941 if (val < (rlim_t) 0)
12942 break;
12943 }
12944 if (c)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012945 sh_error("bad number");
Eric Andersenc470f442003-07-28 09:56:35 +000012946 val *= l->factor;
12947 }
12948 }
12949 if (all) {
12950 for (l = limits; l->name; l++) {
12951 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012952 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012953 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012954 }
12955 return 0;
12956 }
12957
12958 getrlimit(l->cmd, &limit);
12959 if (set) {
12960 if (how & HARD)
12961 limit.rlim_max = val;
12962 if (how & SOFT)
12963 limit.rlim_cur = val;
12964 if (setrlimit(l->cmd, &limit) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012965 sh_error("error setting limit (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +000012966 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012967 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012968 }
12969 return 0;
12970}
12971
Eric Andersen90898442003-08-06 11:20:52 +000012972
12973#ifdef CONFIG_ASH_MATH_SUPPORT
12974
12975/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12976
12977 Permission is hereby granted, free of charge, to any person obtaining
12978 a copy of this software and associated documentation files (the
12979 "Software"), to deal in the Software without restriction, including
12980 without limitation the rights to use, copy, modify, merge, publish,
12981 distribute, sublicense, and/or sell copies of the Software, and to
12982 permit persons to whom the Software is furnished to do so, subject to
12983 the following conditions:
12984
12985 The above copyright notice and this permission notice shall be
12986 included in all copies or substantial portions of the Software.
12987
12988 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12989 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12990 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12991 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12992 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12993 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12994 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12995*/
12996
12997/* This is my infix parser/evaluator. It is optimized for size, intended
12998 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000012999 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000013000 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000013001 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000013002 * be that which POSIX specifies for shells. */
13003
13004/* The code uses a simple two-stack algorithm. See
13005 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000013006 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000013007 * this is based (this code differs in that it applies operators immediately
13008 * to the stack instead of adding them to a queue to end up with an
13009 * expression). */
13010
13011/* To use the routine, call it with an expression string and error return
13012 * pointer */
13013
13014/*
13015 * Aug 24, 2001 Manuel Novoa III
13016 *
13017 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13018 *
13019 * 1) In arith_apply():
13020 * a) Cached values of *numptr and &(numptr[-1]).
13021 * b) Removed redundant test for zero denominator.
13022 *
13023 * 2) In arith():
13024 * a) Eliminated redundant code for processing operator tokens by moving
13025 * to a table-based implementation. Also folded handling of parens
13026 * into the table.
13027 * b) Combined all 3 loops which called arith_apply to reduce generated
13028 * code size at the cost of speed.
13029 *
13030 * 3) The following expressions were treated as valid by the original code:
13031 * 1() , 0! , 1 ( *3 ) .
13032 * These bugs have been fixed by internally enclosing the expression in
13033 * parens and then checking that all binary ops and right parens are
13034 * preceded by a valid expression (NUM_TOKEN).
13035 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013036 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013037 * ctype's isspace() if it is used by another busybox applet or if additional
13038 * whitespace chars should be considered. Look below the "#include"s for a
13039 * precompiler test.
13040 */
13041
13042/*
13043 * Aug 26, 2001 Manuel Novoa III
13044 *
13045 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13046 *
13047 * Merge in Aaron's comments previously posted to the busybox list,
13048 * modified slightly to take account of my changes to the code.
13049 *
13050 */
13051
13052/*
13053 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13054 *
13055 * - allow access to variable,
13056 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13057 * - realize assign syntax (VAR=expr, +=, *= etc)
13058 * - realize exponentiation (** operator)
13059 * - realize comma separated - expr, expr
13060 * - realise ++expr --expr expr++ expr--
13061 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013062 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013063 * - was restored loses XOR operator
13064 * - remove one goto label, added three ;-)
13065 * - protect $((num num)) as true zero expr (Manuel`s error)
13066 * - always use special isspace(), see comment from bash ;-)
13067 */
13068
13069
13070#define arith_isspace(arithval) \
13071 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13072
13073
13074typedef unsigned char operator;
13075
13076/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013077 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013078 * precedence. The ID portion is so that multiple operators can have the
13079 * same precedence, ensuring that the leftmost one is evaluated first.
13080 * Consider * and /. */
13081
13082#define tok_decl(prec,id) (((id)<<5)|(prec))
13083#define PREC(op) ((op) & 0x1F)
13084
13085#define TOK_LPAREN tok_decl(0,0)
13086
13087#define TOK_COMMA tok_decl(1,0)
13088
13089#define TOK_ASSIGN tok_decl(2,0)
13090#define TOK_AND_ASSIGN tok_decl(2,1)
13091#define TOK_OR_ASSIGN tok_decl(2,2)
13092#define TOK_XOR_ASSIGN tok_decl(2,3)
13093#define TOK_PLUS_ASSIGN tok_decl(2,4)
13094#define TOK_MINUS_ASSIGN tok_decl(2,5)
13095#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13096#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13097
13098#define TOK_MUL_ASSIGN tok_decl(3,0)
13099#define TOK_DIV_ASSIGN tok_decl(3,1)
13100#define TOK_REM_ASSIGN tok_decl(3,2)
13101
13102/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13103#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13104
13105/* conditional is right associativity too */
13106#define TOK_CONDITIONAL tok_decl(4,0)
13107#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13108
13109#define TOK_OR tok_decl(5,0)
13110
13111#define TOK_AND tok_decl(6,0)
13112
13113#define TOK_BOR tok_decl(7,0)
13114
13115#define TOK_BXOR tok_decl(8,0)
13116
13117#define TOK_BAND tok_decl(9,0)
13118
13119#define TOK_EQ tok_decl(10,0)
13120#define TOK_NE tok_decl(10,1)
13121
13122#define TOK_LT tok_decl(11,0)
13123#define TOK_GT tok_decl(11,1)
13124#define TOK_GE tok_decl(11,2)
13125#define TOK_LE tok_decl(11,3)
13126
13127#define TOK_LSHIFT tok_decl(12,0)
13128#define TOK_RSHIFT tok_decl(12,1)
13129
13130#define TOK_ADD tok_decl(13,0)
13131#define TOK_SUB tok_decl(13,1)
13132
13133#define TOK_MUL tok_decl(14,0)
13134#define TOK_DIV tok_decl(14,1)
13135#define TOK_REM tok_decl(14,2)
13136
13137/* exponent is right associativity */
13138#define TOK_EXPONENT tok_decl(15,1)
13139
13140/* For now unary operators. */
13141#define UNARYPREC 16
13142#define TOK_BNOT tok_decl(UNARYPREC,0)
13143#define TOK_NOT tok_decl(UNARYPREC,1)
13144
13145#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13146#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13147
13148#define PREC_PRE (UNARYPREC+2)
13149
13150#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13151#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13152
13153#define PREC_POST (UNARYPREC+3)
13154
13155#define TOK_POST_INC tok_decl(PREC_POST, 0)
13156#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13157
13158#define SPEC_PREC (UNARYPREC+4)
13159
13160#define TOK_NUM tok_decl(SPEC_PREC, 0)
13161#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13162
13163#define NUMPTR (*numstackptr)
13164
Rob Landley88621d72006-08-29 19:41:06 +000013165static int tok_have_assign(operator op)
Eric Andersen90898442003-08-06 11:20:52 +000013166{
13167 operator prec = PREC(op);
13168
13169 convert_prec_is_assing(prec);
13170 return (prec == PREC(TOK_ASSIGN) ||
13171 prec == PREC_PRE || prec == PREC_POST);
13172}
13173
Rob Landley88621d72006-08-29 19:41:06 +000013174static int is_right_associativity(operator prec)
Eric Andersen90898442003-08-06 11:20:52 +000013175{
13176 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13177 prec == PREC(TOK_CONDITIONAL));
13178}
13179
13180
13181typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013182 arith_t val;
13183 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013184 char contidional_second_val_initialized;
13185 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013186 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013187} v_n_t;
13188
13189
13190typedef struct CHK_VAR_RECURSIVE_LOOPED {
13191 const char *var;
13192 struct CHK_VAR_RECURSIVE_LOOPED *next;
13193} chk_var_recursive_looped_t;
13194
13195static chk_var_recursive_looped_t *prev_chk_var_recursive;
13196
13197
13198static int arith_lookup_val(v_n_t *t)
13199{
13200 if(t->var) {
13201 const char * p = lookupvar(t->var);
13202
13203 if(p) {
13204 int errcode;
13205
13206 /* recursive try as expression */
13207 chk_var_recursive_looped_t *cur;
13208 chk_var_recursive_looped_t cur_save;
13209
13210 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13211 if(strcmp(cur->var, t->var) == 0) {
13212 /* expression recursion loop detected */
13213 return -5;
13214 }
13215 }
13216 /* save current lookuped var name */
13217 cur = prev_chk_var_recursive;
13218 cur_save.var = t->var;
13219 cur_save.next = cur;
13220 prev_chk_var_recursive = &cur_save;
13221
13222 t->val = arith (p, &errcode);
13223 /* restore previous ptr after recursiving */
13224 prev_chk_var_recursive = cur;
13225 return errcode;
13226 } else {
13227 /* allow undefined var as 0 */
13228 t->val = 0;
13229 }
13230 }
13231 return 0;
13232}
13233
13234/* "applying" a token means performing it on the top elements on the integer
13235 * stack. For a unary operator it will only change the top element, but a
13236 * binary operator will pop two arguments and push a result */
Rob Landley88621d72006-08-29 19:41:06 +000013237static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
Eric Andersen90898442003-08-06 11:20:52 +000013238{
Eric Andersen90898442003-08-06 11:20:52 +000013239 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013240 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013241 int ret_arith_lookup_val;
13242
13243 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13244 without arguments */
13245 numptr_m1 = NUMPTR - 1;
13246
13247 /* check operand is var with noninteger value */
13248 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13249 if(ret_arith_lookup_val)
13250 return ret_arith_lookup_val;
13251
13252 rez = numptr_m1->val;
13253 if (op == TOK_UMINUS)
13254 rez *= -1;
13255 else if (op == TOK_NOT)
13256 rez = !rez;
13257 else if (op == TOK_BNOT)
13258 rez = ~rez;
13259 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13260 rez++;
13261 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13262 rez--;
13263 else if (op != TOK_UPLUS) {
13264 /* Binary operators */
13265
13266 /* check and binary operators need two arguments */
13267 if (numptr_m1 == numstack) goto err;
13268
13269 /* ... and they pop one */
13270 --NUMPTR;
13271 numptr_val = rez;
13272 if (op == TOK_CONDITIONAL) {
13273 if(! numptr_m1->contidional_second_val_initialized) {
13274 /* protect $((expr1 ? expr2)) without ": expr" */
13275 goto err;
13276 }
13277 rez = numptr_m1->contidional_second_val;
13278 } else if(numptr_m1->contidional_second_val_initialized) {
13279 /* protect $((expr1 : expr2)) without "expr ? " */
13280 goto err;
13281 }
13282 numptr_m1 = NUMPTR - 1;
13283 if(op != TOK_ASSIGN) {
13284 /* check operand is var with noninteger value for not '=' */
13285 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13286 if(ret_arith_lookup_val)
13287 return ret_arith_lookup_val;
13288 }
13289 if (op == TOK_CONDITIONAL) {
13290 numptr_m1->contidional_second_val = rez;
13291 }
13292 rez = numptr_m1->val;
13293 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13294 rez |= numptr_val;
13295 else if (op == TOK_OR)
13296 rez = numptr_val || rez;
13297 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13298 rez &= numptr_val;
13299 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13300 rez ^= numptr_val;
13301 else if (op == TOK_AND)
13302 rez = rez && numptr_val;
13303 else if (op == TOK_EQ)
13304 rez = (rez == numptr_val);
13305 else if (op == TOK_NE)
13306 rez = (rez != numptr_val);
13307 else if (op == TOK_GE)
13308 rez = (rez >= numptr_val);
13309 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13310 rez >>= numptr_val;
13311 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13312 rez <<= numptr_val;
13313 else if (op == TOK_GT)
13314 rez = (rez > numptr_val);
13315 else if (op == TOK_LT)
13316 rez = (rez < numptr_val);
13317 else if (op == TOK_LE)
13318 rez = (rez <= numptr_val);
13319 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13320 rez *= numptr_val;
13321 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13322 rez += numptr_val;
13323 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13324 rez -= numptr_val;
13325 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13326 rez = numptr_val;
13327 else if (op == TOK_CONDITIONAL_SEP) {
13328 if (numptr_m1 == numstack) {
13329 /* protect $((expr : expr)) without "expr ? " */
13330 goto err;
13331 }
13332 numptr_m1->contidional_second_val_initialized = op;
13333 numptr_m1->contidional_second_val = numptr_val;
13334 }
13335 else if (op == TOK_CONDITIONAL) {
13336 rez = rez ?
13337 numptr_val : numptr_m1->contidional_second_val;
13338 }
13339 else if(op == TOK_EXPONENT) {
13340 if(numptr_val < 0)
13341 return -3; /* exponent less than 0 */
13342 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013343 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013344
13345 if(numptr_val)
13346 while(numptr_val--)
13347 c *= rez;
13348 rez = c;
13349 }
13350 }
13351 else if(numptr_val==0) /* zero divisor check */
13352 return -2;
13353 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13354 rez /= numptr_val;
13355 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13356 rez %= numptr_val;
13357 }
13358 if(tok_have_assign(op)) {
13359 char buf[32];
13360
13361 if(numptr_m1->var == NULL) {
13362 /* Hmm, 1=2 ? */
13363 goto err;
13364 }
13365 /* save to shell variable */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013366#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersena68ea1c2006-01-30 22:48:39 +000013367 snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013368#else
Eric Andersena68ea1c2006-01-30 22:48:39 +000013369 snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013370#endif
Eric Andersen90898442003-08-06 11:20:52 +000013371 setvar(numptr_m1->var, buf, 0);
13372 /* after saving, make previous value for v++ or v-- */
13373 if(op == TOK_POST_INC)
13374 rez--;
13375 else if(op == TOK_POST_DEC)
13376 rez++;
13377 }
13378 numptr_m1->val = rez;
13379 /* protect geting var value, is number now */
13380 numptr_m1->var = NULL;
13381 return 0;
13382err: return(-1);
13383}
13384
13385/* longest must first */
13386static const char op_tokens[] = {
13387 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13388 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13389 '<','<', 0, TOK_LSHIFT,
13390 '>','>', 0, TOK_RSHIFT,
13391 '|','|', 0, TOK_OR,
13392 '&','&', 0, TOK_AND,
13393 '!','=', 0, TOK_NE,
13394 '<','=', 0, TOK_LE,
13395 '>','=', 0, TOK_GE,
13396 '=','=', 0, TOK_EQ,
13397 '|','=', 0, TOK_OR_ASSIGN,
13398 '&','=', 0, TOK_AND_ASSIGN,
13399 '*','=', 0, TOK_MUL_ASSIGN,
13400 '/','=', 0, TOK_DIV_ASSIGN,
13401 '%','=', 0, TOK_REM_ASSIGN,
13402 '+','=', 0, TOK_PLUS_ASSIGN,
13403 '-','=', 0, TOK_MINUS_ASSIGN,
13404 '-','-', 0, TOK_POST_DEC,
13405 '^','=', 0, TOK_XOR_ASSIGN,
13406 '+','+', 0, TOK_POST_INC,
13407 '*','*', 0, TOK_EXPONENT,
13408 '!', 0, TOK_NOT,
13409 '<', 0, TOK_LT,
13410 '>', 0, TOK_GT,
13411 '=', 0, TOK_ASSIGN,
13412 '|', 0, TOK_BOR,
13413 '&', 0, TOK_BAND,
13414 '*', 0, TOK_MUL,
13415 '/', 0, TOK_DIV,
13416 '%', 0, TOK_REM,
13417 '+', 0, TOK_ADD,
13418 '-', 0, TOK_SUB,
13419 '^', 0, TOK_BXOR,
13420 /* uniq */
13421 '~', 0, TOK_BNOT,
13422 ',', 0, TOK_COMMA,
13423 '?', 0, TOK_CONDITIONAL,
13424 ':', 0, TOK_CONDITIONAL_SEP,
13425 ')', 0, TOK_RPAREN,
13426 '(', 0, TOK_LPAREN,
13427 0
13428};
13429/* ptr to ")" */
13430#define endexpression &op_tokens[sizeof(op_tokens)-7]
13431
13432
Eric Andersened9ecf72004-06-22 08:29:45 +000013433static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013434{
"Robert P. J. Day"68229832006-07-01 13:08:46 +000013435 char arithval; /* Current character under analysis */
Eric Andersen90898442003-08-06 11:20:52 +000013436 operator lasttok, op;
13437 operator prec;
13438
13439 const char *p = endexpression;
13440 int errcode;
13441
13442 size_t datasizes = strlen(expr) + 2;
13443
13444 /* Stack of integers */
13445 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013446 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013447 * the reader. */
13448 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13449 *numstackptr = numstack;
13450 /* Stack of operator tokens */
13451 operator *stack = alloca((datasizes) * sizeof(operator)),
13452 *stackptr = stack;
13453
13454 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13455 *perrcode = errcode = 0;
13456
13457 while(1) {
13458 if ((arithval = *expr) == 0) {
13459 if (p == endexpression) {
13460 /* Null expression. */
13461 return 0;
13462 }
13463
13464 /* This is only reached after all tokens have been extracted from the
13465 * input stream. If there are still tokens on the operator stack, they
13466 * are to be applied in order. At the end, there should be a final
13467 * result on the integer stack */
13468
13469 if (expr != endexpression + 1) {
13470 /* If we haven't done so already, */
13471 /* append a closing right paren */
13472 expr = endexpression;
13473 /* and let the loop process it. */
13474 continue;
13475 }
13476 /* At this point, we're done with the expression. */
13477 if (numstackptr != numstack+1) {
13478 /* ... but if there isn't, it's bad */
13479 err:
13480 return (*perrcode = -1);
13481 }
13482 if(numstack->var) {
13483 /* expression is $((var)) only, lookup now */
13484 errcode = arith_lookup_val(numstack);
13485 }
13486 ret:
13487 *perrcode = errcode;
13488 return numstack->val;
13489 } else {
13490 /* Continue processing the expression. */
13491 if (arith_isspace(arithval)) {
13492 /* Skip whitespace */
13493 goto prologue;
13494 }
13495 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013496 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013497
13498 numstackptr->var = alloca(var_name_size);
13499 safe_strncpy(numstackptr->var, expr, var_name_size);
13500 expr = p;
13501 num:
13502 numstackptr->contidional_second_val_initialized = 0;
13503 numstackptr++;
13504 lasttok = TOK_NUM;
13505 continue;
13506 } else if (is_digit(arithval)) {
13507 numstackptr->var = NULL;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013508#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersenad63cb22004-10-08 09:43:34 +000013509 numstackptr->val = strtoll(expr, (char **) &expr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013510#else
13511 numstackptr->val = strtol(expr, (char **) &expr, 0);
13512#endif
Eric Andersen90898442003-08-06 11:20:52 +000013513 goto num;
13514 }
13515 for(p = op_tokens; ; p++) {
13516 const char *o;
13517
13518 if(*p == 0) {
13519 /* strange operator not found */
13520 goto err;
13521 }
13522 for(o = expr; *p && *o == *p; p++)
13523 o++;
13524 if(! *p) {
13525 /* found */
13526 expr = o - 1;
13527 break;
13528 }
13529 /* skip tail uncompared token */
13530 while(*p)
13531 p++;
13532 /* skip zero delim */
13533 p++;
13534 }
13535 op = p[1];
13536
13537 /* post grammar: a++ reduce to num */
13538 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13539 lasttok = TOK_NUM;
13540
13541 /* Plus and minus are binary (not unary) _only_ if the last
13542 * token was as number, or a right paren (which pretends to be
13543 * a number, since it evaluates to one). Think about it.
13544 * It makes sense. */
13545 if (lasttok != TOK_NUM) {
13546 switch(op) {
13547 case TOK_ADD:
13548 op = TOK_UPLUS;
13549 break;
13550 case TOK_SUB:
13551 op = TOK_UMINUS;
13552 break;
13553 case TOK_POST_INC:
13554 op = TOK_PRE_INC;
13555 break;
13556 case TOK_POST_DEC:
13557 op = TOK_PRE_DEC;
13558 break;
13559 }
13560 }
13561 /* We don't want a unary operator to cause recursive descent on the
13562 * stack, because there can be many in a row and it could cause an
13563 * operator to be evaluated before its argument is pushed onto the
13564 * integer stack. */
13565 /* But for binary operators, "apply" everything on the operator
13566 * stack until we find an operator with a lesser priority than the
13567 * one we have just extracted. */
13568 /* Left paren is given the lowest priority so it will never be
13569 * "applied" in this way.
13570 * if associativity is right and priority eq, applied also skip
13571 */
13572 prec = PREC(op);
13573 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13574 /* not left paren or unary */
13575 if (lasttok != TOK_NUM) {
13576 /* binary op must be preceded by a num */
13577 goto err;
13578 }
13579 while (stackptr != stack) {
13580 if (op == TOK_RPAREN) {
13581 /* The algorithm employed here is simple: while we don't
13582 * hit an open paren nor the bottom of the stack, pop
13583 * tokens and apply them */
13584 if (stackptr[-1] == TOK_LPAREN) {
13585 --stackptr;
13586 /* Any operator directly after a */
13587 lasttok = TOK_NUM;
13588 /* close paren should consider itself binary */
13589 goto prologue;
13590 }
13591 } else {
13592 operator prev_prec = PREC(stackptr[-1]);
13593
13594 convert_prec_is_assing(prec);
13595 convert_prec_is_assing(prev_prec);
13596 if (prev_prec < prec)
13597 break;
13598 /* check right assoc */
13599 if(prev_prec == prec && is_right_associativity(prec))
13600 break;
13601 }
13602 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13603 if(errcode) goto ret;
13604 }
13605 if (op == TOK_RPAREN) {
13606 goto err;
13607 }
13608 }
13609
13610 /* Push this operator to the stack and remember it. */
13611 *stackptr++ = lasttok = op;
13612
13613 prologue:
13614 ++expr;
13615 }
13616 }
13617}
13618#endif /* CONFIG_ASH_MATH_SUPPORT */
13619
13620
Eric Andersenc470f442003-07-28 09:56:35 +000013621#ifdef DEBUG
13622const char *bb_applet_name = "debug stuff usage";
13623int main(int argc, char **argv)
13624{
13625 return ash_main(argc, argv);
13626}
13627#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013628
Eric Andersendf82f612001-06-28 07:46:40 +000013629/*-
13630 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013631 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013632 *
13633 * This code is derived from software contributed to Berkeley by
13634 * Kenneth Almquist.
13635 *
13636 * Redistribution and use in source and binary forms, with or without
13637 * modification, are permitted provided that the following conditions
13638 * are met:
13639 * 1. Redistributions of source code must retain the above copyright
13640 * notice, this list of conditions and the following disclaimer.
13641 * 2. Redistributions in binary form must reproduce the above copyright
13642 * notice, this list of conditions and the following disclaimer in the
13643 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013644 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013645 * may be used to endorse or promote products derived from this software
13646 * without specific prior written permission.
13647 *
13648 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13649 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13650 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13651 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13652 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13653 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13654 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13655 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13656 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13657 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13658 * SUCH DAMAGE.
13659 */